关于Autowired那点事
大家都知道,注解出来之前,向一个bean中注入另一个bean我们需要在配置文件里配置,像这样:
<?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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="car" class="com.example.demo.bean.Car" />
<bean id="person" class="com.example.demo.bean.Person" >
<!-- 第一种方式,通过setter方法注入 -->
<property name="car" ref="car" />
<!-- 第二种方式,通过构造函数注入 -->
<constructor-arg ref="car" />
</bean>
</beans>
我们看到,要在Person类中注入Car实例,首先要声明两个这两个bean,同时还要在Person类中提供带有Car参数的有参构造函数(如果选择通过构造器注入),或者提供setter方法(setter注入),像这样:
public class Person {
private Car car;
// 构造器注入时必须提供此构造函数
public Person(Car car) {
this.car = car;
System.out.println("===>inject car by constructor. ");
}
// setter注入时必须提供此set方法
public void setCar(Car car) {
this.car = car;
}
}
大家想想,如果我们Person类又需要注入一个其他bean NewCar,我们怎么做?首先,我们要在xml里面配置这个NewCar,,然后在person这个bean里面通过进行setter注入,或者构造器注入,最后我们还要对应的在Person类里面增加一个构造器或者set方法。。。
上面的过程,元芳你怎么看?
于是便有了注解。。。注解真是个好东西
有了注解以后,我们就省去了在xml里面配置so many bean的烦恼,麻麻再也不用担心我代码写的慢了。。
第一步,xml配置一个扫描器,扫描我们要放去bean容器的所有类(application-context.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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example.demo.bean" />
</beans>
第二步,在我们需要spring帮我们管理的bean上面增加注解:@Controller、@Component、@Service、@Repository、@Resource其中的一种,这些注解就是告诉spring,你给我创建这些bean的实例,要用的时候我就直接去容器里拿了。我们想在person类里用car,直接一个@Autowired,car实例就来了,我们想来个NewCar,那就再@Autowired一下,多么简单。我们的世界再也没有了new。。。
@Component
public class Car {
public Car() {
System.out.println("得到了car实例");
}
}
@Component
public class Person {
@Autowired
private Car car;
}
注解确实让我们的世界清静了很多,但是大家有没有想过,注解的本质是什么?
有句话收得好:万变不离其宗。其实注解本质上和xml是一样的,毕竟是先有xml配置,然后才有的注解。
细想一下我们就会发现,这个@Component不就等于我们在xml里面bean的声明么 ,在person里面注入car不就等于在xml里person bean里配置的car注入么。。。
等等,这里有人就有疑问了,person里面注入car有两种方式,那@Autowired到底是set注入还是构造器注入呢?good question。有问题就要动手去实践
测试类:
public class XmlConfigBeanTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-context.xml");
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
}
}
Person类:
@Component
public class Person {
private String name;
@Autowired
private Car car;
public Person(Car car) {
this.car = car;
System.out.println("===>inject car by constructor. ");
}
public void setCar(Car car) {
this.car = car;
System.out.println("===>inject by setter. ");
}
@Override
public String toString() {
return "Person{" +
" car=" + car +
'}';
}
}
我们这里注解,set、构造器都提供,大家猜猜spring通过哪种方式注入car?看结果:
===>inject car by constructor.
Person{ car=com.example.demo.bean.Car@1e8b7643}
意外吧,spring首选还是构造器注入,我们把构造器注释掉,结果:
Person{ car=com.example.demo.bean.Car@1115ec15}
此时选择的是@Autowired注解,大家可以在@Autowired接口里打上断点,debug一下,就会证实确实如此。
我们继续把@Autowired注释掉,结果:
Person{ car=null}
没注入进去。。。也就是有setter也不管用。
结论:@Autowired注解本质上等价于构造器注入。