@Autowired应该是我们在Spring项目中最常用的注解了。
使用起来非常方便,但是一旦出现问题调试起来也是比较麻烦的。
笔者就是这样,平时用来一时爽,出现问题两行泪。
究其原因,还是对@Autowired了解得不够深入,下决心好好玩一次
1.@Autowired介绍先来看下其定义,如下:
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* Declares whether the annotated dependency is required.
* Defaults to {@code true}.
*/
boolean required() default true;
}
可以配置在构造函数、方法上、方法参数上、成员变量上。
其他方式不多介绍,笔者再使用的时候主要还是使用配置在成员变量上这么一种方式。
先从网络上摘录一段(来自Spring 注解配置(2)——@Autowired - Just_Do - 博客园 ):
@Autowired注解标注在上面这些位置,可以实现自动装配的工作。在使用@Autowired之前,我们对一个bean的属性进行装配的方式如下:
这种可想而知,如果有比较多的属性依赖,那么是要写一大段这样的配置的
基于Annotation的@Autowired就把我们从这里解脱出来。
先来看一个示例
2.自动注入的示例不同于之前的XML方式和JavaConfig方式,笔者在这里都采用Annotation的方式
模拟项目中Service层和DAO层之间的调用,这个大家都比较熟悉的。
1)Service、DAO层接口及实现类
// DAO
public interface StudentDao {
public void add(Student stu);
public void delete(Student stu);
}
// Service
public interface StudentService {
public void add(Student stu);
public void delete(Student stu);
}
// DAOImpl
@Repository
public class StudentDaoImpl implements StudentDao {
@Override
public void add(Student stu) {
System.out.println("insert student..." + stu);
}
@Override
public void delete(Student stu) {
System.out.println("delete student..." + stu);
}
}
// ServiceImpl
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentDao studentDao;
@Override
public void add(Student stu) {
studentDao.add(stu);
}
@Override
public void delete(Student stu) {
studentDao.delete(stu);
}
}
2.AnnotationConfiguration类用于扫描包下的带有Annotation的类
@Configuration
@ComponentScan(basePackages = "annotation")
public class AnnotationConfiguration {
}
basePackages后面跟的就是需要扫描的包路径,以上几个类都在annotation包下,会被主动注入到容器中
3.测试
@Test
public void testAnnotationConfig(){
AnnotationConfigApplicationContext applicationContext
= new AnnotationConfigApplicationContext(AnnotationConfiguration.class);
// 1.如果采用名称匹配的话,StudentServiceImpl类的名称没有指定,默认生成为studentServiceImpl,当然我们也可以主动指定,通过@Service("name")来指定
StudentService studentService = (StudentService) applicationContext.getBean("studentServiceImpl");
// 2.通过类型匹配,我们常用这种方式
//StudentService studentService = applicationContext.getBean(StudentService.class);
Student stu = new Student();
stu.setName("lucy");
stu.setAge(20);
studentService.add(stu);
}
// res
insert student...Student(id=0, name=lucy, age=20)
总结:
* 既然是通过Annotation的方式来注入bean,那么一定要记得在实现类上添加相应的注解;
* 通过JavaConfig的方式来扫描包下的类,并添加到容器中,这种方式类似于beans.xml中
3.@Autowired的规则
@Autowired默认是按照类型进行匹配的(byType),默认情况下,它要求依赖对象必须存在,否则会报错,当然我们也可以设置@Autowired(required=false)来设置。
@Autowired的查找过程如下:
@Autowired注解在容器中查找对应类型的bean
* 如果结果刚好为一个,则将该bean装配给@Autowired指定的变量
* 如果一个也没有,并且required=true的情况下,则报错
* 如果为多个,则也会报错,因为Spring不知道该依赖哪一个具体的bean
关于第2/3条大家可以自己试下。
提出一个问题:如果项目中出现了StudentDao接口的多个实现类,那么我们如何依赖呢?如何依赖某一个具体的实现类呢?
接着往下看...
4.@Autowired与@Qualifier强强联合针对于上面的问题,我们就需要指定具体的bean名称来依赖,具体做法如下:
1)添加一个StudentDAO的实现,并设置原来的StudentDaoImpl名称
// 主动指定一个名称,不使用自定义的名称studentDaoImpl
@Repository("stuDao")
public class StudentDaoImpl implements StudentDao {}
// 创建另一个实现,名称为stuDao1
@Repository("stuDao1")
public class StudentDaoImpl1 implements StudentDao {
@Override
public void add(Student stu) {
System.out.println("dao1 insert student..." + stu);
}
@Override
public void delete(Student stu) {
System.out.println("dao1 delete student..." + stu);
}
}
2)StudentServiceImpl主动指定依赖项
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
@Qualifier("stuDao1")// 指定指定名称为stuDao1的bean注入
private StudentDao studentDao;
@Override
public void add(Student stu) {
studentDao.add(stu);
}
@Override
public void delete(Student stu) {
studentDao.delete(stu);
}
}
3)测试
// 测试类方法依然不变,结果如下
dao1 insert student...Student(id=0, name=lucy, age=20)
可以看到结果:StudentServiceImpl使用了我们指定的那个DAO实现类来进行了save操作
5.@Autowired与@Primary强强联合
除了上面的指定dao实现类名称,我们也可以使用@Primary来实现。
这个注解的含义就是,当多个实现类共存时,优先使用含有@Primary注解的实现类。
这个笔者就不再详述过程了,大家可以自己试下。
总结:
我们在使用@Autowired注解的时候,Spring主要是基于类型来主动装配的,如果我们需要指定某一个实现类,可以考虑使用@Primary或者@Qualifier来实现
参考:Spring Framework Reference Documentation
代码地址:GitHub - kldwz/springstudy