Spring中Bean的装配方式

Spring有三种装配Bean的方式:
(1)在XML中显式配置;
(2)在Java中显式配置;
(3)隐式的Bean发现机制和自动装配;
之前在xml中设置Bean的属性就是第一种方式,而第三种方式是Spring中最重要的装配方式。
Spring的自动装配需要从两个操作来实现:
组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;
组件扫描和自动装配组合发挥巨大威力,使的显示的配置降低到最少。Spring的自动装配分为xml装配和注解,推荐不使用自动装配xml配置 , 而使用注解 。

使用xml配置完成自动装配

  1. package com.wjh.po;
  2. /**
  3. * @author wjh
  4. * @date 2021/7/16 23:13
  5. * @Package com.wjh.po
  6. */
  7. public class Cat {
  8. public void shout(){
  9. System.out.println("喵喵喵~~~");
  10. }
  11. }
  1. package com.wjh.po;
  2. /**
  3. * @author wjh
  4. * @date 2021/7/16 23:12
  5. * @Package com.wjh.po
  6. */
  7. public class Dog {
  8. public void shout(){
  9. System.out.println("汪汪汪!!!");
  10. }
  11. }
  1. package com.wjh.po;
  2. /**
  3. * @author wjh
  4. * @date 2021/7/16 23:14
  5. * @Package com.wjh.po
  6. */
  7. public class Person {
  8. private String name;
  9. private Cat cat;
  10. private Dog dog;
  11. public Person() {
  12. }
  13. public Person(String name, Cat cat, Dog dog) {
  14. this.name = name;
  15. this.cat = cat;
  16. this.dog = dog;
  17. }
  18. public String getName() {
  19. return name;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. public Cat getCat() {
  25. return cat;
  26. }
  27. public void setCat(Cat cat) {
  28. this.cat = cat;
  29. }
  30. public Dog getDog() {
  31. return dog;
  32. }
  33. public void setDog(Dog dog) {
  34. this.dog = dog;
  35. }
  36. @Override
  37. public String toString() {
  38. return "Person{" +
  39. "name='" + name + '\'' +
  40. ", cat=" + cat +
  41. ", dog=" + dog +
  42. '}';
  43. }
  44. }

byName自动装配(按名称自动装配)

  1. <bean id="dog" class="com.wjh.po.Dog" />
  2. <bean id="cat" class="com.wjh.po.Cat"/>
  3. <bean id="person" class="com.wjh.po.Person" autowire="byName">
  4. <property name="name" value="阿离"/>
  5. </bean>

可以看到,byName自动装配只需要在bean标签加上“autowire=”byName””即可,这样就可以自动装配Person类的cat(装载为Cat实例)和dog(装载为Dog实例)属性了,而以前的手动装载的xml配置是:

  1. <bean id="dog" class="com.wjh.po.Dog" />
  2. <bean id="cat" class="com.wjh.po.Cat"/>
  3. <bean id="person" class="com.wjh.po.Person" autowire="byName">
  4. <property name="name" value="阿离"/>
  5. <property name="cat" ref="cat"/>
  6. <property name="dog" ref="dog"/>
  7. </bean>

byName实现机制:
byName自动装配是利用Java的反射机制获取自动装配类中的set方法名,去掉set后将其首字母小写再到IOC容器中查找是否有对应Bean的id,如果有则查看该Bean的类型与set方法的参数类型是否匹配,匹配上了则调用set方法进行依赖注入,否则会报空指针异常。因此,byName的自动装配跟set方法名和参数类型有关,跟属性名无关。

byType自动装配 (按类型自动装配)

使用byType自动装配的前提条件:同一类型的对象,在spring容器中唯一。如果不满足前提条件会报不唯一异常(NoUniqueBeanDefinitionException)。如(不满足前提,无法自动装配):

  1. <bean id="dog" class="com.wjh.po.Dog" />
  2. <bean id="cat" class="com.wjh.po.Cat"/>
  3. <bean id="cat2" class="com.wjh.po.Cat"/>
  4. <bean id="person" class="com.wjh.po.Person" autowire="byType">
  5. <property name="name" value="阿离"/>
  6. </bean>

byType实现机制:
byType自动装配是利用Java的反射机制获取类中的set方法的参数类型,寻找此接口类型的实现类或子类,找到后将其首字母小写与IOC容器Bean的id进行匹配,匹配成功后则调用set方法进行依赖注入。因此,byType自动装配与方法名无关,与属性名无关,与set方法的参数类型有关。

通过byName和byType的实现机制可以看到,二者都用到的是反射机制,而且都必须具有set方法,否则无法完成装配。

使用注解完成自动装配

环境配置:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:context="http://www.springframework.org/schema/context"
  4. 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">
  5. <context:annotation-config/>//开启属性注解支持
  6. <bean id="..." name="...">...<bean/>
  7. </beans>

使用@Autowired自动装配

@Autowired可以想象成byType装配,只需要在属性上面打上这个注解就可以完成自动装配了,如:

  1. package com.wjh.po;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. /**
  4. * @author wjh
  5. * @date 2021/7/16 23:14
  6. * @Package com.wjh.po
  7. */
  8. public class Person {
  9. private String name;
  10. @Autowired
  11. private Cat cat;
  12. @Autowired
  13. private Dog dog;
  14. public Person() {
  15. }
  16. public Person(String name, Cat cat, Dog dog) {
  17. this.name = name;
  18. this.cat = cat;
  19. this.dog = dog;
  20. }
  21. public String getName() {
  22. return name;
  23. }
  24. public void setName(String name) {
  25. this.name = name;
  26. }
  27. public Cat getCat() {
  28. return cat;
  29. }
  30. public void setCat(Cat cat) {
  31. this.cat = cat;
  32. }
  33. public Dog getDog() {
  34. return dog;
  35. }
  36. public void setDog(Dog dog) {
  37. this.dog = dog;
  38. }
  39. @Override
  40. public String toString() {
  41. return "Person{" +
  42. "name='" + name + '\'' +
  43. ", cat=" + cat +
  44. ", dog=" + dog +
  45. '}';
  46. }
  47. }

注意事项
(1)@Autowired注解和byType装载不同的是,去掉set方法依然可以完成自动装配,由于@Autowired注解实现原理较为复杂,暂时不做解释。
(2)@Autowired注解可以配合@Qualififier使用,@Qualififier注解是根据类型(byName)自动装配的,如:

@Autowired 
@Qualifier(value = "cat2") 
private Cat cat; 

@Autowired 
@Qualifier(value = "dog2") 
private Dog dog;

但是@Qualififier注解是不能够单独使用的。
(3)@Autowired(required=false) 表示的是它注解的属性可以为null,但required的默认值是true。

使用@Resource自动装配

@Resource注解中如有指定的name属性,先按name属性执行的值进行byName方式查找装配;其次再进行默认的byName方式(获取自动装配类中的set方法名,去掉set后将其首字母小写)进行装配;如果以上都不成功,则按byType的方式自动装配,如果还是不成功,则报异常。如:

@Resource(name = "cat")
private Cat cat;
@Resource
private Dog dog;