Spring Bean自动装配

举报
CoderX 发表于 2022/04/16 17:12:44 2022/04/16
【摘要】 装配 Spring在Bean与Bean之间建立依赖关系的行为称为"装配"。 Spring的的IoC容器不能独自完成装配工作,需要主动将Bean放进入,并告诉它Bean与Bean之间的依赖关系,他才能按照要求完成装配。 XML配置中通过<constructor-arg>和<property>中的ref属性,是手动维护Bean与Bean之间的依赖关系。例如: 一个部门(Dept)可以有多个员工(...

装配

Spring在Bean与Bean之间建立依赖关系的行为称为"装配"。

Spring的的IoC容器不能独自完成装配工作,需要主动将Bean放进入,并告诉它Bean与Bean之间的依赖关系,他才能按照要求完成装配。

XML配置中通过<constructor-arg><property>中的ref属性,是手动维护Bean与Bean之间的依赖关系。

例如: 一个部门(Dept)可以有多个员工(Employee),而一个员工只可能属于某一个部门,这种关联关系定义在 XML 配置的 Bean 定义中。

 beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
     <!--部门 Dept 的 Bean 定义-->
     <bean id="dept" class="net.biancheng.c.Dept"/>
     <!--雇员 Employee 的 Bean 定义-->
     <bean id="employee" class="net.biancheng.c.Employee"/>
         <!--通过 <property> 元素维护 Employee 和 Dept 的依赖关系-->
         <property name="dept" ref="dept"/>
     </bean>
 </beans>

缺点: 随着应用的不断发展,容器中包含的 Bean 会越来越多,Bean 和 Bean 之间的依赖关系也越来越复杂,这就使得我们所编写的 XML 配置也越来越复杂,越来越繁琐。

解决方案: 过于复杂的 XML 配置不但可读性差,而且编写起来极易出错,严重的降低了开发人员的开发效率。为了解决这一问题,Spring 框架还为我们提供了“自动装配”功能。


Spring自动装配

Spring的自动装配功能可以让Spring容器依据某种自动装配规则,为指定的Bean从应用上下文(ApplicationContext容器)中查找他所依赖的Bean,并自动建立Bean之间的依赖关系。

使用自动装配,需要对Spring XML配置文件中<bean>元素的autowire属性进行设置。

 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
     <!--部门 Dept 的 Bean 定义-->
     <bean id="dept" class="net.biancheng.c.Dept"></bean>
    
     <!--雇员 Employee 的 Bean 定义,通过 autowire 属性设置自动装配的规则-->
     <bean id="employee" class="net.biancheng.c.Employee" autowire="byName">
     </bean>
 </beans>

自动装配规则

Spring提供五种自动装配规则,分别与autowire属性的5个取值对应:

属性值 说明
byName 按名称自动装配。 Spring 会根据的 Java 类中对象属性的名称,在整个应用的上下文 ApplicationContext(IoC 容器)中查找。若某个 Bean 的 id 或 name 属性值与这个对象属性的名称相同,则获取这个 Bean,并与当前的 Java 类 Bean 建立关联关系。
byType 按类型自动装配。 Spring 会根据 Java 类中的对象属性的类型,在整个应用的上下文 ApplicationContext(IoC 容器)中查找。若某个 Bean 的 class 属性值与这个对象属性的类型相匹配,则获取这个 Bean,并与当前的 Java 类的 Bean 建立关联关系。
constructor 与 byType 模式相似,不同之处在与它应用于构造器参数(依赖项),如果在容器中没有找到与构造器参数类型一致的 Bean,那么将抛出异常。 其实就是根据构造器参数的数据类型,进行 byType 模式的自动装配。
default 表示默认采用上一级元素 <beans> 设置的自动装配规则(default-autowire)进行装配。
no 默认值,表示不使用自动装配,Bean 的依赖关系必须通过 <constructor-arg><property> 元素的 ref 属性来定义。

代码示例:

  1. 部门类(员工类的依赖项)

     package org.autowireDemo;
     ​
     /**
      * 部门类  employee类的依赖
      */
     public class Dept {
         //部门编号
         private String deptNo;
         //部门名称
         private String deptName;
     ​
         public Dept() {
             System.out.println("正在执行 Dept 的无参构造方法>>>>");
         }
         public Dept(String deptNo, String deptName) {
             System.out.println("正在执行 Dept 的有参构造方法>>>>");
             this.deptNo = deptNo;
             this.deptName = deptName;
         }
         public void setDeptNo(String deptNo) {
             System.out.println("正在执行 Dept 的 setDeptNo 方法>>>>");
             this.deptNo = deptNo;
         }
         public void setDeptName(String deptName) {
             System.out.println("正在执行 Dept 的 setDeptName 方法>>>>");
             this.deptName = deptName;
         }
         public String getDeptNo() {
             return deptNo;
         }
         public String getDeptName() {
             return deptName;
         }
         @Override
         public String toString() {
             return "Dept{" +
                     "deptNo='" + deptNo + '\'' +
                     ", deptName='" + deptName + '\'' +
                     '}';
         }
     ​
     ​
     ​
     }
     ​


  2. 员工类

     package org.autowireDemo;
     ​
     /**
      * 员工类
      */
     public class Employee {
         //员工编号
         private String empNo;
         //员工姓名
         private String empName;
         //部门信息
         private Dept dept;
         public Employee() {
             System.out.println("正在执行 Employee 的无参构造方法>>>>");
         }
         public Employee(String empNo, String empName, Dept dept) {
             System.out.println("正在执行 Employee 的有参构造方法>>>>");
             this.empNo = empNo;
             this.empName = empName;
             this.dept = dept;
         }
         public void setEmpNo(String empNo) {
             System.out.println("正在执行 Employee 的 setEmpNo 方法>>>>");
             this.empNo = empNo;
         }
         public void setEmpName(String empName) {
             System.out.println("正在执行 Employee 的 setEmpName 方法>>>>");
             this.empName = empName;
         }
         public void setDept(Dept dept) {
             System.out.println("正在执行 Employee 的 setDept 方法>>>>");
             this.dept = dept;
         }
         public Dept getDept() {
             return dept;
         }
         public String getEmpNo() {
             return empNo;
         }
         public String getEmpName() {
             return empName;
         }
         @Override
         public String toString() {
             return "Employee{" +
                     "empNo='" + empNo + '\'' +
                     ", empName='" + empName + '\'' +
                     ", dept=" + dept +
                     '}';
         }
     }
     ​


  3. main方法

     package org.autowireDemo;
     ​
     import org.springframework.context.ApplicationContext;
     import org.springframework.context.support.ClassPathXmlApplicationContext;
     ​
     public class MainApp {
         public static void main(String[] args) {
             ApplicationContext context = new ClassPathXmlApplicationContext("autowireBeans.xml");
             Employee employee = context.getBean("employee", Employee.class);
             System.out.println(employee);
         }
     }


1.不使用自动装配(autowire="no")

不使用自动装配必须通过 <bean> 元素的 <constructor-arg><property> 元素的 ref 属性维护 Bean 的依赖关系。

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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" default-autowire="constructor">
 ​
     <bean id="dept" class="org.autowireDemo.Dept">
         <property name="deptNo" value="1"/>
         <property name="deptName" value="技术部"/>
     </bean>
 ​
 ​
     <bean id="employee" class="org.autowireDemo.Employee" >
         <property name="empNo" value="002"/>
         <property name="empName" value="张三"/>
         <property name="dept" ref="dept"/>
     </bean>
 ​
 ​
 </beans>

运行结果:

 正在执行 Dept 的无参构造方法>>>>
 正在执行 Dept 的 setDeptNo 方法>>>>
 正在执行 Dept 的 setDeptName 方法>>>>
 ​
 正在执行 Employee 的无参构造方法>>>>
 正在执行 Employee 的 setEmpNo 方法>>>>
 正在执行 Employee 的 setEmpName 方法>>>>
 正在执行 Employee 的 setDept 方法>>>>
 Employee{empNo='002', empName='张三', dept=Dept{deptNo='1', deptName='技术部'}}

2.按名称自动装配(autowire="byName")

autowire="byName" 表示按属性名称自动装配,XML 文件中 Bean 的 id 或 name 必须与类中的属性名称相同。

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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 ​
     <bean id="dept" class="org.autowireDemo.Dept">
         <property name="deptNo" value="1"/>
         <property name="deptName" value="技术部"/>
     </bean>
 ​
 ​
     <bean id="employee" class="org.autowireDemo.Employee" autowire="byName">
         <property name="empNo" value="002"/>
         <property name="empName" value="张三"/>
     </bean>
 ​
 ​
 </beans>

运行结果:

 正在执行 Dept 的无参构造方法>>>>
 正在执行 Dept 的 setDeptNo 方法>>>>
 正在执行 Dept 的 setDeptName 方法>>>>
 ​
 正在执行 Employee 的无参构造方法>>>>
 正在执行 Employee 的 setEmpNo 方法>>>>
 正在执行 Employee 的 setEmpName 方法>>>>
 正在执行 Employee 的 setDept 方法>>>>
 Employee{empNo='002', empName='张三', dept=Dept{deptNo='1', deptName='技术部'}}

如果将部门Bean的id修改为dept2,则输出结果中 dept=null

3.按类型自动装配(autowire=“byType”)

autowire="byType" 表示按类中对象属性数据类型进行自动装配。即使 XML 文件中 Bean 的 id 或 name 与类中的属性名不同,只要 Bean 的 class 属性值与类中的对象属性的类型相同,就可以完成自动装配。

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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 ​
     <bean id="dept1" class="org.autowireDemo.Dept">
         <property name="deptNo" value="1"/>
         <property name="deptName" value="技术部"/>
     </bean>
 ​
 ​
     <bean id="employee" class="org.autowireDemo.Employee" autowire="byType">
         <property name="empNo" value="002"/>
         <property name="empName" value="张三"/>
     </bean>
 ​
 ​
 </beans>

运行结果:

 正在执行 Dept 的无参构造方法>>>>
 正在执行 Dept 的 setDeptNo 方法>>>>
 正在执行 Dept 的 setDeptName 方法>>>>
 22:38:33.198 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'employee'
 正在执行 Employee 的无参构造方法>>>>
 正在执行 Employee 的 setEmpNo 方法>>>>
 正在执行 Employee 的 setEmpName 方法>>>>
 正在执行 Employee 的 setDept 方法>>>>
 Employee{empNo='002', empName='张三', dept=Dept{deptNo='1', deptName='技术部'}}

如果同时存在多个相同类型的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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 ​
     <bean id="dept1" class="org.autowireDemo.Dept">
         <property name="deptNo" value="1"/>
         <property name="deptName" value="技术部"/>
     </bean>
     <bean id="dept2" class="org.autowireDemo.Dept">
         <property name="deptNo" value="2"/>
         <property name="deptName" value="开发部"/>
     </bean>
 ​
 ​
     <bean id="employee" class="org.autowireDemo.Employee" autowire="byType">
         <property name="empNo" value="002"/>
         <property name="empName" value="张三"/>
     </bean>
 ​
 ​
 </beans>
 Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'employee' defined in class path resource [autowireBeans.xml]: Unsatisfied dependency expressed through bean property 'dept'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.autowireDemo.Dept' available: expected single matching bean but found 2: dept1,dept2

4.构造函数自动装配(autowire="constructor")

autowire="constructor" 表示按照 Java 类中构造函数进行自动装配。

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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 ​
    <!-- <bean id="dept1" class="org.autowireDemo.Dept">
         <property name="deptNo" value="1"/>
         <property name="deptName" value="技术部"/>
     </bean>
 ​
 ​
 ​
     <bean id="employee" class="org.autowireDemo.Employee" autowire="constructor">
         <property name="empNo" value="001"/>
         <property name="empName" value="张三"/>
     </bean>-->
     <bean id="dept1" class="org.autowireDemo.Dept">
         <constructor-arg name="deptNo" value="1"/>
         <constructor-arg name="deptName" value="技术部"/>
     </bean>
 ​
     <bean id="employee" class="org.autowireDemo.Employee" autowire="constructor">
         <constructor-arg name="empNo" value="001"/>
         <constructor-arg name="empName" value="张三"/>
     </bean>
 ​
 ​
 </beans>
 ​

运行结果:

 正在执行 Dept 的有参构造方法>>>>
 正在执行 Employee 的有参构造方法>>>>
 Employee{empNo='001', empName='张三', dept=Dept{deptNo='1', deptName='技术部'}}

5.默认的自动装配模式(autowire="default")

默认采用上一级标签 <beans> 设置的自动装配规则(default-autowire)进行装配,Beans.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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" default-autowire="byType">
 ​
     <bean id="dept1" class="org.autowireDemo.Dept">
         <property name="deptNo" value="1"/>
         <property name="deptName" value="技术部"/>
     </bean>
     
     <bean id="employee" class="org.autowireDemo.Employee">
         <property name="empNo" value="001"/>
         <property name="empName" value="张三"/>
     </bean>
    
 </beans>
 ​

输出结果

 正在执行 Dept 的无参构造方法>>>>
 正在执行 Dept 的 setDeptNo 方法>>>>
 正在执行 Dept 的 setDeptName 方法>>>>
 ​
 正在执行 Employee 的无参构造方法>>>>
 正在执行 Employee 的 setEmpNo 方法>>>>
 正在执行 Employee 的 setEmpName 方法>>>>
 正在执行 Employee 的 setDept 方法>>>>
 Employee{empNo='001', empName='张三', dept=Dept{deptNo='1', deptName='技术部'}}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。