Spring的依赖注入
Spring中有几种依赖注入的方式?
从大的范围来说就是:手动注入和自动注入
手动注入
手动注入是我们最开始学习spring的时候使用的,因为对于初学者来说那更容易理解。
set注入
<bean name="userService" class="com.qijian.service.UserService"> <property name="orderService" ref="orderService"/> </bean>
构造方法注入
<bean name="userService" class="com.qijian.service.UserService"> <constructor‐arg index="0" ref="orderService"/> </bean>
使用命名空间注入
c名命空间和p名命空间不能直接使用需要导入xml约束。
@Data public class User { private String name; private int age; }
C:xmlns:c="http://www.springframework.org/schema/c"
<bean id="user1" class="com.qijian.pojo.User" c:name="qijianc" c:age="18"/>
P:xmlns:p="http://www.springframework.org/schema/p"
<bean id="user" class="com.qijian.pojo.User" p:name="qijian" p:age="18" />
自动注入
xml的autowire自动注入
在xml中,可以定义一个Bean时去指定这个bean的自动注入模式
byType,byName,constructor,default,no
<bean id="userService" class="com.luban.service.UserService" autowire="byType"/>
表示Spring会自动的给userService中所有的属性自动赋值(不需要这个属性上有
@Autowired注解,但需要这个属性有对应的set方法)。
Spring在通过byName的自动填充属性时流程是:
找到所有set方法所对应的XXX部分的名字
根据XXX部分的名字去获取bean
Spring在通过byType的自动填充属性时流程是:
获取到set方法中的唯一参数的参数类型,并且根据该类型去容器中获取bean
如果找到多个,会报错。
Spring在通过constructor的自动填充(假设只有一个构造方法)
此时就可以不写set方法了,当某个bean是通过构造方法来注入时,spring利用
构造方法的参数信息从Spring容器中去找bean,找到bean之后作为参数传给构造方法,从而实例化得到一个bean对象,并完成属性赋值(属性赋值的代码得程序员来写)。
其他
no,表示关闭autowire
default,表示默认值,我们一直演示的某个bean的autowire,而也可以直接在标签中设置autowire,如果设置了,那么标签中设置的autowire如果为default,那么则会用标签中设置的autowire。
注意:XML中的autowire控制的是整个bean的所有属性,而@Autowired注解是直接写在某个属性、某个set方法、某个构造方法上的。
@Autowired注解相当于XML中的autowire属性的注解方式的替代。
从本质上讲,@Autowired注解提供了与autowire相同的功能,但是拥有更细粒度的控制和更广泛的适用性。
为什么我们平时都是用的@Autowired注解呢?而没有用上文说的这种自动注入方式呢?
@Autowired是更细粒度的控制(XML中的autowire控制的是整个bean的所有属性,而@Autowired注解是直接写在某个属性、某个set方法、某个构造方法上的。)
如果一个类有多个构造方法,那么如果用XML的autowire=constructor,你无法控制到底用哪个构造方法,而你可以用@Autowired注解来直接指定你想用哪个构造方法。同时,用@Autowired注解,还可以控制,哪些属性想被自动注入,哪些属性不想,这也是细粒度的控制。但是@Autowired无法区分byType和byName,@Autowired是先byType,如果找到多个则byName。
@Autowired注解的自动注入
@Autowired注解可以写在:
- 属性上:先根据属性类型去找Bean,如果找到多个再根据属性名确定一个
- 构造方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
- set方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
为什么@Autowired不支持静态字段或属性的注入?
@Component @Scope("prototype") public class OrderService { }
@Component @Scope("prototype") public class UserService { @Autowired private static OrderService orderService; public void test() { System.out.println("test123"); } }
UserService和OrderService都是原型Bean,假设Spring支持static字段进行自动注
入,那么现在调用两次
UserService userService1 = context.getBean("userService") UserService userService2 = context.getBean("userService")
问此时,userService1的orderService值是什么?还是它自己注入的值吗?
答案是不是,一旦userService2 创建好了之后,static orderService字段的值就发生了修改了,从而出现bug。