@Autowired使用全纪录

前言:

    @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.
	 * <p>Defaults to {@code true}.
	 */
	boolean required() default true;

}

    可以配置在构造函数、方法上、方法参数上、成员变量上。

    其他方式不多介绍,笔者再使用的时候主要还是使用配置在成员变量上这么一种方式。    

    先从网络上摘录一段(来自https://www.cnblogs.com/caoyc/p/5626365.html ):

    @Autowired注解标注在上面这些位置,可以实现自动装配的工作。在使用@Autowired之前,我们对一个bean的属性进行装配的方式如下:

扫描二维码关注公众号,回复: 8522719 查看本文章
<property name="属性名" value=" 属性值"/> 

    这种可想而知,如果有比较多的属性依赖,那么是要写一大段这样的配置的

    基于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中

<context:component-scan base-package="annotation"/>

   

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来实现

参考:

https://docs.spring.io/spring/docs/4.3.23.RELEASE/spring-framework-reference/htmlsingle/ 

代码地址:https://github.com/kldwz/springstudy  

发布了122 篇原创文章 · 获赞 119 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_26323323/article/details/90140201