主动式:要什么资源我们自己创建即可。过去采用的方式。
被动式:资源不是由我们自己创建,而是交给一个容器来创建和设置,我们直接拿来用。Spring采用的方式。
Spring中有个容器,容器能知道哪个组件(类)运行的时候,需要的另外一个组件(类)。容器通过反射的形式,将容器中准备好的组件注入当前组件中。
控制反转(IOC)是一种思想,依赖注入(DI)是一种实现。
在传统的依赖注入配置中,我们必须要明确要给属性装配哪一个bean的引用,一旦bean很多,就不好维护了。
基于这样的场景,Spring使用注解进行自动装配,来解决这个问题。自动装配就是开发人员不必知道具体要装配哪个bean的引用,这个识别的工作会由Spring来完成。自动装配是为了将依赖注入“自动化”的一个简化配置的操作。
首先要清楚组件(类)注册到Spring容器后的类型和name,方便下面的理解。
可以参考:https://blog.csdn.net/qq_42780289/article/details/107884738
1)容器中同类型只有一个组件的情况
默认优先按照类型去容器中找对应的组件,找到就赋值。具体看下面的例子:
组件1
@Service
public class BookService {
}
类型为BookService,name为bookService。
测试
@Autowired
BookService bookService;
@Test
void MyTest() {
System.out.println(bookService);
}
这里@Autowired先以属性的类型 BookService 去容器中找对应的组件,找到只有一个该类型的组件,成功!
2)容器中同类型有多个组件的情况
如果找到多个相同类型的组件,再将属性的名称作为组件的name去容器中查找。具体看下面的例子:
组件1
@Service
public class BookService {
}
类型为BookService,name为bookService。
组件2
@Configuration
public class MainConfigOfAutowired {
@Bean
public BookService bookService01() {
return new BookService();
}
}
类型为BookService,name为bookService01。
测试
@Autowired
BookService bookService;
@Autowired
BookService bookService01;
@Test
void MyTest() {
System.out.println(bookService);
System.out.println(bookService01);
}
第一个@Autowired先以属性的类型 BookService 去容器中找对应的组件,找到有两个该类型的组件;接着将属性的名称 bookService 作为组件的name去容器中查找,找到组件1,成功!
第二个@Autowired同理也可以找到组件2。
3)用类型和name都找不到组件
找不到就会报错。但是也可以使用@Autowired(required=false),找不到就赋值为空。
使用@Qualifier指定需要装配的组件的name,而不是使用属性的类型或属性的名称。具体看下面的例子:
组件1
@Service
public class BookService {
}
类型为BookService,name为bookService。
组件2
@Configuration
public class MainConfigOfAutowired {
@Bean
public BookService bookService01() {
return new BookService();
}
}
类型为BookService,name为bookService01。
测试
@Qualifier("bookService01")
@Autowired
BookService bookService;
@Test
void MyTest() {
System.out.println(bookService);
}
使用@Qualifier(“bookService01”)明确指定name后,@Autowired不再看属性的类型或属性的名称,直接用 bookService01 作为组件的name去容器中查找,找到组件2,成功!
让Spring进行自动装配的时候,默认使用首选(用@Primary指定)的bean。具体看下面的例子:
组件1
@Service
public class BookService {
}
类型为BookService,name为bookService。
组件2
@Configuration
public class MainConfigOfAutowired {
@Primary
@Bean
public BookService bookService01() {
return new BookService();
}
}
类型为BookService,name为bookService01。
测试1
@Autowired
BookService bookService;
@Test
void MyTest() {
System.out.println(bookService);
}
因为组件2使用了@Primary注解标注,所以@Autowired不再看属性的类型或属性的名称,直接就找到组件2,成功!
测试2
@Qualifier("bookService")
@Autowired
BookService bookService;
@Test
void MyTest() {
System.out.println(bookService);
}
虽然组件2使用了@Primary注解标注,但是使用@Qualifier()明确指定后,@Primary就不起作用了,所以还是直接用指定的 bookService 作为组件的name去容器中查找,找到组件1,成功!
@Autowired可以标注在,构造器、参数、方法、属性上,都是从容器中获组件并赋值。
1)标注在属性上
上面已经谈论了很多,这里就不说了。
2)标注在方法上
@Component
public class Bookshelf {
private Book book;
public Book getBook() {
return book;
}
@Autowired
public void setBook(Book book) {
this.book = book;
}
}
@Autowired标注在方法上,容器在创建 Bookshelf 对象时,会自动调用该方法从ioc容器中获取 Book 组件,注意该方法也会被执行一次。
3)标注在构造器上
@Component
public class Bookshelf {
private Book book;
@Autowired
public Bookshelf(Book book) {
this.book = book;
}
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
}
这里@Autowired标注在构造器上,容器在创建 Bookshelf 对象时,会先调用构造器从ioc容器中获取 Book 组件。
4)标注在参数上
@Configuration
public class MyConfig {
@Bean
public Bookshelf bookshelf(@Autowired Book book) {
return new Bookshelf(book);
}
}
这里@Autowired标注在参数上,在向容器注册 Bookshelf 组件时要用到 Book 组件,所以会先从ioc容器中获取 Book 组件,再进行注册。
1)标在构造器上的@Autowired可以省略
@Component
public class Bookshelf {
private Book book;
public Bookshelf(Book book) {
this.book = book;
}
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
}
如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,因为构造器要用的组件,都是从容器中获取。
2)@Bean标注方法时,参数的@Autowired可以省略
@Configuration
public class MyConfig {
@Bean
public Bookshelf bookshelf(Book book) {
return new Bookshelf(book);
}
}
这里@Bean标注的方法注册组件的时候,方法参数的值可以直接从容器中获取。
Spring还支持使用@Resource(JSR250)和@Inject(JSR330)。
可以和@Autowired一样可以实现自动装配功能。
默认是按照属性的名称来进行装配的。也可以指定name,比如@Resource(name="")。
没有类似@Autowired(reqiured=false)的功能,也不支持@Primary功能。
需要导入javax.inject的包。
<dependency>
<groupId>javax.injectgroupId>
<artifactId>javax.injectartifactId>
<version>1version>
dependency>
和@Autowired一样可以实现自动装配功能。
和@Autowired一样,先按照属性的类型查找,如果有多个同类型的组件,再按照属性的名称进行查找。
没有类似@Autowired(reqiured=false)的功能,但是支持@Primary功能。
Spring支持使用@Autowired注解,也支持使用@Resource(JSR250)和@Inject(JSR330)注解。
其中@Autowired是Spring框架中的注解,而@Resource(JSR250)和@Inject(JSR330)是java规范的注解。三者的用法前面都有讲,@Autowired注解的功能是最强大的。