【Spring 注解式开发】自动装配

所谓自动装配,就是Spring 自动从 Spring 容器当中获取 Bean 对象并注入到需要的属性上的过程,也叫依赖注入(DI)。要想了解都有哪些装配方法,首先需要了解 Spring 对 Bean 的命名规则。Bean 的命名规则icon-default.png?t=N7T8http://t.csdn.cn/45BwD

Spring 中实现依赖注入有以下三种方法:

  1. 属性注入(Field Injection)
  2. Setter 注入(Setter Injection)
  3. 构造器注入(Constructor Injection)

简单类型注入

简单类型的注入使用  @Value 注解,该注解可以出现在属性上、setter 上和构造器的入参上。使用方法如下:

// 这里三种方法全部写了,实际使用任选其一,一般推荐使用属性注入方式
@Component
public class User {
    @Value("张三")
    private String name;
    @Value("张三")
    public void setName(String name) {
        this.name = name;
    }
    public User(@Value("张三") String name) {
        this.name = name;
    }
}

对象类型注入

属性注入

属性注入的实现代码共有三种情况,当然 Setter 注入和构造器注入也有类似情况,所以统一在属性注入这里详细描述,后面谈到 Setter 注入和构造器注入时就不过多赘述了。具体实现代码如下:

// 情况一:容器中只有一个类型匹配上的 Bean 的注入情况
@Component
public class FieldInjectionDemo {
    @Autowired
    private Student student;

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        FieldInjectionDemo demo = context.getBean(FieldInjectionDemo.class);
        System.out.println(demo.student.name);
    }
}
@Component
class Students {
    @Bean
    public Student stu1() {
        return new Student("张一");
    }
}
class Student {
    String name;
    public Student(String name) {
        this.name = name;
    }
}

情况一运行结果:

// 情况二:容器中有多个类型匹配上的 Bean 的注入情况
@Component
public class FieldInjectionDemo {
    @Autowired
    private Student student;

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        FieldInjectionDemo demo = context.getBean(FieldInjectionDemo.class);
        System.out.println(demo.student.name);
    }
}
@Component
class Students {
    @Bean
    public Student stu1() {
        return new Student("张一");
    }
    @Bean
    public Student stu2() {
        return new Student("张二");
    }
    @Bean
    public Student student() {
        return new Student("张三");
    }
}

情况二运行结果:

// 情况三:容器中有多个类型匹配上的 Bean,但是 Bean 名称无法与属性名相吻合的注入情况
@Component
public class FieldInjectionDemo {
    @Autowired
    @Qualifier("stu2")
    private Student student;

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        FieldInjectionDemo demo = context.getBean(FieldInjectionDemo.class);
        System.out.println(demo.student.name);
    }
}
@Component
class Students {
    @Bean
    public Student stu1() {
        return new Student("张一");
    }
    @Bean
    public Student stu2() {
        return new Student("张二");
    }
    @Bean
    public Student stu3() {
        return new Student("张三");
    }
}

 情况三运行结果:

Setter 注入

Setter 注入的实现代码如下:

@Component
public class SetterInjectionDemo {
    
    private Student student;
    
    @Autowired
    public void setStudent(Student student) {
        this.student = student;
    }
    
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        SetterInjectionDemo demo = context.getBean(SetterInjectionDemo.class);
        System.out.println(demo.student.name);
    }
}
@Component
class Students {
    @Bean
    public Student stu1() {
        return new Student("张一");
    }
}

构造器注入

构造器注入的实现代码如下:

@Component
public class ConstructorInjectionDemo {
    private Student student;

    @Autowired
    public ConstructorInjectionDemo(Student student) {
        this.student = student;
    }

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        ConstructorInjectionDemo demo = context.getBean(ConstructorInjectionDemo.class);
        System.out.println(demo.student.name);
    }
}
@Component
class Students {
    @Bean
    public Student stu1() {
        return new Student("张一");
    }
}

当构造器只有一个的时候,还可以将 @Autowired 省略,如:

@Component
public class ConstructorInjectionDemo {
    private Student student;

    public ConstructorInjectionDemo(Student student) {
        this.student = student;
    }

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        ConstructorInjectionDemo demo = context.getBean(ConstructorInjectionDemo.class);
        System.out.println(demo.student.name);
    }
}

当容器中存在多个类型匹配上的 Bean 时需要注意的是:@Qualifier 不可以标记到构造器上,但是可以标记到构造器入参上,代码如下:

@Autowired
public FieldInjectionDemo(@Qualifier("stu2") Student student) {
    this.student = student;
}

使用方法总结

  • 使用 @Autowired 进行对象注入时,首先根据对象的类型从容器中获取对象,如果类型匹配上的对象只有一个,那么就直接将对象注入;

  • 如果容器中有多个匹配的对象,此时会根据属性名 / 入参名和容器中的 Bean 的名称进行匹配注入;

  • 如果容器中有多个匹配的对象,但是没有一个 Bean 名称与属性名 / 入参名相吻合,那么此时需要配合注解 @Qualifier 来指定要注入的 Bean 名称。

@Resource

  • @Resource 注解是 JDK 扩展包中的,也就是说属于 JDK 的一部分。所以该注解是标准注解,更加具有通用性。
  • 执行流程:默认根据  name 装配,未指定 name 时,使用属性名作为 name。通过 name 找不到的话会通过类型装配。
  • 只能用在属性上和 setter 上,不能用在构造器上。

@Resource 注解属于 JDK 扩展包,所以不在 JDK 当中,需要额外引入以下依赖:【如果是 JDK8 的话不需要引入。高于 JDK11 或低于 JDK8 需要引入

<dependency>
  <groupId>jakarta.annotation</groupId>
  <artifactId>jakarta.annotation-api</artifactId>
  <version>2.1.1</version>
</dependency>

一定要注意:如果你用 Spring 6,要知道 Spring 6 不再支持 JavaEE,它支持的是  JakartaEE9。(Oracle 把 JavaEE 贡献给 Apache 了,Apache 把 JavaEE 的名字改成 JakartaEE 了,大家之前所接触的所有的 javax.* 包名统一修改为 jakarta.* 包名了)

关于 @Autowired 和 @Resource 的其他区别请见磊哥博客:@Autowired 报错的 4 种情况!icon-default.png?t=N7T8http://t.csdn.cn/QV56w

三种注入方式的优缺点

  • 属性注⼊
    • 优点:简洁,使⽤⽅便;
    • 缺点:过于依赖 IoC 容器,如果没有 IoC 容器则不可⽤;并且不能为 final 修饰的变量注入对象。
  • Setter 注入
    • 优点:通用性好,不依赖 IoC 容器,即使没有 IoC 容器也可以手动调用 setter 注入。可以解决循环依赖问题。
    • 缺点:不能为 final 修饰的变量注入对象;注入的对象可被修改,因为在任意位置都可以调用 Setter 来重新赋值。
  • 构造器注入
    • 优点:可以为 final 修饰的变量注入对象;注入的对象不能被修改,因为创建对象的时候才会调用构造器,并且只会调用一次;通用性更好,不依赖 IoC 容器;构造器注入是目前 Spring 官方推荐的方式。

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小李哞哞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值