Spring通过DI(依赖注入)实现IOC(控制反转)
实例Bean注入
1、构造方法注入:
a) xml文件配置
b) java代码
public class UserService implements IUserService {
private IUserDao userDao;
public UserService(IUserDao userDao) {
this.userDao = userDao;
}
public void loginUser() {
userDao.loginUser();
}
}
注:
单个注入参数场景:
1、其中必须保证,com.lyu.spring.dao.impl.UserDaoJdbc 实现IUserDao接口
2、只有一个有参数的构造方法并且参数类型与注入的bean的类型匹配,那就会注入到该构造方法中。
3、如果有多个参数的构造方法,且都有要注入的参数类型。只会注入到只有一个参数的构造方法中,且与构造方法的顺序无关;如果没有单独一个的,会注入失败。
多个注入参数场景:
1、直接在xml配置多个construct-arg节点即可。
2、如果有多个构造方法,方法注入参数顺序不同时,跟顺序有关系,哪个在前会使用哪个构造方法。
2、Setter注入
xml配置文件:
注:spring会将name值的每个单词首字母转换成大写,然后再在前面拼接上”set”构成一个方法名,然后去对应的类中查找该方法,通过反射调用,实现注入。
切记:name属性值与类中的成员变量名以及set方法的参数名都无关,只与对应的set方法名有关,下面的这种写法是可以运行成功的
public class UserService implements IUserService {
private IUserDao userDao1;
public void setUserDao(IUserDao userDao1) {
this.userDao1 = userDao1;
}
public void loginUser() {
userDao1.loginUser();
}
}
还有一点需要注意:如果通过set方法注入属性,那么spring会通过默认的空参构造方法来实例化对象,所以如果在类中写了一个带有参数的构造方法,一定要把空参数的构造方法写上,否则spring没有办法实例化对象,导致报错。
3、基于注解方式
依赖关系注入
@Resource:
java的注解,默认以byName的方式去匹配与属性名相同的bean的id,如果没有找到就会以byType的方式查找,如果byType查找到多个的话,使用@Qualifier注解(spring注解)指定某个具体名称的bean。
@Autowired
java的注解,默认以byType的方式去匹配与属性名相同的bean的id,如果没有找到,再以byname方式匹配与属性名相同的bean的id。
Bean 循环依赖
1、构造方法的依赖
现象:Bean A引用Bean B,Bean B引用Bean C,Bean C引用Bean A。在创建A时,需要创建B,依次类推,三者形成一个环,形成循环依赖。
结果:Spring 在此场景下会抛出BeanCurrentlyInCreateException。
原理:Spring 在创建Bean时会维护一个"正在创建的Bean池",一旦有Bean的ID在池子里,如果在create该bean则会抛出上述异常。如果Bean被创建成功后,Bean会被移出"正在创建的池"
实例:
public class C {
private A a;
public C(){}
public C(A a){ this.a = a; }
public A getA() { return a; }
public void setA(A a) { this.a = a; }
public void hello(){ a.doHello(); }
public void doHello(){
System.out.println("I am C");
}
}
A和B类结果类似C
main方法:
public class SpringMain {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(“bean-circle.xml”);
A a = A.class.cast(ac.getBean(“a”));
a.hello();
}
}
调用main方法抛出异常。
原理:
Spring中不能存在构造方法中的循环引用,因为,还没创建要注入的属性值,无法赋值
2、Setter注入循环依赖
a) Spring 可以完成Bean在单例模式下的循环依赖,不会抛出异常。
原理:在一个单例bean创建的时候,Spring就把它当作存在循环依赖来处理,就是
1、在一个bean调用无参构造方法实例化结束之后,会放到三级缓存中提前曝光,让其他的依赖他的bean可以获得到还没有创建完成的它。
2、当在填充属性的时候如果发现有一个需要注入的属性值是一个引用值,在类型转换的时候就会在IOC容器中查找这个引用的bean,没有就先创建它,就这样一直递归着执行下去。
3、由于是循环依赖,就不可能有任何一个bean可以直接创建完,所以只能先把还没有填充属性的bean的引用赋给当前bean,Spring很巧妙的用了三级缓存来保留住了这个引用。
4、从这也可以看出,Spring中不能存在构造方法中的循环引用,因为,还没创建要注入的属性值,无法赋值。
————————————————
版权声明:本文为CSDN博主「赵银龙」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_37343985/article/details/82822990
b) Spring无法完成Bean在非单例模式下的循环依赖,会抛出异常。