接下来,我们一起来了解一下Spring的几种注入方式。
首先来了解一下定义:属性注入是指通过 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进行属性注入的配置桥段
上面的代码配置的一个Bean,class属性对应前面建好的实体Car,
运行一下 Tomcat,Spring容器会在Tomcat启动的时候创建;
控制台输出的结果:
构造函数注入是除属性注入外的另外一种注入方式,它保证了一些必要的属性在Bean实例化时就得到设置,确保在Bean实例化后就可以使用。
值得一提的是构造函数注入又分为多种方式,我们慢慢来看。
如果任何可用的Car对象都需要使用到brand,maxSpeed,price的值,那使用Setter注入方式,则只能人为的在配置时提供保证而无法再语法上提供保证,那这个时候使用构造函数注入就能满足这一个要求,使用构造函数注入的前提是要保证Bean中有提供带参的构造函数。
在
控制台输出的结果:
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;
}
因为brand和corp都是String类型,所以Spring无法确定type为String的
控制台输出的结果:
有时需要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的方式针对这样的情况又难以满足了这时就需要联合使用
对于上图的代码清单如果只根据index来进行匹配入参,那么Spring无法确认第三个参数是price还是maxSpeed了,所以解决这种有歧义的冲突,请将type和index结合使用,对于因参数数目相同而类型不同引起的潜在配置歧义问题,Spring容器可以正确的启动且不会给出报错信息,他将随机采用一个匹配的构造函数实例化Bean,而被选择的构造函数可能并不是用户所期望的那个。因此,必须要特别谨慎,以避免潜在的错误。
控制台输出的结果:
如果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入参都是可辨别的,所以无须在
但是为了避免潜在配置歧义引起的张冠李戴的情况,如果Bean存在多个构造函数,那么显式指定index和type属性是一种良好的配置习惯。
看控制台输出的结果:
5.循环依赖问题
Spring容器对构造函数配置Bean进行实例化有一个前提,即Bean构造函数入参引用的对象必须已经准备就绪。由于这个机制,如果两个Bean都相互引用,都采用构造函数注入方式,就会发生类似于线程死锁的循环依赖问题。
控制台输出的结果:(这就是采用循环注入方式产生最大的问题)
如何解决这种问题?将相互依赖的两个Bean中的其中一个Bean采用Setter注入的方式即可。
控制台输出结果:
既然需要一个工厂,那么我们需要创建一个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配置如下:
看控制台输出的结果:
Spring 提供给了我们多种注入方式,需要使用哪种方式各位同鞋可以根据自身的场景下考量,
这篇文章就分享到这啦,溜啦溜啦~~