说明:
(1)在【Spring IoC容器与Bean管理21:使用注解方式实现Spring IoC二:组件类型注解(对象实例化);@Repository,@Service,@Controller,@Component;】中,仅仅介绍了实例化对象,但是没有涉及为对象的属性注入数据;本博客中介绍的【自动装配注解】,其目的就是实现对象的依赖注入;
(2)【自动装配注解】包括【按类型装配注解】和【按名称装配注解】;
(3)本篇博客主要介绍以【@Autowired】注解为例,介绍【自动装配注解】中的【按类型装配注解】的使用和缺点;
(3)本篇博客,沿用【Spring IoC容器与Bean管理21:使用注解方式实现Spring IoC二:组件类型注解(对象实例化);@Repository,@Service,@Controller,@Component;】中的代码s08;
目录
一:自动装配注解简介
0.【按类型装配】注解和【按名称装配】注解简述:
1.【按类型装配】的注解:@Autowired和@Inject:
2.【按名称装配】的注解:@Named和@Resource:
二:自动装配注解:之【按类型装配】注解:之@Autowired注解
[email protected]注解用法:【在属性上使用@Autowired注解】和【在set方法上使用@Autowired注解】
策略一:在userDao属性上使用@Autowired注解
策略二:在setUserDao()方法上使用@Autowired注解
区别分析:
[email protected]注解用法:缺点和问题
(1)演示:为什么,在工作中,不推荐使用【按类型装配注解】;
(2)使用【按类型装配注解】,如何解决【由于IoC容器中出现多个相同类型的对象,从而导致的NoUniqueBeanDefinitionException】的问题?
一:自动装配注解简介
0.【按类型装配】注解和【按名称装配】注解简述:
● 【按名称装配】:在【Spring IoC容器与Bean管理12:IoC在项目中的作用;】中的s04项目为例:在绝大多数场景下,我们都是采用【按名称装配】的策略;
●【按类型装配】:不需要关心在IoC容器中,bean的名称是什么;在运行过程中为属性注入值时,只需要从IoC容器中获取对应类型的对象,然后完成自定注入;
1.【按类型装配】的注解:@Autowired和@Inject:
● @Autowired:这个是Spring提供的,即这是Spring自己提供的规范;
● @Inject:由JSR-330(Java规范要求第330号文件,这个文件是Java领域的标准和业界的规范)提供的标准;自然Spring对JSR-330也提供了支持;
● @Autowired和@Inject这两个【按类型装配】的注解,不推荐使用;更多的时候,鼓励使用【按名称装配】的注解;
2.【按名称装配】的注解:@Named和@Resource:
● @Named:这个注解要和@Inject注解匹配使用;即在@Inject注解后,增加@Named注解,其会按照属性名(或者其他自定义的规则)完成对象的装配;同时@Named也是JSR-330(Java规范要求第330号文件,这个文件是Java领域的标准和业界的规范)提供的标准
● @Resource:这个注解出现的较早,是JSR-250提供的标准;这个注解不但可以按照名称进行依赖注入,如果不满足按名称进行依赖注入时,其也能自动按类型装配;@Resource这个注解是目前功能最强大的自动供装配注解;
二:自动装配注解:之【按类型装配】注解:之@Autowired注解
● 沿用【Spring IoC容器与Bean管理21:使用注解方式实现Spring IoC二:组件类型注解(对象实例化);@Repository,@Service,@Controller,@Component;】中的代码s08;
● 在实际工作中,不推荐使用【按类型装配】注解;
● 事先说明:MVC架构模式采用分层的方式依次的逐级调用的,即Controller调用Service(也就是Controller依赖于Service啦),Service调用Dao(也就是Service依赖于Dao);由于前面,我们在UserController类、UserService类、UserDao类中使用了对应的注解,所以在IoC容器初始化的时候,这三个类的bean对象就会被创建了;
1.@Autowired注解用法:【在属性上使用@Autowired注解】和【在set方法上使用@Autowired注解】
策略一:在userDao属性上使用@Autowired注解
运行:通过运行结果,可以看到上面实现了对象注入,但是其并不是通过setter方法来实现的;
但是,如果采用下面的策略:
……………………………………………………
策略二:在setUserDao()方法上使用@Autowired注解
重新运行: ……………………………………………………区别分析:
(1)【在属性上使用@Autowired注解】和【在set方法上使用@Autowired注解】,都可以完成对象的注入;
(2)【在属性上使用@Autowired注解】没有执行set方法;【在set方法上使用@Autowired注解】执行了set方法;
(3)如果装配注解放在set方法上,则自动按类型或者名称对set方法参数进行注入;
(4)如果装配注解放在属性上,IoC容器会自动通过反射技术,将属性private修饰符自动更改为public,由于属性的访问修饰符成了public,这就意味着从外侧可以直接对这个属性赋值,不再执行set方法,然后赋值完成后,再将修饰符改回到private;(这个过程是在运行时,动态完成的,对程序员不可见) (5)由于(4)中的原因,在实际开发中,如果使用注解来实现对象依赖注入的话,通常是不用写set方法的;
2.@Autowired注解用法:缺点和问题
(1)演示:为什么,在工作中,不推荐使用【按类型装配注解】;
既然有了Dao接口,那么UserDao类应该实现这个接口(在实际开发中,这也是约定俗成的开发方式): 因为有了所有Dao的接口,那么在Service中,按照面向对象编程的理念,userDao属性的类型也应该修改为IUserDao接口:至此,还没有什么问题。
然后,比如原有的UserDao是基于Mysql数据库写的,如果后面需要改为Oracle数据库,直接的想法是新创建一个类,这个类实现IUserDao接口,然后按照Oracle开发就行了;
但是,这样以后就会出问题了:运行SpringApplication类,就会报错了:NoUniqueBeanDefinitionException: 该行报错信息完整摘录如下:Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.imooc.spring.ioc.dao.IUserDao' available: expected single matching bean but found 2: udao,userOracleDao
其大意是,我期望在容器只有唯一的、匹配的bean,但是在容器中发现了两个bean(分别是userDao和userOracleDao);
之所以会注入失败,就是因为@Autowired注解是【按类型装配】的注解;
(2)使用【按类型装配注解】,如何解决【由于IoC容器中出现多个相同类型的对象,从而导致的NoUniqueBeanDefinitionException】的问题?
解决办法1:去掉被抛弃的那个Dao类的@Repository注解;(目的是,IoC容器中不要出现类型重复的Dao对象) 解决办法2:引入@Primary注解 运行结果:
【按类型装配】注解之所以容易出问题的原因就是:在容器中,可能会出现多个相同类型的对象,如果稍不注意就会出现NoUniqueBeanDefinitionException;为了避免这个问题,在实际开发中,多使用【按名称装配】的注解,因为名称在容器中都是唯一的,所以可以有效避免刚才错误的发生;而【按名称装配】的注解在下篇博客中会给予介绍;