Spring Beans 自动装配

89 阅读7分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

使用了 IOC/DI 以后,对象与对象之间的关系是通过配置文件 ref 属性组织在一起,而不再是通过硬编码的方式耦合在一起了。但这样做有弊端:就是需要额外编写大量的配置文件。

需要注意的是,自动装配只适用于对象类型的属性,即通过 ref 属性注入的 <Bean> 与 <Bean> 之间的关系,而不适用于简单类型,就是基本类型和 String 类型。

自动装配模式

使用基于 XML 的配置元数据时,可以使用 <bean /> 元素的 autowire 属性为 bean 定义指定 autowire 模式。autowiring 功能有四种模式,你可以为每个 bean 指定 autowiring,从而可以选择要 autowiring 的对象。以下表中介绍了四种装配模式:

autowire 属性值自动装配方式
no(默认)不使用自动装配。必须引用由 ref 属性来指定对象之间的依赖关系。大型项目中不建议设置为默认方式。
byName根据属性名自动装配。如果某一个 <bean> 的 id 值,与当前 <bean> 的某一个属性名相同,则自动注入;如果没有找到,则什么也不做。(本质是寻找属性名的 set 方法)
byType根据属性类型自动装配。如果某一个 <bean> 的类型,恰好与当前 <bean> 的某一个属性的类型相同,则主动注入;如果有多个 <bean> 的类型都与当前 <bean> 的某一个属性的类型相同,则 Spring 将无法决定注入哪一个 <bean>,就会抛出一个异常;如果没有找到,则什么也不做。
constructor根据构造器自动装配。与 byType 类似,区别是它需要使用构造方法。如果 Spring 没有找到与构造方法参数列表一致的 <bean>,则会抛出异常。

接下来我们把环境先搭建好,本实验中主要需要大家学会如何进行自动装配的配置。

搭建环境参考前面一个文章 关于Spring的小知识和第一个spring项目的创建 - 掘金 (juejin.cn)

然后我们在dao,resourcees里面添加对应Java和xml文件,最后在test里面书写测试方法

image.png

ADAO相关代码

image.png

image.png

BDAO相关代码

image.png

image.png

User代码

package com.yamiya.pojo;

import java.util.Date;

public class Users {
    private Integer userid;
    private String username;
    private String usertype;
    private Date hiredate;

    /**
     * 无参构造器
     */
    public Users(){

    }
    /**
     * 带参数构造器
     * @param userid 用户编号
     * @param username 用户名
     * @param usertype 用户类型
     */
    public Users(Integer userid, String username, String usertype){
        this.userid = userid;
        this.username = username;
        this.usertype = usertype;
    }

    public void setUserid(Integer userid) {
        this.userid = userid;
    }
    public Integer getUserid() {
        return userid;
    }

    public void setUsername(String username) {
        this.username = username;
    }
    public String getUsername() {
        return username;
    }

    public void setUsertype(String usertype) {
        this.usertype = usertype;
    }
    public String getUsertype() {
        return usertype;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }
    public Date getHiredate() {
        return hiredate;
    }

    @Override
    public String toString() {
        return super.getClass().getName() + "[userid = " +userid+", username = "+username+", usertype = "+ usertype + "]";
    }
}

UserService代码

package com.yamiya.service;

import com.yamiya.dao.IUserADAO;
import com.yamiya.dao.IUserBDAO;
import com.yamiya.pojo.Users;

public class UserService {

    private IUserADAO userdaoa;
    private IUserBDAO userdaob;
    private Users user;

    public UserService(){

    }

    public UserService(IUserADAO userdaoa, IUserBDAO userdaob, Users user) {
        this.userdaoa = userdaoa;
        this.userdaob = userdaob;
        this.user = user;
    }

    public void getUsers(){
        System.out.println(user);
        userdaob.updateUser(user);
        userdaoa.queryUsers();
    }

    public IUserADAO getUserdaoa() {
        return userdaoa;
    }

    public void setUserdaoa(IUserADAO userdaoa) {
        this.userdaoa = userdaoa;
    }

    public IUserBDAO getUserdaob() {
        return userdaob;
    }

    public void setUserdaob(IUserBDAO userdaob) {
        this.userdaob = userdaob;
    }

    public Users getUser() {
        return user;
    }

    public void setUser(Users user) {
        this.user = user;
    }




}

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.xsd">


</beans>

到这里环境完成,下面开始装配

根据属性名自动装配

这种模式需要指定属性名的自动装配。需要在 Spring 容器中,也就是配置文件中对 bean 元素中的 autowire 属性设置为 byName。然后容器将 bean 的属性与配置文件中定义为相同名称的 bean 进行匹配和连接。如果找到匹配项,它将注入这些 bean,否则,它将抛出异常。

我们先来分析一下提供给大家的代码:

image.png

image.png

提供给大家两个接口 IUserADAO 和 IUserBDAO ,分别创建查询所有用户信息和更新用户信息的方法,在实现类 UserADAOImpl 和 UserBDAOImpl 中进行方法的实现,方法中的内容比较简单。 这个 UserService 类用来调用之前所说的接口中的方法,所以需要在该类中注入 2 个接口和 1 个数据 Bean 的实例,如果接口实例没有注入的话,那么在 getUsers() 方法里就无法调用接口中方法,还会抛出空指针异常。

以上所讲的这些代码需要清楚这些提供的类和接口是干什么用的。

接下来需要采用根据属性名自动装配模式,将接口 IUserADAO 和 IUserBDAO 以及类 Users 的对象实例注入到类 UserService 中。

1.修改springAutowireByName.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.xsd">

        <bean id="user" class="com.yamiya.pojo.Users">
                <property name="userid" value="2020606"/>
                <property name="username" value="King" />
                <property name="usertype" value="VVVip会员" />
        </bean>

        <bean id="userdaoa" class="com.yamiya.dao.UserADAOImpl"></bean>

        <bean id="userdaob" class="com.yamiya.dao.UserBDAOImpl"></bean>

        <bean id="userservice" class="com.yamiya.service.UserService" autowire="byName" />

</beans>

主要使用的是 <bean> 元素中的属性 autowire,采用的是 autowire="byName",通过名字进行自动注入操作。

需要注意:id 的属性值必须和 UserService 类中的属性名保持一致,否则无法通过名字进行查找匹配。 2. 修改测试类 TestAutowire 添加 testAutowireByName() 测试方法进行测试:

package com.yamiya;

import com.yamiya.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAutowire {
    @Test
    public  void testAutowireByName(){

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springAutowireByName.xml");
        UserService us = context.getBean("userservice", UserService.class);
us.getUser();
context.close();

    }
}

根据属性类型自动装配

这种模式需要根据属性类型自动装配。需要在 Spring 容器中,也就是配置文件中对 bean 元素中的 autowire 属性设置为 byType。然后容器将 bean 的类型与配置文件中定义的 bean 的类型进行匹配和连接。如果找到匹配项,它将注入这些 bean,否则,它将抛出异常。

同样我们接下来需要采用根据属性类型自动装配模式,将接口 IUserADAO 和 IUserBDAO 以及类 Users 的对象实例注入到类 UserService 中。

  1. 修改 springAutowireByType.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.xsd">

    <bean class="com.yamiya.pojo.Users">
        <property name="userid" value="2000125"/>
        <property name="username" value="Demi" />
        <property name="usertype" value="超级会员" />
    </bean>

    <bean class="com.yamiya.dao.UserADAOImpl"></bean>

    <bean class="com.yamiya.dao.UserBDAOImpl"></bean>

    <bean id="userservice" class="com.yamiya.service.UserService" autowire="byType" />
</beans>

主要使用的是 <bean> 元素中的属性 autowire,采用的是 autowire="byType",通过对象类型进行自动注入操作。

需要注意:配置的 bean 中 id 属性可以省略,但配置文件中提供的 bean 的类型必须和 UserService 类中的属性类型保持一致,否则无法通过类型进行查找匹配。

  1. 修改测试类 TestAutowire 添加 testAutowireByType() 测试方法进行测试:
@Test
public void testAutowireByType(){
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springAutowireByType.xml");
    UserService us = context.getBean("userservice", UserService.class);
    us.getUsers();
    context.close();
}

根据构造器自动装配

这种模式与 byType 非常相似,但它应用于构造器参数。Spring 容器中 bean 的 autowire 属性设置为 constructor。然后,它尝试把它的构造函数的参数与配置文件中 bean 的类型进行匹配和连接。如果找到匹配,它会注入这些 bean,否则它会抛出异常。

我们接下来需要采用根据构造器自动装配模式,将接口 IUserADAO 和 IUserBDAO 以及类 Users 的对象实例通过 UserService 类中的构造器进行注入。

  1. 修改 springAutowireConstructor.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.xsd">
    <bean class="com.yamiya.pojo.Users">
        <property name="userid" value="2000128"/>
        <property name="username" value="Tina" />
        <property name="usertype" value="普通会员" />
    </bean>

    <bean class="com.yamiya.dao.UserADAOImpl"></bean>

    <bean class="com.yamiya.dao.UserBDAOImpl"></bean>

    <bean id="userservice" class="com.yamiya.service.UserService" autowire="constructor" />


</beans>

主要使用的是 <bean> 元素中的属性 autowire,采用的是 autowire="constructor",通过对象类型进行自动注入操作。

需要注意:配置的 bean 中 id 属性可以省略,但是在 UserService 类中必须存在带参数的构造器,构造器参数类型还需要和配置文件中的 bean 的类型一致。

  1. 修改测试类 TestAutowire 添加 testAutowireConstructor() 测试方法进行测试:
@Test
public void testAutowireConstructor(){
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springAutowireConstructor.xml");
    UserService us = context.getBean("userservice", UserService.class);
    us.getUsers();
    context.close();
}

到这里,三种方法已经完成,大家可以去试试哦

总结

这篇讲述了 Bean 自动装配的 3 种模式,一般主要使用的前 2 种 byName 和 byType 。

自动装配的优点:

  1. 自动装配可以显著减少指定属性或构造器参数。
  2. 自动装配可以随着对象的发展更新配置,在开发期间尤其有用,也不需要在代码库变得更稳定时切换到显示装配。

自动装配的局限性和缺点:

  1. property 和 constructor-arg 设置中的显式依赖项始终会覆盖自动装配。
  2. 自动装配不如显式装配精确。

图片描述