这个注解是核心注解之一。
参考资料
介绍
@Autowired
:织入(Spring
上下文已有实例(已注入IOC
),@Autowired
只是取一下)
@Autowired
说:”请给我一个该类的实例,例如,我之前用@Bean
或者@Component
注释创建的一个实例进入IOC
了”。
其实,用法的简单原理是这样的:
@Component
注解的类,会被 spring
扫描到,并且,实例化一个类到 spring IOC
。
而,@Autowired
注解的属性或者其他,会从 spring IOC
拿到之前注解的实例。
也就是,一般来说 @Component
配合 @Autowired
联用。
默认情况下必须要求依赖对象存在,如果要允许 null
值,可以设置它的required
属性为false
。
使用
@Autowired 可以修饰
关于上面的详细请参考。
我在这里只针对两个进行简要说明「主要是其他没有用到,未来可能会继续补充」
成员变量 一般,我们都会这样使用该注解。
application.properties 1 2 person.name =123 person.age =1
user,java 1 2 3 4 5 6 7 @Data @Component @ConfigurationProperties (prefix = "person" , ignoreUnknownFields = false )public class User { private String name; private int age; }
test.java 1 2 3 4 5 6 @service public class TestService { @Autowired private User user; }
但是,这样的使用方式在 IDEA
中会出现 warning
。
Spring Team recommends “Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies”.
如果要编辑器修改的话,会被修改成
1 2 3 4 5 private final User user;public HelloController (User user) { this .user = user; }
这是 java
的书写规范问题,至于,为什么要有 final
,我搬运一下网上的答案。不过,这样子写,感觉破坏了唯一性。
spring
配置默认的 bean
的 scope
是 singleton
,也就是启动后一直有。通过设置 bean
的 scope
属性为 prototype
来声明该对象为动态创建。但是,如果你的 service
本身是 singleton
,注入只执行一次。@Autowired
本身就是单例模式,只会在程序启动时执行一次,即使不定义final
也不会初始化第二次,所以这个final
是没有意义的吧。可能是为了防止,在程序运行的时候,又执行了一遍构造函数;
或者是更容易让人理解的意思,加上final
只会在程序启动的时候初始化一次,并且在程序运行的时候不会再改变。
例子说明所用实例唯一 application.properties 1 2 person.name =123 person.age =1
user,java 1 2 3 4 5 6 7 @Data @Component @ConfigurationProperties (prefix = "person" , ignoreUnknownFields = false )public class User { private String name; private int age; }
TestService.java 1 2 3 4 5 6 7 8 9 10 @service public class TestService { @Autowired private User user; public void test () { System.out.println(user.getName()); } }
InitService.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Component public class InitService { @Autowired private User user; @Autowired private TestService testService; @PostConstruct public void init () { System.out.println(user.getName()); user.setName("test" ); testService.test(); } }
输出
123
test
构造器 假设有这样一个例子。
1 2 3 4 5 6 7 8 @Autowired private User user; private String school; public UserAccountServiceImpl () { this .school = user.getSchool(); }
很明显,这个例子运行并不成功,因为
Java
类会先执行构造方法,然后再给注解了@Autowired
的user
注入值。
所以,构造方法中会出现空指针错误。
但是,我们可以给构造方法,添加该注解。
1 2 3 4 5 6 7 8 private User user; private String school; @Autowired public UserAccountServiceImpl (User user) { this .user = user; this .school = user.getSchool(); }
这是因为:
Java
变量的初始化顺序为:静态变量或静态语句块–>实例变量或初始化语句块–>构造方法
因为 user
是实例变量,所以,会先初始化它。
当然,User
需要 @Component
之类的注解进行修饰。
多实例使用 这个请参考。
集合注入 除了指定 Bean 的方式注入,我们也可以通过集合的方式一次性注入接口的所有实现类:
1 2 3 4 5 6 7 8 @Component public class InterfaceInject { @Autowired List <IWolf> list; @Autowired private Map <String ,IWolf> map; }
上面的两种形式都会将 IWolf
中所有的实现类注入集合中。如果使用的是 List
集合,那么我们可以取出来再通过 instanceof
关键字来判定类型;而通过 Map
集合注入的话,Spring
会将 Bean
的名称(默认类名首字母小写)作为 key
来存储,这样我们就可以在需要的时候动态获取自己想要的实现类。
注入为 null 有时候,我们使用这个注解,发现注入的值为 null
,造成这种原因可能有以下几种情况
该类没有托管给 spring
管理
这个类有被 new
出来的实例的,new
过的对象不会交给 Spring
容器管理 所以里面的 service
或者 dao
注入不进来
确实需要在这个 new
的类去注入某些类,但是用 @Autowired
又注入为 null
,这时候我们需要手动去弄 Spring
容器中的 Bean
实现 ApplicationContextAware
接口
举一个简单的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package com.lou.springboot;import com.alibaba.fastjson2.JSON;import lombok.Data;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.ConfigurableApplicationContext;import org.springframework.stereotype.Component;import org.springframework.stereotype.Service;@SpringBootApplication public class Application { public static void main (String[] args) { ConfigurableApplicationContext configurableApplicationContext = SpringApplication.run(Application.class , args ) ; Run run = new Run(); run.proc(); } } @Data class Person { private String name; private Integer age; } @Service class PersonService { public void proc (String cppMsg) { Person person = JSON.parseObject(cppMsg, Person.class ) ; System.out.println(person); } } @Component class Run { @Autowired private PersonService personService; public void proc () { personService.proc("{\"age\":12,\"name\":\"Antony\"}" ); } }
此时 personService.proc("{\"age\":12,\"name\":\"Antony\"}");
的 personService
是 null
。
使用 ConfigurableApplicationContext
进行获取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package com.lou.springboot;import com.alibaba.fastjson2.JSON;import lombok.Data;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.ConfigurableApplicationContext;import org.springframework.stereotype.Component;import org.springframework.stereotype.Service;@SpringBootApplication public class Application { public static void main (String[] args) { ConfigurableApplicationContext configurableApplicationContext = SpringApplication.run(Application.class , args ) ; Run run = configurableApplicationContext.getBean(Run.class ) ; run.proc(); } } @Data class Person { private String name; private Integer age; } @Service class PersonService { public void proc (String cppMsg) { Person person = JSON.parseObject(cppMsg, Person.class ) ; System.out.println(person); } } @Component class Run { @Autowired private PersonService personService; public void proc () { personService.proc("{\"age\":12,\"name\":\"Antony\"}" ); } }
另一种方式请参考 spring | ApplicationContextAware 接口