b05-2 Spring依赖注入(精通SPring 4.x)

本篇内容:
  • 1、属性注入
  • 2、构造方法注入(注入方式:参数名称,参数类型,参数索引,反射注入)
  • 3、循环注入
  • 4、工厂方法注入(普通工厂类,静态工厂类)
  • 5、注入方式选择

一、属性注入

  • 属性注入是指通过setXxx()注入bean的属性值或依赖对象。属性注入方式比较灵活,属性注入为采用方式

1.1、属性注入实例

  • 属性注入要求Bean提供一个默认构造函数,并给需要注入的属性提供sett方法
    Spring先调用Bean的默认构造方法实例化Bean对象,在通过反射的方式调用setter方法注入属性
1.1.1、创建java实体类
public class SetterObject {
​
    private String color;
    private int size;
​
    public void getData() {
        System.out.println("SetterObject{" +
                "color='" + color + '\'' +
                ", size=" + size +
                '}');
    }
​
    public void setColor(String color) {
        this.color = color;
    }
​
    public void setSize(int size) {
        this.size = size;
    }
}
1.1.2、配置文件
<?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="setter" class="com.demo.setter.SetterObject">
        <property name="color" value="红色"/>
        <property name="size" value="4188"/>
    </bean></beans>
说明:
property name=”color” value=”红色”
  • property:为属性注入标识
  • name:为属性的名称
  • value:为属性对应的值
注意:
  • Spring只会检查Bean中是否对应的方法,不会检查是否有对应的属性采用变量。
1.1.3、测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:src/main/resources/setter.xml"})
public class SetterObjectTest {@Autowired
    private SetterObject setter;
​
    @Test
    public void getBean() {
        setter.getData();
    }
​
}

1.2、java中属性命名规范

  • Spring配置文件中的元素所指定的属性名和Bean实现类的Setter方法满足Java命名规范:xxx属性对应的setXxx()

二、构造函数注入

  • 保证了一些必要属性在Bean实例化的时候得到设置。
  • 使用构造函数方式注入Bean必须提供带参的构造函数
定义java实体对象
public class ConstructorObject {
​
    private String desc;
    private String title;
    private int size;
​
    public ConstructorObject(String desc, int size) {
        this.desc = desc;
        this.size = size;
    }
​
    public ConstructorObject(String desc, String title, int size) {
        this.desc = desc;
        this.title = title;
        this.size = size;
    }
​
    public void getData() {
        System.out.println("ConstructorObject{" +
                "desc='" + desc + '\'' +
                ", title='" + title + '\'' +
                ", size=" + size +
                '}');
    }
}

2.1、按照参数名称方式注入

  • 使用constructor-arg元中的name属性,name对应为构造函数中的参数名称,value为参数名称对应的值
配置文件
    <!--按照参数名称方式-->
    <bean id="constructorObject_name" class="com.demo.constructor.ConstructorObject">
        <constructor-arg name="desc" value="test-desc-data"/>
        <constructor-arg name="title" value="test-title-data"/>
        <constructor-arg name="size" value="4188"/>
    </bean>
    name="desc":对应的参数名称
    value="test-title-data":对应的参数值

2.2、按照参数类型注入

  • 使用constructor-arg元中的type属性,type对应为构造函数中的参数类型,value为参数名称对应的值
配置文件
    <!--按照参数类型-->
    <bean id="constructorObject_type" class="com.demo.constructor.ConstructorObject">
        <constructor-arg type="java.lang.String" value="test-desc-type"/>
        <constructor-arg type="java.lang.String" value="test-title-type"/>
        <constructor-arg type="int" value="4188"/>
    </bean>
    type="int":对应的参数类型
    value="4188":对应的参数值

2.3、按照参数索引注入

  • 安装构造函数中参数索引值匹配,索引其实值为0.
    <!--按照参数索引-->
    <bean id="constructorObject_index" class="com.demo.constructor.ConstructorObject">
        <constructor-arg index="0" value="test-desc-index"/>
        <constructor-arg index="1" value="test-title-index"/>
        <constructor-arg index="2" value="4188"/>
    </bean>
说明
  • index=”0”:对应的索引值,代表为第0个参数
  • value=”test-desc-index”:参数对应的值

2.4、按照反射方式注入

  • 当构造函数中参数的类型是不相同的,可以通过java反射方式获取参数对应的类型
1、构造函数
    public ConstructorObject(String desc, int size) {
        this.desc = desc;
        this.size = size;
    }
2、配置
    <!--按照反射方式-->
    <bean id="constructorObject_reflection" class="com.demo.constructor.ConstructorObject">
        <constructor-arg value="test-desc-reflection"/>
        <constructor-arg value="4188"/>
    </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.xsd"><!--按照参数名称方式-->
    <bean id="constructorObject_name" class="com.demo.constructor.ConstructorObject">
        <constructor-arg name="desc" value="test-desc-data"/>
        <constructor-arg name="title" value="test-title-data"/>
        <constructor-arg name="size" value="4188"/>
    </bean><!--按照参数类型-->
    <bean id="constructorObject_type" class="com.demo.constructor.ConstructorObject">
        <constructor-arg type="java.lang.String" value="test-desc-type"/>
        <constructor-arg type="java.lang.String" value="test-title-type"/>
        <constructor-arg type="int" value="4188"/>
    </bean><!--按照参数索引-->
    <bean id="constructorObject_index" class="com.demo.constructor.ConstructorObject">
        <constructor-arg index="0" value="test-desc-index"/>
        <constructor-arg index="1" value="test-title-index"/>
        <constructor-arg index="2" value="4188"/>
    </bean><!--按照反射方式-->
    <bean id="constructorObject_reflection" class="com.demo.constructor.ConstructorObject">
        <constructor-arg value="test-desc-reflection"/>
        <constructor-arg value="4188"/>
    </bean>
​
​
</beans>
完整测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:src/main/resources/constructor.xml"})
public class ConstructorObjectTest {@Autowired
    public ConstructorObject constructorObject_name;
    @Autowired
    public ConstructorObject constructorObject_type;
    @Autowired
    public ConstructorObject constructorObject_index;
    @Autowired
    public ConstructorObject constructorObject_reflection;
​
    @Test
    public void getBeanByName() {
        constructorObject_name.getData();
    }
​
    @Test
    public void getBeanByType() {
        constructorObject_type.getData();
    }
​
    @Test
    public void getBeanByIndex() {
        constructorObject_index.getData();
    }
​
    @Test
    public void getBeanByReflection() {
        constructorObject_reflection.getData();
    }
​
}

三、循环注入

  • Spring容器对构造方法配置Bean进行实例化有个前提,Bean构造函数中的参数必须准完成。由于这个限制如果两个Bean都采用构造函数的方式注入就会出现类似线程死锁的循环依赖问题
1、java实体对象
public class ForeObjectA {
​
    private String desc;
    private ForeObjectB foreObjectB;
​
    public ForeObjectA(String desc, ForeObjectB foreObjectB) {
        this.desc = desc;
        this.foreObjectB = foreObjectB;
    }
​
    public void getData() {
        System.out.println("ForeObjectA{" +
                "desc='" + desc + '\'' +
                ", foreObjectB=" + foreObjectB +
                '}');
    }
}
2、java实体对象
public class ForeObjectB {
​
    private String title;
    private ForeObjectA foreObjectA;
​
    public ForeObjectB(String title, ForeObjectA foreObjectA) {
        this.title = title;
        this.foreObjectA = foreObjectA;
    }
​
    public void getData() {
        System.out.println( "ForeObjectB{" +
                "title='" + title + '\'' +
                ", foreObjectA=" + foreObjectA +
                '}');
    }
}
3、配置文件
<?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="foreA" class="com.demo.fore.ForeObjectA">
        <constructor-arg name="desc" value="test-desc"/>
        <constructor-arg name="foreObjectB" ref="foreB"/>
    </bean><bean id="foreB" class="com.demo.fore.ForeObjectB">
        <constructor-arg name="title" value="test-title"/>
        <constructor-arg name="foreObjectA" ref="foreA"/>
    </bean></beans>
4、测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:src/main/resources/fore.xml"})
public class ForeObjectTest {@Autowired
    private ForeObjectB foreB;
​
    @Autowired
    private ForeObjectA foreA;
​
    @Test
    public void getBean() {
        foreA.getData();
        foreB.getData();
    }
}
5、解决方案:
  • 将两个实体的构造方法注入改成属性注入

四、工厂方法注入

  • 采用工厂类方式注入java对象需要手动创建工厂类
java实体对象
public class CarObject {
​
    private String color;
    private String title;
​
    public String getColor() {
        return color;
    }
​
    public void setColor(String color) {
        this.color = color;
    }
​
    public String getTitle() {
        return title;
    }
​
    public void setTitle(String title) {
        this.title = title;
    }
​
    @Override
    public String toString() {
        return "CarObject{" +
                "color='" + color + '\'' +
                ", title='" + title + '\'' +
                '}';
    }
}

4.1、非静态工厂方法注入

  • 在Java中非静态工厂类必须要实例化工厂类才能调用工厂类方法
  • 工厂类负责创建一个或多个目标类实例,工厂类方法一般以接口或抽象类变量的形式返回目标类
  • 工厂类对外屏蔽了目标的实例化步骤,调用者不需知道具体的目标类
    public CarObject createCar() {
        CarObject carObject = new CarObject();
        carObject.setColor("银灰色");
        carObject.setTitle("雷克萨斯");
        return carObject;
    }
配置文件
    <bean id="factory" class="com.demo.factory.CarFactory"/>
    <bean id="car" factory-method="createCar" factory-bean="factory"/>
说明:
    id="factory":定义工厂类
    factory-method="createCar":指定创建实体类(id="car")对应的工厂方法
    factory-bean="factory":指定创建实体类(id="car") 对应的工厂类   

4.2、静态工厂

  • 静态工厂类在使用时不需要创建工厂类对象就可以直接调用工厂类中的方法,在Spring中也不需要的定义工厂类Bean
    public static CarObject newCar() {
        CarObject carObject = new CarObject();
        carObject.setColor("银灰色");
        carObject.setTitle("雷克萨斯");
        return carObject;
    }
配置文件
    <!--静态工厂类:不需要创建工厂类对象-->
    <bean id="newCar" class="com.demo.factory.CarFactory" factory-method="newCar"/>
说明:
        class="com.demo.factory.CarFactory":对应的静态工厂类
        factory-method="newCar":工厂类对应的静态方法

五、注入方式选择

  • Spring有3种方式选择,具体注入方式选择并没有统一标准

1、使用构造函数方式的优点

  • 1、保证重要的属性在Bean实例化时被设置好。
  • 2、不需要为每个属性提供setter方法,减少方法个数,避免外部错误调用

2、构造函数方式的缺点

  • 1、属性过多,构造方法就变得很多,可读性差
  • 2、不够灵活,可选属性也需要提供参数
  • 3、多个构造方法存在歧义
  • 4、构造方法不利于类的扩展与继承,子类需要引用父类的构造方法
  • 5、构造方法存在循环注入问题
代码地址
https://github.com/brusion/brusion-code/tree/master/demo-java/03%20-%20demo%20-%20spring/spring-study-4x/01-ioc/01-ioc-type
Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值