@Autowired不止可以标注在属性上,也可以标注在构造器、方法、参数上
标注在方法上:
@Component
public class Student {
private Bike bike;
public Bike getBike() {
return bike;
}
@Autowired
public void setBike(Bike bike) {
this.bike = bike;
}
}
一般标注在Setter方法上,其实可以标注在任何方法上,但是方法一定要有入参。此时,Spring容器在初始化Student对象后就会调用其标注@Autowired的方法,将属性注入进去,注入的方式依然是先根据类型查找,查到多个时再根据参数名匹配。那么问题来了,标注有@Autowired注解的方法是何时调用的呢?如果在被注入的对象创建之前调用肯定是不行的,在从容器中获取Student的实例时该实例就已经有了bike属性值,说明该属性的注入并非在第一次使用时,而是在容器创建bean之后通过后置处理的方式注入的该属性,难道是在容器中所有的Bean都创建完之后才会调用这些@Autowired注解的方法吗?是的,其实是AutowiredAnnotationBeanPostProcessor后置处理器的功劳,在创建完Bean之后会后置处理这些标注有@Autowired注解的方法、属性、入参等。那么还有一个问题假如容器中的bean没有无参构造器,但有一个标注了@Autowired注解的有参构造器(在只有一个有参构造器时该构造器上的@Autowired可以省略,就是说隐藏带有@Autowired),此时在创建bean的时候就需要注入属性,那就不是AutowiredAnnotationBeanPostProcessor能解决的了,这时会怎么样呢?这时Spring会将这个Bean的创建时机置后,待其他的Bean都创建完之后再创建该Bean,如果两个类中都有@Autowired注解的构造器,且彼此的构造器中的入参相互引用的话则会报错,因为这两个对象都无法创建,报UnsatisfiedDependencyException异常,此时采用@Autowired(required=false)也不可以,原因也很简单,因为在创建对象时都需要检查彼此有没有创建好,而返回的都是false,所以不可以。
标注在构造器上:注意必须是有参构造器
@Component
public class Student {
private Bike bike;
@Autowired
public Student(Bike bike) {
this.bike = bike;
}
public Bike getBike() {
return bike;
}
public void setBike(Bike bike) {
this.bike = bike;
}
}
默认情况下,Spring在实例化bean时会调用类的无参构造器,但是在类提供了有参构造器时,如果有参构造器上有@Autowired注解,Spring则会调用该有参构造器创建实例,如果没有,则还是调无参构造器(无参构造器存在)。那么问题来了,如果类中既有无参构造,又有@Autowired注解的有参构造,或者有多个@Autowired注解的有参构造时Spring会怎么创建实例呢?在有多个@Autowired标注的构造器时会报错,在仅有一个@Autowired标注的构造器时,会调用@Autowired标注的构造器,如果只有一个有参构造器时,@Autowired可以省略。
标注在参数上:作用和标注在方法上是一样的,只不过标注在参数上可以更精确的指明哪些参数需要由Spring注入,哪些不必由Spring注入
@Component
public class Student {
private Bike bike;
private Car car;
public Student(@Autowired Bike bike, Car car) {
this.bike = bike;
this.car = car;
System.out.println("两个参数...");
}
public Bike getBike() {
return bike;
}
public void setBike(Bike bike) {
this.bike = bike;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
}
容器类中@Bean注解的方法的入参的实例也是从容器中获取的:相当于入参的位置加了@Autowired,此时入参位置的bean必须能在容器中找到,否则会报错,如果不想使其报错,可以使用required=false指明其并非必须的
@Configuration
@ComponentScan("com.bdm.modle")
public class AutowiredConfig {
@Bean
public Student student(Car car, @Autowired(required = false) Bike bike) {
Student student = new Student();
student.setBike(bike);
student.setCar(car);
return student;
}
}
在IOC容器中的bean的方法的入参中如果有Spring的底层类型,则会自动注入进去:
@Component
public class Car {
public Car(ApplicationContext applicationContext) {
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String string : beanDefinitionNames) {
System.out.println(string);
}
}
}
此处构造器中的ApplicationContext会由容器注入进去