Spring注解注入
Spring基于Annotation配置Bean
简介
这种注入方式也比较常见,并且在Spring企业级开发中用途最广的DI模式之一,有时候相对于XML配置模式,Autowire注入是很方便的。
首先需要导入支持AOP的包,因为需要在XML配置文件中通知Spring容器扫描含有注解文件的包。
分类
1)@Component
可以使用此注解描述 Spring 中的 Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应类上即可。
2)@Repository
用于将数据访问层(DAO层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
3)@Service
通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
4)@Controller
通常作用在控制层(如 Struts2 的 Action),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
5)@Autowired
用于对 Bean 的属性变量、属性的 Set 方法及构造函数进行标注,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配。
6)@Resource
其作用与 Autowired 一样。其区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 实例名称进行装配。
@Resource 中有两个重要属性:name 和 type。
Spring 将 name 属性解析为 Bean 实例名称,type 属性解析为 Bean 实例类型。如果指定 name 属性,则按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配。
如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。
7)@Qualifier
与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定。
案例
1)Dao层实现类
@Repository("userDao") // 持久层组件注解
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("Dao层的add()方法。。。");
}
}
2)Service层实现类
@Service("userService")
public class UserServiceImpl implements UserService {
@Resource(name = "userDao")
private UserDao userDao;
// public void setUserDao(UserDao userDao) {
// this.userDao = userDao;
// }
@Override
public void add() {
userDao.add();
System.out.println("Service层的add()方法。。。");
}
}
3)Annotation层
@Controller("userAction")
public class UserAction {
@Resource(name = "userService")
private UserService userService;
// public void setUserService(UserService userService) {
// this.userService = userService;
// }
public void add(){
userService.add();
System.out.println("Action层的add()方法。。。");
}
}
4)XML配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 通知Spring扫描指定包下含有组件注解的Java文件 -->
<context:component-scan base-package="com.lyl.*"/>
</beans>
5)测试类
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserAction userAction = (UserAction) context.getBean("userAction");
userAction.add();
}
打印结果:
Dao层的add()方法。。。
Service层的add()方法。。。
Action层的add()方法。。。
上面案例使用的就是通过注解来实现注入bean。其中可以发现Service层、Annotation层的实现类中由属性,但是setter方法注释了也能注入成功,说明注解方法实现的注入,可以不用写setter方法,Spring容器会自动的帮我们实现注入。
将Service层的@Resource(name = "userService")
改为@Resource(name = "userService1")
,运行会报错,由此发现,使用@Resoure
默认按照byName模式进行注入。改为@Autowired
,并更改Service的属性名:private UserDao userDao;
改为private UserDao userDao1;
,运行通过并有正确结果,说明@Autowired
注解默认按照byType模式进行注入。
@Qualifier注解的作用:
简单来说就是使用了@Autowired
注解,但是此时出现了使用同一接口的多个实现类,此时由于默认使用的是byType模式,Spring并不知道我们需要注入的是什么,使用我们可以用@Qualifier
调用byName模式告诉Spring我们需要注入那个bean。
注解注入之构造函数
在注解注入这块除了Setter注解注入,成员变量注解注入,还有一个比较重要的——“构造函数注入”。
其实也很简单理解,就是在构造方法上面写@Autowired即可,但是在学习的时候,碰到一个问题,就是一个有参构造函数中有多个同一类型形参,这个时候Spring就无法分辨我们实参的传递和赋值。
这个问题也想了好久,找了也蛮久的,因为这个问题是我临时想的,所以无从下手,一开始尝试使用@Qualifier
解决问题,因为可以根据byName模式注入嘛,但是放在构造方法上面又报错,用@Resource
也报错,就开始漫长的百度之旅,终于让我找到了一个很小很小的例子,@Qualifier
注解放入构造函数的形参前面,运行,发现能够正确的Run出结果,后面仔细一想,发现我们的问题本质是Spring无法识别我们实参的传递和赋值,使用@Qualifier
是正确的思路,主要是放置位置是在形参前面,来指明该形参使用的是byName模式并指明使用的BeanName,这样一来就能够理解了这一个特殊情况的解决问题方法。
代码如下:
@Controller("userAction")
public class UserAction {
private UserService userService1;
private UserService userService2;
@Autowired
public UserAction(@Qualifier("userService") UserService userService1, @Qualifier("userService1")UserService userService2) {
this.userService1 = userService1;
this.userService2 = userService2;
}
public void add(){
userService1.add();
userService2.add();
System.out.println("Action层的add()方法。。。");
}
}
在初学者应该会碰到这个问题,这个问题也是我在学习注解注入的构造方法的时候临时想到的!如果没有出现同类型的多参构造函数,一般情况下不需要使用@Qualifier
小结
实际上,我们使用注解来帮助我们注入时,是Spring帮助我们节省了代码,实现了操作,原理依旧是咱们写在XML配置文件中的一样,需要注意的就是@Autowired
和@Repository
注解默认使用的Autowire注入模式不同。还有就是在构造方法中@Autowired
和@Qualifier
的搭配使用
1.强制性的依赖性或者当目标不可变时,使用构造函数注入(应该说尽量都使用构造器来注入)
2.可选或多变的依赖使用setter注入(建议可以使用构造器结合setter的方式来注入)
3.在大多数的情况下避免field域注入(感觉大多数同学可能会有异议,毕竟这个方式写起来非常简便,但是它的弊端确实远大于这些优点)
会加油学习Java的,目前水平还不够,基础不扎实。