网站首页 > 技术文章 正文
一.属性注入
首先来了解一下定义:属性注入是指通过 setXxx()方法注入Bean的属性或依赖对象。
为什么要使用: 因为属性注入方式具有可选择性和高灵活性的特点,所以属性注入方式是实际应用中最常采用的注入方式。
来来来,直接上代码!
造个Car实体类
Car类中定义了3个属性,并分别提供了对应的Setter方法
package com.vtstar.entity; /** * @ClassName Car * @Description TODO * @Author XiaoWu * @Date 2018/9/6 9:53 * @Version 1.0 **/ public class Car { private int maxSpeed; public String brand; private double price; private Boss boss; public Car() { } public Car(double price, Boss boss) { System.out.println("I'm the Car's construct two " + price + " boss " + boss.getName()); this.price = price; this.boss = boss; } public Car(int maxSpeed, String brand, double price) { System.out.println("车的时速是" + maxSpeed + " 品牌为:" + brand + " 价格为:" + price); this.maxSpeed = maxSpeed; this.brand = brand; this.price = price; } public int getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(int maxSpeed) { System.out.println("The maximum speed is " + maxSpeed); this.maxSpeed = maxSpeed; } public String getBrand() { return brand; } public void setBrand(String brand) { System.out.println("It is a " + brand + " Car"); this.brand = brand; } public double getPrice() { return price; } public void setPrice(double price) { System.out.println("The price of this car " + price); this.price = price; } }
在Spring配置文件中对Car进行属性注入的配置桥段
<!--&&&&&&&&&&&&&&&&&&&&&&&&& setter属性方式注入 &&&&&&&&&&&&&&&&&&&&&& --> <bean id="car" class="com.vtstar.entity.Car"> <property name="brand" value="保时捷 k3"/> <property name="maxSpeed" value="100"/> <property name="price" value="30.1"/> </bean>
上面的代码配置的一个Bean,class属性对应前面建好的实体Car,<property/>标签对应Bean中的每一个属性,name为属性的名称,value为参数值,在Bean中拥有与其对应的Setter方法,maxSpeed对应setMaxSpeed(),price对应setPrice();
运行一下 Tomcat,Spring容器会在Tomcat启动的时候创建;
二.构造函数注入
构造函数注入是除属性注入外的另外一种注入方式,它保证了一些必要的属性在Bean实例化时就得到设置,确保在Bean实例化后就可以使用。
值得一提的是构造函数注入又分为多种方式,我们慢慢来看。
1. 按类型匹配入参
如果任何可用的Car对象都需要使用到brand,maxSpeed,price的值,那使用Setter注入方式,则只能人为的在配置时提供保证而无法再语法上提供保证,那这个时候使用构造函数注入就能满足这一个要求,使用构造函数注入的前提是要保证Bean中有提供带参的构造函数。
<!--1.根据参数类型注入--> <bean id="car1" class="com.vtstar.entity.Car"> <constructor-arg type="int" value="300"/> <constructor-arg type="java.lang.String" value="红旗"/> <constructor-arg type="double" value="20000000.9"/> </bean>
在<constructor/>元素中有一个type元素,它为Spring提供了判断配置项和构造函数入参对应关系的“信息”。
2. 按索引匹配入参
Java语言通过入参的类型及顺序区分不同的重载方法。如果构造函数中有两个类型相同的入参,那么使用第一种方式是行不通的,因为type无法确认对应的关系。这时我们就需要使用索引匹配入参的方式来进行确认。
为了更好的演示按索引匹配入参,将Car构造函数进行了修改
public Car(String brand, String corp, double price) { System.out.println("brand :" + brand + " corp :" + corp + " price :"+price); this.brand = brand; this.corp = corp; this.price = price; } <!--2.通过入参位置下标--> <bean id="car2" class="com.vtstar.entity.Car"> <constructor-arg index="0" value="400"/> <constructor-arg index="1" value="大众辉腾"/> <constructor-arg index="2" value="20000000"/> </bean>
因为brand和corp都是String类型,所以Spring无法确定type为String的<constructor-arg/>到底对应的是brand还是corp。但是这种按索引匹配入参的方式能够消除这种不确定性。
3. 联合使用类型和索引匹配入参
有时需要Type和index联合使用才能确定配置项和构造函数入参的对应关系,举个栗子
public Car(String brand, String corp, double price) { System.out.println("brand :" + brand + " corp :" + corp + " price :"+price); this.brand = brand; this.corp = corp; this.price = price; } public Car(String brand, String corp, int maxSpeed) { System.out.println("brand :" + brand + " corp :" + corp + " maxSpeed :"+maxSpeed); this.brand = brand; this.corp = corp; this.maxSpeed = maxSpeed; }
在这里,Car拥有两个重载的构造函数,它们都有两个相同类型的入参,按照index的方式针对这样的情况又难以满足了这时就需要联合使用<constructor-arg/>中的type和index了。
<!--3.通过参数类型和入参位置联合注入--> <bean id="car3" class="com.vtstar.entity.Car"> <constructor-arg index="0" type="java.lang.String" value="30000000.0"/> <constructor-arg index="1" type="java.lang.String" value="卡迪拉克"/> <constructor-arg index="2" type="int" value="400"/> </bean>
对于上图的代码清单如果只根据index来进行匹配入参,那么Spring无法确认第三个参数是price还是maxSpeed了,所以解决这种有歧义的冲突,请将type和index结合使用,对于因参数数目相同而类型不同引起的潜在配置歧义问题,Spring容器可以正确的启动且不会给出报错信息,他将随机采用一个匹配的构造函数实例化Bean,而被选择的构造函数可能并不是用户所期望的那个。因此,必须要特别谨慎,以避免潜在的错误。
4.通过自身类型反射入参
如果Bean的构造函数入参类型是可辨别的,什么是可辨别的入参类型呢?(非基础数据类型且入参类型各异)
我们再建一个Boss实体类,在Boss类中引用Car类
package com.vtstar.entity; import java.util.Date; /** * @ClassName Boss * @Description TODO * @Author XiaoWu * @Date 2018/9/6 11:22 * @Version 1.0 **/ public class Boss { private String name; private Car car; private Integer age; public Boss() { } public Boss(String name, Car car,Integer age) { System.out.println("The name of the boss " + name + " ,He has a " + car.getBrand()+" age is "+age); this.name = name; this.car = car; this.age = age; } public String getName() { return name; } public Car getCar() { return car; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
Spring配置Boss相关的Bean,由于name, car ,age入参都是可辨别的,所以无须在<constructor-arg/>中指定type和index。
<!--4.通过自身类型反射入参--> <bean id="boss" class="com.vtstar.entity.Boss"> <constructor-arg value="Tom"/> <constructor-arg ref="car1"/> <constructor-arg value="20"/> </bean>
但是为了避免潜在配置歧义引起的张冠李戴的情况,如果Bean存在多个构造函数,那么显式指定index和type属性是一种良好的配置习惯。
5.循环依赖问题
Spring容器对构造函数配置Bean进行实例化有一个前提,即Bean构造函数入参引用的对象必须已经准备就绪。由于这个机制,如果两个Bean都相互引用,都采用构造函数注入方式,就会发生类似于线程死锁的循环依赖问题。
<!--5.循环依赖注入--> <bean id="boss1" class="com.vtstar.entity.Boss"> <constructor-arg index="0" value="Tom"/> <constructor-arg index="1" ref="car4"/> <constructor-arg index="2" value="20"/> </bean> <bean id="car4" class="com.vtstar.entity.Car"> <constructor-arg index="0" value="232.9"/> <constructor-arg index="1" ref="boss1"/> </bean>
如何解决这种问题?将相互依赖的两个Bean中的其中一个Bean采用Setter注入的方式即可。
<!--5.循环依赖注入--> <bean id="boss1" class="com.vtstar.entity.Boss"> <constructor-arg index="0" value="Tom"/> <constructor-arg index="1" ref="car"/> </bean> <bean id="car" class="com.vtstar.entity.Car"> <property name="brand" value="保时捷 k3"/> <property name="maxSpeed" value="100"/> <property name="price" value="30.1"/> </bean>
构造函数注入方式:
优点:
1.构造函数可以保证一些重要的属性在bean实例化的时候就设置好,避免因为一些重要的属性没有提供而导致一个无用的Bean 实例情况
2.不需要为每个属性提供Setter方法,减少了类的方法个数
3.可以更好的封装类变量,不需要为每个属性提供Setter方法,避免外部错误的调用
缺点:
1.如果一个类属性太多,那么构造函数的参数将变成一个庞然大物,可读性较差
2.灵活性不强,在有些属性是可选的情况下,如果通过构造函数注入,也需要为可选的参数提供一个null值
3.如果有多个构造函数,则需要考虑配置文件和具体构造函数匹配歧义的问题,配置上相对复杂
4.构造函数不利于类的继承和拓展,因为子类需要引用父类复杂的构造函数
5.构造函数注入有时会造成循环依赖的问题
三. 工厂注入
既然需要一个工厂,那么我们需要创建一个CarFactory类
package com.vtstar.ioc; import com.vtstar.entity.Car; /** * @ClassName CarFactory * @Description TODO * @Author XiaoWu * @Date 2018/9/6 13:55 * @Version 1.0 **/ public class CarFactory { /* * @methodName createHongQiCar * @Description 创建红旗轿车制造工厂 * @Date 2018/9/6 13:58 * @Param [] * @return com.vtstar.entity.Car **/ public Car createHongQiCar(){ Car car = new Car(); car.setBrand("红旗H1"); System.out.println("这里是非静态工厂的创建..." + car.getBrand()); return car; } /* * @methodName createDaZhongCar * @Description 创建大众汽车制造工厂 * @Date 2018/9/6 14:02 * @Param [] * @return com.vtstar.entity.Car **/ public static Car createDaZhongCar(){ Car car = new Car(); car.setBrand("大众GoGoGo"); System.out.println("这里是静态工厂的创建..." + car.getBrand()); return car; } }
工厂注入方式分为 静态工厂和非静态工厂,相关Spring配置如下:
<!--非静态注入工厂方法--> <bean id="carFactory" class="com.vtstar.ioc.CarFactory"/> <bean id="car5" factory-bean="carFactory" factory-method="createHongQiCar"/> <!--静态注入工厂方法--> <bean id="car6" class="com.vtstar.ioc.CarFactory" factory-method="createDaZhongCar"/>
文章转自https://blog.csdn.net/qq_37464248/article/details/82463889
猜你喜欢
- 2024-10-18 MyBatisPlus又在搞事了!发布神器,一个依赖轻松搞定权限问题
- 2024-10-18 史上硬核!Jar 包依赖冲突排查思路和解决方法
- 2024-10-18 小白都能看懂的 Spring 源码揭秘之依赖注入(DI)源码分析
- 2024-10-18 Spring-bean的循环依赖以及解决方式
- 2024-10-18 Maven技术方案最全手册 maven详细教程
- 2024-10-18 JAVA编程规范之二方库依赖 java方法库
- 2024-10-18 Spring依赖注入原理分析 spring依赖注入作用
- 2024-10-18 简单2步实现maven打包java工程并将依赖jar输出到指定目录
- 2024-10-18 怎么进阶学好Java 如何用Spring解决循环依赖
- 2024-10-18 Spring 源码分析之 bean 依赖注入原理(注入属性)
你 发表评论:
欢迎- 11-19零基础学习!数据分析分类模型「支持向量机」
- 11-19机器学习 | 算法笔记(三)- 支持向量机算法以及代码实现
- 11-19我以前一直没有真正理解支持向量机,直到我画了一张图
- 11-19研一小姑娘分享机器学习之SVM支持向量机
- 11-19[机器学习] sklearn支持向量机
- 11-19支持向量机
- 11-19初探支持向量机:用大白话解释、原理详解、Python实现
- 11-19支持向量机的核函数
- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)