Spring Annotations # @Autowired(每日一解系列)

2020-03-23 · 树下魅狐 · · 本文共1,872个字,预计阅读需要9分钟。

——每日一解系列之Spring Annotations

从Spring Framework 2.5开始,引入了一种全新的依赖注入注解@Autowired,这个注解允许Spring自动将被其注释的Java类注入到Spring 的BeanFactory中。

每日一解系列文章

序言

在本文中,我将基于Spring Boot来演示如何启用自动注入,以及@Autowired注解各种使用方式。在此系列的文章中,都将采用基于Java的配置方式来配置Spring中的Bean,不再使用基于XML的配置方式。

1. 启用Annotation

如果你同样使用了Spring Boot,则可以通过下面的Java代码配置方式来开启Annotation支持:

@Configuration
@ComponentScan(basePackages = {"com.ramostear.autowired.annotation.beans"})
public class AppConfig{

}

其中,@Configuration作用是告诉Spring这是一个基于Java的配置文件,@ComponentScan则指定Spring进行组件扫描的包路径。如果你使用基于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-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">

     <context:component-scan base-package="com.ramostear.autowired.annotation.beans"/>

</beans>

2. @Autowired注解

开启Spring注解支持后,你可以将@Autowired注解注释到类的属性,Setter方法或构造函数上。Spring会根据@Autowired作用的位置,自动完成目标对象的注入工作。

2.1 @Autowired作用于属性

@Autowired注解使用在类的属性上时,Spring会自动调用属性的目标类的构造方法,并将最终的实例化对象赋予当前的属性。下面以电脑,屏幕,键盘,鼠标为例子,演示四者之间通过Spring完成自动注入:

@Component
public class Keyboard {

    public void working(){
        System.out.println("keyboard is working...");
    }
}
@Component
public class Mouse {

    public void working(){
        System.out.println("mouse is working...");
    }
}
@Component
public class Screen {

    public void working(){
        System.out.println("screen is working...");
    }
}

说明

@Component注解表示该类是一个被Spring容器所管理的单例Bean组件

接下来,创建一个Computer.java类,并使用@Autowired注解对其属性进行注释:

@Component
public class Computer {

    @Autowired
    private Keyboard keyboard;
    @Autowired
    private Mouse mouse;
    @Autowired
    private Screen screen;

    public void working(){
        screen.working();
        keyboard.working();
        mouse.working();
        System.out.println("computer is working...");
    }
}

最后,在main方法中测试上述定义的三个组件是否成功注入到Computer类中,并输出相关的提示语句。在测试代码中,首先使用AnnotationConfigApplicationContext类获得应用上下文,然后通过类类型获得注入到Spring容器中的bean组件。

@SpringBootApplication
public class AutowiredAnnotationApplication {

    public static void main(String[] args) {
        SpringApplication.run(AutowiredAnnotationApplication.class, args);
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(AppConfig.class);

        System.out.println("@Autowired Annotation on field.");
        Computer computer = context.getBean(Computer.class);
        computer.working();

        context.close();

    }
}

main()方法运行结束后,可在控制台观察到如下的输出语句:

@Autowired Annotation on field.
screen is working...
keyboard is working...
mouse is working...
computer is working...

说明

如果@Autowired注解直接作用到属性上,则当前类在初始化时就需要完成其引用对象的装配工作。

2.2 @Autowired作用于Setter方法

当在Setter方法上使用@Autowired注解时,Spring会根据对象类型完成组件的自动装配工作。创建一个新的类MagicBook.java来演示此案例(其余的类沿用之前案例中的类):

@Component
public class MagicBook {

    private Keyboard keyboard;
    private Mouse mouse;
    private Screen screen;

    @Autowired
    public void setKeyboard(Keyboard keyboard) {
        this.keyboard = keyboard;
    }
    @Autowired
    public void setMouse(Mouse mouse) {
        this.mouse = mouse;
    }
    @Autowired
    public void setScreen(Screen screen) {
        this.screen = screen;
    }

    public void working(){
        screen.working();
        keyboard.working();
        mouse.working();
        System.out.println("MagicBook is working...");
    }
}

同样,在main()方法中编写对应的代码进行测试,并观察控制台输出信息。

System.out.println("@Autowired Annotation on setter method.");
MagicBook magicBook = context.getBean(MagicBook.class);
magicBook.working();
@Autowired Annotation on setter method.
screen is working...
keyboard is working...
mouse is working...
MagicBook is working...

提示

于作用在属性上不同的是,当@Autowired注解作用在Setter方法上时,在实例化当前类的过程中,不会立即装配相关的组件,只有在显示调用Setter方法时Spring才会完成装配工作。

2.3 @Autowired作用于Constructor

除上述两种方式外,@Autowired还可以在构造器上使用,在此情况下,当实例化当前对象时,Spring将自动完成组件注入工作。新建一个XPhone.java类演示此案例,并在main()方法中编写测试代码,运行并观察控制台输出。

@Component
public class XPhone {
    private final Keyboard keyboard;
    private final Mouse mouse;
    private final Screen screen;

    @Autowired
    public XPhone(Keyboard keyboard,Mouse mouse,Screen screen){
        this.keyboard = keyboard;
        this.mouse = mouse;
        this.screen = screen;
    }

    public void working(){
        keyboard.working();
        mouse.working();
        screen.working();
        System.out.println("XPhone is working...");
    }
}
System.out.println("@Autowired Annotation on constructor.");
XPhone xPhone = context.getBean(XPhone.class);
xPhone.working();
@Autowired Annotation on constructor.
keyboard is working...
mouse is working...
screen is working...
XPhone is working...

注意

如果@Autowired注解作用于构造器上,则该类中有且只有一个构造器可以使用@Autowired注解

3. 其他

3.1 默认配置

当一个类中有且只有一个构造器且使用基于构造器完成组件装配的情况下,构造器可以不使用@Autowired注解。Spring默认会使用该构造器并根据参数类型完成自动装配工作。新建一个XWatch.java来演示此案例:

@Component
public class XWatch {
    private final Keyboard keyboard;
    private final Mouse mouse;
    private final Screen screen;

    public XWatch(Keyboard keyboard,Mouse mouse,Screen screen){
        this.keyboard = keyboard;
        this.mouse = mouse;
        this.screen = screen;
    }

    public void working(){
        keyboard.working();
        mouse.working();
        screen.working();
        System.out.println("XWatch is working...");
    }
}

在main()方法中编写测试代码,运行main()方法并观察控制台输出:

System.out.println("Single constructor does not use @Autowired annotation.");
XWatch xWatch = context.getBean(XWatch.class);
xWatch.working();
Single constructor does not use @Autowired annotation.
keyboard is working...
mouse is working...
screen is working...
XWatch is working...

3.2 可选依赖

在使用@Autowired注解时,如果希望某个组件的自动装配是可选的(非必须),则可以通过下面的方式配置:

@Autowired(required=false)
private DemoComponent demoComponent;

本文所涉及的源代码已上传到Github,需要的小伙伴可点击下面的链接移步到Github进行下载: