其他分享
首页 > 其他分享> > day60( 关于框架 , 关于Spring框架,通过Spring管理对象,自动装配, Ioc与DI,@Qualifier ,构造方法,@Autowired的警告 ,@Resource注解 )

day60( 关于框架 , 关于Spring框架,通过Spring管理对象,自动装配, Ioc与DI,@Qualifier ,构造方法,@Autowired的警告 ,@Resource注解 )

作者:互联网

day60( 关于框架 , 关于Spring框架,通过Spring管理对象,自动装配, Ioc与DI,@Qualifier ,构造方法,@Autowired的警告 ,@Resource注解 )

1.关于框架

1.概念:

 

2.关于Spring框架

1.作用

2.创建对象

3. 在Maven工程中使用Spring

3.通过Spring管理对象

1.创建对象的方式

2.通过@Bean方法

3.通过组件扫描创建对象

4.配置注解属性

5.配件注解

6.选择创建对象的方式

7.Spring Bean的作用域

8. 创建对象的小结

  1. Spring可以将创建出来的对象管理起来,对于开发者而言,当需要某个类的对象时,只需要从Spring容器中获取即可

  2. 创建对象的方式有2种:

    1. 通过@Bean方法:在配置类中自定义方法,返回需要Spring管理的对象,此方法必须添加@Bean注解

    2. 通过组件扫描:在配置类中使用@ComponentScan指定需要扫描的包,并确保需要Spring管理对象的类都在此包或其子孙包下,且这些类必须添加@Component、@Repository、@Service、@Controller中的其中某1个注解

    3. 如果需要Spring管理的是自定义的类的对象,应该使用组件扫描的做法,如果需要Spring管理的对象的类型不是自定义的,只能使用@Bean方法的做法

  3. 使用组件扫描时,在@ComponentScan中指定的包是扫描的根包,其子孙包中的类都会被扫描,通常,指定的包不需要特别精准,但也不宜过于粗糙,你应该事先规划出项目的根包并配置在组件扫描中,且保证自定义的每个组件类都在此包或其子孙包中

  4. 在Spring框架的解释范围内,@Component、@Repository、@Service、@Controller的作用是完全相同的,但语义不同,应该根据类的定位进行选取

  5. @Configuration是特殊的组件注解,Spring会通过代理模式来处理,此注解应该仅用于配置类

  6. 使用@Bean方法时,beanName默认是方法名,也可以在@Bean注解中配置参数来指定beanName

  7. 使用组件扫描时,beanName默认是将类名首字母改为小写的名称(除非类名不符合首字母大写、第2字母小写的规律),也可以在@Component或其它组件注解中配置参数来指定beanName

  8. Spring Bean的作用域默认是预加载的单例的,可以通过@Scope("prototype")配置为“非单例的”,在单例的前提下,可以通过@Lazy配置为“懒加载的” ,通常,保持为默认即可

  9. 关于配置注解参数:

    1. 如果你需要配置的只是注解的value这1个属性,不需要显式的写出属性名称

    2. 如果你需要配置注解中的多个属性,每个属性都必须显式写出属性名称,包括value属性

    3. 如果你需要配置的注解属性的值是数组类型,当只指定1个值时,可以不使用大括号将值框住,当指定多个值时,多个值必须使用大括号框住,且各值之间使用逗号分隔

    4. 你可以通过查看注解的源代码来了解注解可以配置哪些属性、属性的值类型、默认值

    5. 在注解的源代码中,@AliasFor可理解为“等效于”

4.自动装配

1.自动装配机制

2.@Autowired的装配机制

  1. 关于@Autowired的装配机制,首先,会根据需要装配的数据的类型在Spring容器中统计匹配的Bean(对象)的数量

  2. 当匹配的Bean数量为0个时,判断@Autowired注解的required属性值

    1. true(默认):装配失败,启动项目时即抛出NoSuchBeanDefinitionException

    2. false:放弃自动装配,不会报告异常,后续直接使用此属性时,会出现NPE (空指针异常)

  3. 当匹配的Bean数量为1个时,将直接装配,且装配成功

  4. 当匹配的Bean数量为多个时:自动尝试按照名称实现装配(即:要求属性名称与beanName相同)

    1. 存在与属性名称匹配的Spring Bean:装配成功

    2. 不存在与属性名称匹配的Spring Bean:装配失败,启动项目时即抛出NoUniqueBeanDefinitionException

3.小结

  1. 当某个属性需要被注入值,且你肯定此值存在于Spring容器中,你可以在属性上添加@Autowired注解,则Spring框架会自动为此属性注入值

  2. 如果某个方法是由Spring调用的,当方法体中需要某个值,且你肯定此值存在于Spring容器中,你可以将其声明为方法的参数,则Spring框架会自动从容器中找到此值并且于调用此方法,如果声明了多个这样的参数,各参数的先后顺序是不重要的

  3. 自动装配的前提是Spring会自动创建此类的对象,否则,Spring不可能为属性赋值,也不可能调用类中的方法

  4. @Autowired的装配机制的表现是可以根据类型实现装配,并且,当匹配类型的Bean有多个时,还可以根据名称进行匹配,从而实现装配,你需要熟记具体装配机制

5.其它

  1. 仍有一些与Spring框架相关的内容并未在本课提及,主要包括:

    1. Spring Bean的生命周期

    2. 读取properties配置文件

    3. @Value注解

    4. Spring AOP

6.课后阅读

1. IoC

  1. IoC(Inversion of Control:控制反转)是Spring框架的核心,在传统的开发模式下,是由开发者创建对象、为对象的属性赋值、管理对象的作用域和生命周期等,所以,是开发者拥有“控制权”,当使用了Spring之后,这些都交给Spring框架去完成了,开发者不必关心这些操作的具体实现,所以,称之为“控制反转

  2. 无论是创建对象,还是自动装配等等,只要是Spring创建并管理对象的操作,都可以称之为Spring IoC的过程

2.DI

  1. DI(Dependency Injection:依赖注入)是Spring框架实现IoC的核心实现,当某个类中声明了另一个类的属性(例如在UserController类中声明了UserMapper类型的属性),则称之为依赖(即UserController依赖了UserMapper),Spring框架会帮你完成依赖项的赋值,只是你在你的代码中看不到赋值过程或赋值符号,所以称之为注入

3.Ioc与DI关系

4. 关于@Qualifier

  1. @Qualifier注解是在自动装配机制中,用于指定beanName的注解

  2. 通常是因为存在多个类型匹配的Bean,但是所有Bean的beanName与被装配的属性名称/参数名称都不匹配,且不想修改beanName也不想修改属性名称/参数名称,则可以通过@Qualifier指定beanName

    1. 这种现象在开发实践中并不多见

  3. 在自动装配属性时指定beanName

    @Controller
    public class UserController {
    @Autowired
    @Qualifier("userMapper")
    private UserMapper xxx;
    public void reg() {
    System.out.println("UserController.reg() >> 控制器即将执行用户注册……");
    xxx.insert();
    }
    }
  4. 在自动装配方法参数时指定beanName

    @Configuration
    public class SpringConfig {
    @Bean
    public UserMapper userMapper() {
    return new UserMapper();
    }
    @Bean
    public UserController userController(@Qualifier("userMapper") UserMapper xxx) {
    UserController userController = new UserController();
    userController.userMapper = xxx;
    return userController;
    }
    }

5. 关于构造方法

  1. 当通过组件扫描创建对象时,Spring会自动调用组件类的构造方法,此过程中会使用到反射,所以可以无视构造方法的访问权限

  2. 如果类中仅有1个构造方法,Spring会自动调用这个构造方法

  3. 如果类中没有显式的添加构造方法,根据Java的机制,会由编译器添加默认构造方法,相当于有1个构造方法

  4. 如果类中有多个构造方法,默认情况下,Spring会自动调用无参数构造方法(如果存在的话),如果某个构造方法添加了@Autowired,则Spring会自动调用添加了此注解的构造方法

  5. 被Spring调用的构造方法是允许有参数的,作为开发者,你需要保证Spring可以利用自动装配机制为参数注入值(你需要保证Spring容器中存在匹配的值),否则会导致NoSuchBeanDefinitionException

6. 关于@Resource注解

  1. @Resource注解是javax.annotation包中的

  2. 如果某属性添加了@Resource注解,Spring也可以实现自动装配

    @Controller
    public class UserController {
    @Resource
    private UserMapper userMapper;
    public void reg() {
    System.out.println("UserController.reg() >> 控制器即将执行用户注册……");
    userMapper.insert();
    }
    }
  3. @Resource注解的装配机制是:先尝试根据名称进行装配(即:要求属性名称与beanName相同),如果失败,则尝试根据类型装配,如果不存在类型的Bean,则抛出NoSuchBeanDefinitionException,如果只有1个匹配类型的Bean,则装配成功,如果匹配类型的Bean超过1个,则抛出NoUniqueBeanDefinitionException

  4. 在开发实践中,绝大部分类型的Bean都只有1个,无论是@Autowired还是@Resource,当匹配类型的Bean有且仅有1个时,都可以成功装配,所以,在绝大部分情况下,这2个注解的装配机制的差异对于开发人员来说是无感的

  5. 当需要讨论@Autowired与@Resource的区别时,除了这2个注解所在的包不同、装配机制不同以外,还存在以下区别:

    1. @Autowired可以添加在构造方法的声明之前,@Resource不可以

    2. @Resource可以添加在类的声明之前(但不会装配属性的值),@Autowired不可以

    3. 当存在多个同类型的Bean时

      1. 当装配属性时,@Autowired需要通过@Qualifier指定beanName,而@Resource可以直接配置name属性以指定beanName

      2. 当装配方法的参数时(例如添加了@Autowired的构造方法的参数),@Autowired仍可以使用@Qualifier指定beanName,而@Resource无法解决此问题

  6. 综合来看,由于@Autowired是Spring框架专门定制的注解,且@Autowired可以添加在构造方法上,相比@Resource有更多的应用场景(虽然不一定真的需要这样用),所以,在开发实践中,当需要使用注解显式的表示自动装配时,推荐优先使用@Autowired

7. 关于@Autowired的警告

  1. 当你在属性上添加@Autowired时,在IntelliJ IDEA中会有浅灰色的下划线提示警告

    1. 此警告内容为:Field Injection is not recommended,可译为:字段(类的属性)注入是不推荐的

    2. 假设某开发人员不是通过Spring容器获取UserController的对象,而是通过传统方式,使用new关键字自行创建对象,且忽略了为userMapper属性赋值(此属性是private的,对外不可见,忽略了很常见),则会导致userMapper一直是默认的null值,后续调用userMapper的方法时就会出现NPE,这被视为字段注入的不足之处

  2. 建议的解决方案是这样的:

    @Controller
    public class UserController {
    private UserMapper userMapper;
    public UserController(UserMapper userMapper) {
    this.userMapper = userMapper;
    }
    public void reg() {
    System.out.println("UserController.reg() >> 控制器即将执行用户注册……");
    System.out.println(userMapper.getClass().getName());
    userMapper.insert();
    }
    }
    1. Spring有非常完善的调用构造方法的机制,并且也可以对构造方法中的参数注入值,甚至存在多个匹配类型对象时还可以使用@Qualifier指定beanName,所以,只要构造方法中的代码能够对属性赋值,就可以实现和属性上自动装配完全相同的效果

    2. 只要将必要的值声明为构造方法的参数,无论是Spring创建对象,还是人为创建对象,都需要提供此参数值,除非恶意的传入null值,否则,不会出现NPE问题,所以,此做法是被推荐的

  3. 使用构造方法虽然安全,不会出现NPE,但是,当需要被赋值的属性的数量出现增或减时,都需要调整构造方法,当属性数量较多时,构造方法的参数也会变多,这些都是在开发实践中非常现实的问题

  4. 由于字段注入的NPE问题只是开发阶段人为错误使用导致的,出现概率非常低、可控、容易解决,且字段注入的语法简洁、直观,所以,在开发实践中,字段注入仍是最常见的用法

标签:框架,构造方法,对象,Spring,UserMapper,Bean,注解,属性
来源: https://www.cnblogs.com/xiaoyezilei/p/16309032.html