关于SpringIOC的理解,以及自定义IOC的实现demo

IOC功能模拟实现

自己实现的IOCDemo代码

什么是IOC?

把创建和管理bean的过程转移给了第三方,而这个第三方就是Spring IOC.

何为控制,控制的是什么?

是bean的创建、管理的权利,控制bean的整个生命周期。

什么是反转?

对象的创建这个权利交给了Spring容器,而不是自己去控制,就是反转。

何为依赖,依赖什么?

程序运行需要依赖外部的资源,提供程序内对象的所需要数据、资源。

什么是注入?

配置文件把资源从外部注入到内部,容器加载了外部的文件、对象、数据,然后把这些资源注入给程序内的对象,维护了程序内外对象之间的依赖关系。

为什么要用IOC这种思想,IOC能给我们带来什么好处?

解耦。

如图:

关于SpringIOC的理解,以及自定义IOC的实现demo

关于SpringIOC的理解,以及自定义IOC的实现demo

IOC实现原理:

  1. 自定义注解
  2. 扫描根路径,递归,通过反射获取所有的类,放入 AllSet
  3. 从 AllSet 里获取所有带有IOC注解的类,放到 IOCSet
  4. 利用反射(Class.getDeclaredConstructor().newInstance())给 IOCSet 里的每一个类实例化,然后放入类型为ConcurrentHashMap的 InstanceMap
  5. 接着从AllSet里遍历每一个类,判断里面有没有字段带注入注解(@Autowired),没有就跳过
  6. 有,则首先根据类型去去匹配 InstanceMap
  7. 如果匹配上,且注解上没有自定义类的名字,从 InstanceMap 取出对应类型的实例,利用反射注入到成员变量对应的实例上面
  8. 没匹配上,且注解上没有自定义类的名字,则去 InstanceMap 里找对应类的实现类或者子类,再利用反射注入
  9. 注解上自定义了类的名字,且实现类和子类仍没有匹配上,则遍历每一个类,并获得类的 SimpleName ,用 SimpleName与自定义类名比较,相同的话利用反射注入

Spring中 @Autowired注解与@Resource注解的区别

@Autowired按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。@Resource有两个中重要的属性:name和type。name属性指定byName,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。需要注意的是,@Resource如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。

SpringIOC到底省略了我们什么工作?

new 对象的过程。

Spring中的bean的作用域有哪些?

  • singleton: 唯一bean实例,Spring中的bean默认都是单例的。
  • prototype:每次从容器中取,如getBean都会创建一个新的bean实例
  • request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTPrequest内有效。
  • session:同一个HTTPSession公用一个bean实例。

Spring中的单例bean的线程安全问题?

当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。

解决方法:

  • 在bean中尽量减少可变的成员变量(private final 变量)

  • 在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中。(怎么理解???):基于线程的变量,不会被其他线程获取到。ThreadLocal数据结构类似一个Map的ThreadLocalMap结构。用法

    ThreadLocal<Integer> totalScore = new ThreadLocal<>();
    totalScore.set(1);
    System.out.println(totalScore.get());
    totalScore.set(2);
    totalScore.set(3);
    System.out.println(totalScore.get());
    

Spring中的bean生命周期?

  1. Bean容器找到配置文件中Spring Bean的定义。
  2. Bean容器利用Java Reflection API创建一个Bean的实例。
  3. 如何涉及到一些属性值, 利用set()方法设置一些属性值。
  4. 如果bean实现了beanNameAware 接口,调用setBeanName()方法,传入Bean的名字。
  5. 如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。
  6. 如果Bean实现了BeanFactoryAware接口,调用setBeanClassLoader()方法,传入ClassLoader 对象的实例。
  7. 与上面相似,如果实现了其他的 *.Aware接口,就调用相应的方法。
  8. 如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessBeforeInitialization()方法
  9. 如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法
  10. 如果Bean在配置文件中的定义包含init-method属性,执行指定的方法。
  11. 如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessAfterInitialization()方法
  12. 当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
  13. 当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。

英文版:

关于SpringIOC的理解,以及自定义IOC的实现demo

中文版:

关于SpringIOC的理解,以及自定义IOC的实现demo

如果注入的属性为null,你会从哪些方面去排查?

  1. 检查Spring配置,看看你的xml中有没有放置bean或者,需要注入的类上有没有加注解。
  2. 检查实例化的方式,看看你的对象是不是从容器中获取的
  3. @autowired不能放在一个静态属性上
  4. web容器启动顺序:Listener -> filter -> servlet,如果在filter里去使用controller类调用它里面service层的属性,此时因为还没到servlet层,没注入属性,就会空指针 (有待探讨)(怎么理解???)

你在项目开发中,IOC有遇到什么难点吗?如何解决的?

Spring循环依赖如何解决?

解决方案同一道LeetCode题:two sum 相似

先说思路:A先实例化放到缓存中,然后A填充字段属性,需要B,切B没有实例化,那么接着去实例化B,然后填充B的字段属性,发现B需要A,检查缓存,发现A存在然后取出A填充B,B填充结束后,把B的实例化对象再填充A。

阅读DefaultSingletonBeanRegistry类,你会发现里面有三个Map:

  • private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
  • private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    
  • private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
    

这三个Map就是解决循环依赖的本质:

  1. 准备实例化A,先生成一个工厂singletonFactoriesA,然后填充A的属性
  2. 发现需要填充B,B没有在缓存中,需要实例化,先生成一个工厂singletonFactoriesB,然后填充B的属性
  3. 发现需要填充A,检查缓存,发现存在工厂singletonFactoriesA,则先实例化一个早期的A实例,放入earlySingletonObjects Map中,并删除singletonFactoriesA
  4. 把早期的A实例填充到B上,B成功实例化,放入singletonObjectsMap中,并删除A早期实例
  5. 最后把A一直在等待方法回调结果依赖的B实例填充到A上,放入singletonObjectsMap中
  6. 由于map的key一直是beanname,所以当

循环依赖发生的场景只发生在singelton(默认的单实例)中

https://mp.weixin.qq.com/s/5mwkgJB7GyLdKDgzijyvXw

https://www.jianshu.com/p/a77e64250a9e

Cglib在代理中有什么限制?

委托类不能是final类

引用:

Spring常见问题
什么是Spring循环依赖?
排查IOC注入属性为空

上一篇:【Spring】SpringIoC大致流程


下一篇:刷题之Codeforces Round #723 (Div. 2)