模拟spring容器创建Bean并解决循环依赖 源码参考:https://gitee.com/itmc/spring-m gitee:https://gitee.com/itmc/spring-m.git

1.Spring创建Bean的过程

  • 扫描配置获得BeanDefinitionMap 集Bean定义,像Bean类型,是否是单例,是否是懒加载等.
  • 遍历BeanDefinitionMap去创建Bean
  • 构造推断
  • 属性setter赋值
  • 回调各种Aware,如BeanNameAware
  • Aware回调后,判断是否实现BeanPostProcessor ,调用初始化前方法postProcessBeforeInitialization(),是否被@PostConstruct注解了,如果存在,Spring会调用当前对象的此方法
  • 初始化如果当前instance是InitializingBean子类,则调用初始化方法
  • 判断是否实现BeanPostProcessor ,调用初始化后方法postProcessAfterInitialization(),aop在这里实现
  • 创建bean,Bean对象创建出来后:
    • 如果当前Bean是单例Bean,那么会把该Bean对象存入一个Map,Map的key为beanName,value为Bean对象。这样下次getBean时就可以直接从Map中拿到对应的Bean对象了。(实际上,在Spring源码中,这个Map就是单例池)
    • 如果当前Bean是原型Bean,那么后续没有其他动作,不会存入一个Map,下次getBean时会再次执行上述创建过程,得到一个新的Bean对象。

      2.模拟Spring创建与管理Bean

      如何手写spring容器 - 图1注:本过程简单模拟SpringBean的创建过程.这里只是简单模拟.具体Spring的流程要比这多

2.1 Spring如何管理Bean

  1. public class TestDemo {
  2. public static void main(String[] args) {
  3. ApplicationContext context=new AnnotationConfigApplicationContext("com.itmck.beans");
  4. UserServiceImpl bean = context.getBean("userServiceImpl",UserServiceImpl.class);
  5. bean.sayHi();
  6. }
  7. }

通过AnnotationConfigApplicationContext构造函数可知,我们要自定义spring的ioc容器,首先需要如下:

  • 扫描配置生成BeanDefinitionMap
  • 遍历BeanDefinitionMap创建Bean实例

    1. public class AnnotationConfigApplicationContext {
    2. public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    3. this();
    4. register(componentClasses);
    5. refresh();
    6. }
    7. public AnnotationConfigApplicationContext(String... basePackages) {
    8. this();
    9. scan(basePackages);
    10. refresh();
    11. }
    12. }

    2.2模拟spring

    2.2.1 创建容器

    我们创建了AnnotationConfigApplicationContext并且拥有一个扫描方法,一个刷新方法(创建Bean方法),还有getBean()方法.简单架子如下所示:

说明:

  1. AnnotationConfigApplicationContext(Class<?> myConfigClass) 通过构造方法传入配置类
  2. scan(myConfigClass) 扫描获取Bean定义
  3. refresh() 创建Bean
  4. getBean(String beanName) 获取Bean ```java package com.itmck.spring.core;

/**

  • 太阳当空照,花儿对我笑
  • Create by M ChangKe 2021/11/25 10:17 **/ public class AnnotationConfigApplicationContext {

    /**

    • 通过构造方法传入配置类 *
    • @param myConfigClass 配置类 */ public AnnotationConfigApplicationContext(Class<?> myConfigClass) {

      scan(myConfigClass); refresh(); }

      /**

    • 扫描配置类 *
    • @param myConfigClass 配置类 */ private void scan(Class<?> myConfigClass) { }

      /**

    • 创建Bean */ private void refresh() {

      }

  1. /**
  2. * 通过BeanName获取Bean对象
  3. *
  4. * @param beanName Bean别名
  5. * @return Bean对象
  6. */
  7. public Object getBean(String beanName) {
  8. return null;
  9. }
  10. /**
  11. * 通过通过BeanName一级Bean class获取Bean对象
  12. *
  13. * @param beanName Bean别名
  14. * @param tClass bean class类型
  15. * @param <T> 实例泛型
  16. * @return Bean对象
  17. */
  18. public <T> T getBean(String beanName, Class<T> tClass) {
  19. return tClass.cast(getBean(beanName));
  20. }

}

  1. <a name="YWJAA"></a>
  2. ### 2.2.2 定义注解
  3. 创建注解用于标记bean
  4. - @Component
  5. ```java
  6. package com.itmck.spring.annotation;
  7. import java.lang.annotation.ElementType;
  8. import java.lang.annotation.Retention;
  9. import java.lang.annotation.RetentionPolicy;
  10. import java.lang.annotation.Target;
  11. @Retention(RetentionPolicy.RUNTIME)
  12. @Target(ElementType.TYPE)
  13. public @interface Component {
  14. String value() default "";
  15. }
  • @Autowired ```java package com.itmck.spring.annotation;

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Autowired {

}

  1. - @ComponentScan
  2. ```java
  3. package com.itmck.spring.annotation;
  4. import java.lang.annotation.ElementType;
  5. import java.lang.annotation.Retention;
  6. import java.lang.annotation.RetentionPolicy;
  7. import java.lang.annotation.Target;
  8. /**
  9. * 类扫描注解
  10. *
  11. * 太阳当空照,花儿对我笑
  12. * <p>
  13. * Create by M ChangKe 2021/9/11 16:44
  14. **/
  15. @Retention(RetentionPolicy.RUNTIME)
  16. @Target(ElementType.TYPE)
  17. public @interface ComponentScan {
  18. String value() default "";
  19. }
  • @Scope ```java package com.itmck.spring.annotation;

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Scope {

  1. String value() default "";

}

  1. <a name="D6GNa"></a>
  2. ### 2.2.3 创建BeanDefinition
  3. 扫描的目的就是扫描出BeanDefinition集合.BeanDefinition中包含了Bean类型,是否单例,是否懒加载....等
  4. ```java
  5. package com.itmck.spring.core;
  6. /**
  7. * 太阳当空照,花儿对我笑
  8. * <p>
  9. * Create by M ChangKe 2021/9/11 17:28
  10. **/
  11. public class BeanDefinition {
  12. /**
  13. * bean类型
  14. */
  15. private Class<?> type;
  16. /**
  17. * 是否是单例
  18. */
  19. private String scope;
  20. /**
  21. * 是否是懒加载
  22. */
  23. private boolean isLazy;
  24. //省略getter/setter...
  25. }

2.2.4 创建scan(),refresh()以及getBean()方法

  1. package com.itmck.spring.core;
  2. import com.itmck.spring.annotation.Component;
  3. import com.itmck.spring.annotation.ComponentScan;
  4. import com.itmck.spring.annotation.Scope;
  5. import java.beans.Introspector;
  6. import java.io.File;
  7. import java.lang.reflect.Field;
  8. import java.lang.reflect.InvocationTargetException;
  9. import java.net.URL;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. /**
  13. * 太阳当空照,花儿对我笑
  14. * <p>
  15. * Create by M ChangKe 2021/11/25 10:17
  16. **/
  17. public class AnnotationConfigApplicationContext {
  18. /**
  19. * beanDefinitionMap 存放多个Bean定义 其中key为BeanName,value为BeanDefinition
  20. */
  21. private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
  22. /**
  23. * 单例池,如果创建的是单例对象则放入单例池中
  24. */
  25. private final Map<String, Object> singletonObjects = new HashMap<>(256);
  26. /**
  27. * 通过构造方法传入配置类
  28. *
  29. * @param myConfigClass 配置类
  30. */
  31. public AnnotationConfigApplicationContext(Class<?> myConfigClass) {
  32. scan(myConfigClass);
  33. refresh();
  34. }
  35. /**
  36. * 扫描配置类
  37. *
  38. * @param myConfigClass 配置类
  39. */
  40. private void scan(Class<?> myConfigClass) {
  41. if (myConfigClass.isAnnotationPresent(ComponentScan.class)) {
  42. //如果当前配置类上存在注解@ComponentScan,则代表当前类为配置类
  43. ComponentScan componentScan = myConfigClass.getAnnotation(ComponentScan.class);
  44. //获取value内容 com.itmck.mck
  45. String path = componentScan.value();
  46. path = path.replace(".", "/");//将com.itmck.mck-->com/itmck/mck
  47. //获取当前类加载器
  48. ClassLoader classLoader = this.getClass().getClassLoader();
  49. URL resource = classLoader.getResource(path);
  50. assert resource != null;
  51. File file = new File(resource.getFile());
  52. if (file.isDirectory()) {
  53. File[] files = file.listFiles();
  54. assert files != null;
  55. for (File f : files) {
  56. String absolutePath = f.getAbsolutePath();
  57. absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
  58. absolutePath = absolutePath.replace("\\", ".");
  59. Class<?> aClass = null;
  60. try {
  61. //通过类加载器,加载当前类信息
  62. aClass = classLoader.loadClass(absolutePath);
  63. } catch (ClassNotFoundException e) {
  64. e.printStackTrace();
  65. }
  66. assert aClass != null;
  67. if (aClass.isAnnotationPresent(Component.class)) {
  68. //如果当前类上存在存在@Component注解
  69. Component component = aClass.getAnnotation(Component.class);
  70. String beanName = component.value();
  71. if ("".equals(beanName)) {
  72. //如果没有给默认值,则使用类的首字母小写
  73. beanName = Introspector.decapitalize(aClass.getSimpleName());
  74. }
  75. //扫描的目的就是获取BeanDefinition
  76. BeanDefinition beanDefinition = new BeanDefinition();
  77. beanDefinition.setType(aClass);
  78. //判断是否存在Scope注解标记
  79. if (aClass.isAnnotationPresent(Scope.class)) {
  80. Scope scope = aClass.getAnnotation(Scope.class);
  81. String value = scope.value();
  82. beanDefinition.setScope(value);
  83. } else {
  84. beanDefinition.setScope("singleton");
  85. }
  86. beanDefinitionMap.put(beanName, beanDefinition);
  87. }
  88. }
  89. }
  90. }
  91. }
  92. /**
  93. * 创建Bean
  94. */
  95. private void refresh() {
  96. //在这里拿到beanDefinitionMap后即可对Bean进行创建
  97. beanDefinitionMap.forEach((beanName, beanDefinition) -> {
  98. if ("singleton".equals(beanDefinition.getScope())) {
  99. try {
  100. Object bean = createBean(beanName, beanDefinition);
  101. singletonObjects.put(beanName, bean);
  102. } catch (Exception e) {
  103. e.printStackTrace();
  104. }
  105. }
  106. });
  107. }
  108. private Object createBean(String beanName, BeanDefinition beanDefinition) {
  109. Class<?> aClass = beanDefinition.getType();
  110. Object instance = null;
  111. if (aClass.isAnnotationPresent(Component.class)) {
  112. try {
  113. instance = aClass.getConstructor().newInstance();//无参构造创建Bean
  114. Field[] declaredFields = aClass.getDeclaredFields();
  115. for (Field field : declaredFields) {
  116. String name = field.getName();
  117. field.setAccessible(true);
  118. field.set(instance, getBean(name));
  119. }
  120. } catch (Exception e) {
  121. e.printStackTrace();
  122. }
  123. }
  124. return instance;
  125. }
  126. /**
  127. * 通过BeanName获取Bean对象
  128. *
  129. * @param beanName Bean别名
  130. * @return Bean对象
  131. */
  132. public Object getBean(String beanName) {
  133. if (!beanDefinitionMap.containsKey(beanName)) {
  134. throw new NullPointerException();
  135. }
  136. BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
  137. //如果是获取的Bean在单例池中存在则从单例池中取,否则新建
  138. if ("singleton".equals(beanDefinition.getScope())) {
  139. Object singletonBean = singletonObjects.get(beanName);
  140. if (singletonBean == null) {
  141. singletonBean = createBean(beanName, beanDefinition);
  142. singletonObjects.put(beanName, singletonBean);
  143. }
  144. return singletonBean;
  145. } else {
  146. // 原型Bean
  147. return createBean(beanName, beanDefinition);
  148. }
  149. }
  150. /**
  151. * 通过通过BeanName一级Bean class获取Bean对象
  152. *
  153. * @param beanName Bean别名
  154. * @param tClass bean class类型
  155. * @param <T> 实例泛型
  156. * @return Bean对象
  157. */
  158. public <T> T getBean(String beanName, Class<T> tClass) {
  159. return tClass.cast(getBean(beanName));
  160. }
  161. }

到此位置,已经成功创建spring-m并初始化了相关方法.下一步就是应用案例测试

2.2.5 框架测试

2.2.5.1 创建 OneConfig.class

  1. package com.itmck.one;
  2. import com.itmck.spring.annotation.ComponentScan;
  3. @ComponentScan("com.itmck.one")
  4. public class OneConfig {
  5. }

2.2.5.2 创建User对象

  1. package com.itmck.one;
  2. import com.itmck.spring.annotation.Autowired;
  3. import com.itmck.spring.annotation.Component;
  4. @Component
  5. public class User {
  6. public void run() {
  7. System.out.println("User#run() is running...");
  8. }
  9. }

2.2.5.3 测试

  1. package com.itmck.one;
  2. import com.itmck.mck.MyConfig;
  3. import com.itmck.mck.UserA;
  4. import com.itmck.mck.UserB;
  5. import com.itmck.spring.core.AnnotationConfigApplicationContext;
  6. import com.itmck.spring.core.AnnotationConfigApplicationContext2;
  7. /**
  8. * 太阳当空照,花儿对我笑
  9. * <p>
  10. * Create by M ChangKe 2021/11/24 9:36
  11. **/
  12. public class TestDemo2 {
  13. public static void main(String[] args) {
  14. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
  15. User user = applicationContext.getBean("user", User.class);
  16. user.run();
  17. }
  18. }

运行结果 User#run() is running…
注:上述代码是针对单个Bean进行扫描以及创建的简单流程梳理,但spring中远不止这些.

循环依赖

什么是循环依赖?

  1. 循环依赖就是A依赖B,B依赖A,互相依赖.主要分为一个类之间,两个类,多个类之间的依赖

image.png

  1. 循环依赖分为构造器依赖和属性依赖,众所周知的是Spring能够解决属性的循环依赖(set注入)

    如何解决循环依赖?

    简单来说,解决循环依赖就是加一个出口,方式死循环.
    image.png
    怎样增加出口?简单说就是增加一个缓存

模拟spring解决循环依赖

spring中使用三级缓存解决循环依赖

  1. singletonObjects 单例池
  2. earlySingletonObjects 纯净bean(刚实例化的Bean)
  3. singletonFactories 存放用于创建Bean的工厂 ObjectFactory


模拟解决循环依赖

  • UserA ```java package com.itmck.mck;

import com.itmck.spring.annotation.Autowired; import com.itmck.spring.annotation.Component;

/**

  • 太阳当空照,花儿对我笑
  • Create by M ChangKe 2021/9/11 18:08 **/ @Component public class UserA {

    @Autowired private UserB userB;

    public void run() {

    1. System.out.println("UserA");

    } //省略get/set } ```

  • UserB ```java package com.itmck.mck;

import com.itmck.spring.annotation.Autowired; import com.itmck.spring.annotation.Component;

/**

  • 太阳当空照,花儿对我笑
  • Create by M ChangKe 2021/9/11 18:08 **/ @Component public class UserB {

    @Autowired private UserA userA;

    public void run(){

    1. System.out.println("UserB");

    } //略get/set

}

  1. <a name="e6Zj3"></a>
  2. ### 一级缓存
  3. <a name="omP4n"></a>
  4. #### 一级缓存如何解决?
  5. 首先引入 ** private final Map<String, Object> singletonObjects = new HashMap<>(256); 作为一级缓存**<br />修改createBean()方法是关键.因为A依赖B,在创建A的时候给A属性赋值,这时需要创建B.然后创建B又依赖到A....循环往复.怎么办????
  6. - **调用createBean()进行递归创建**
  7. - **防止递归循环需要添加一个出口函数**
  8. ```java
  9. private Object createBean(String beanName, BeanDefinition beanDefinition) {
  10. //使用一级缓存解决循环依赖
  11. //1================在这里先判断一级缓存中是否存在,这里是解决循环依赖的关键,添加一个递归出口,防止无限递归====
  12. Object singleton = getSingleton(beanName);
  13. if (singleton != null) {
  14. return singleton;
  15. }
  16. //================在这里先判断一级缓存中是否存在,这里是解决循环依赖的关键,添加一个递归出口,防止无限递归=====
  17. Class<?> aClass = beanDefinition.getType();
  18. Object instance = null;
  19. if (aClass.isAnnotationPresent(Component.class)) {
  20. try {
  21. instance = aClass.getConstructor().newInstance();//无参构造创建Bean
  22. //2==================将instance放入一级缓存======================
  23. singletonObjects.put(beanName,instance);//将instance放入一级缓存
  24. //==================将instance放入一级缓存======================
  25. Field[] declaredFields = aClass.getDeclaredFields();
  26. for (Field field : declaredFields) {
  27. field.setAccessible(true);
  28. //**在这里调用自身方法进行递归操作获取bean**
  29. field.set(instance,createBean(field.getName(), beanDefinitionMap.get(field.getName())));
  30. }
  31. } catch (Exception e) {
  32. e.printStackTrace();
  33. }
  34. }
  35. return instance;
  36. }
  37. public Object getSingleton(String beanName) {
  38. if (singletonObjects.containsKey(beanName)) {
  39. return singletonObjects.get(beanName);
  40. }
  41. return null;
  42. }

上述代码两个关键点 1,2

测试

  1. package com.itmck;
  2. import com.itmck.mck.MyConfig;
  3. import com.itmck.mck.UserA;
  4. import com.itmck.mck.UserB;
  5. import com.itmck.one.OneConfig;
  6. import com.itmck.one.User;
  7. import com.itmck.spring.core.AnnotationConfigApplicationContext;
  8. import com.itmck.spring.core.AnnotationConfigApplicationContext2;
  9. /**
  10. * 太阳当空照,花儿对我笑
  11. * <p>
  12. * Create by M ChangKe 2021/11/24 9:36
  13. **/
  14. public class MckSpringApplication {
  15. public static void main(String[] args) throws Exception {
  16. AnnotationConfigApplicationContext2 applicationContext = new AnnotationConfigApplicationContext2(MyConfig.class);
  17. UserA userA = applicationContext.getBean("userA", UserA.class);
  18. UserB userB1 = userA.getUserB();
  19. System.out.println("UserA#userB.run()");
  20. userB1.run();
  21. UserB userB = applicationContext.getBean("userB", UserB.class);
  22. UserA userA1 = userB.getUserA();
  23. System.out.println("UserB#userA.run()");
  24. userA1.run();
  25. }
  26. }

结果如下,表示循环依赖已经解决

  1. UserA#userB.run()
  2. UserB
  3. UserB#userA.run()
  4. UserA

现在看上去一级缓存已经能够解决循环依赖问题.
如果是多线程环境下
假如现有2个线程:线程A在创建BeanA的同时线程B创建BeanB
A线程在创建beanA的时候,实例化后加入一级缓存,B线程在创建B的时候依赖A此时去一级缓存中getBeanA,拿到的是不完整的beanA.
所以一级缓存解决的是单线程环境下的循环依赖,多线程环境仍然不能保证解决.此时需要引入二级缓存

二级缓存

二级缓存如何解决?

  • 修改代码如下,新增二级缓存earlySingletonObjects用于存放纯净Bean

    private final Map earlySingletonObjects = new ConcurrentHashMap<>(256);

  • 改造scan()与getSingleton()方法 ```java private Object createBean(String beanName, BeanDefinition beanDefinition) { //使用一级缓存解决循环依赖 //在这里先判断一级缓存中是否存在,这里是解决循环依赖的关键,添加一个递归出口,防止无限递归 Object singleton = getSingleton(beanName); if (singleton != null) {

    1. return singleton;

    } Class<?> aClass = beanDefinition.getType(); Object instance = null; if (aClass.isAnnotationPresent(Component.class)) {

    1. try {
    2. instance = aClass.getConstructor().newInstance();//无参构造创建Bean
    3. earlySingletonObjects.put(beanName, instance);//这里新增二级缓存存放新鲜反射出来的纯净Bean
    4. Field[] declaredFields = aClass.getDeclaredFields();
    5. for (Field field : declaredFields) {
    6. field.setAccessible(true);
    7. field.set(instance, createBean(field.getName(), beanDefinitionMap.get(field.getName())));//在这里调用自身方法进行递归操作获取bean
    8. }
    9. } catch (Exception e) {
    10. e.printStackTrace();
    11. }

    } //初始化在这里 //init——— singletonObjects.put(beanName, instance);//将instance放入一级缓存,这里的Bean是完成了属性赋值,初始化等完整的单例Bean return instance; }

/**

  • 通过判断 *
  • @param beanName Bean别名
  • @return Bean对象 */ public Object getSingleton(String beanName) { if (singletonObjects.containsKey(beanName)) {
    1. return singletonObjects.get(beanName);
    }else if (earlySingletonObjects.containsKey(beanName)){
    1. //新增二级缓存后,一级缓存没有从二级缓存中取
    2. return earlySingletonObjects.get(beanName);
    } return null;

}

  1. 上述代码注意:注意:earlySingletonObjects.put(beanName, instance)与singletonObjects.put(beanName, instance)位置<br />最后运行结果与上述一致
  2. <a name="I2Okh"></a>
  3. ### 总结:一级缓存和二级缓存的作用
  4. - 一级缓存: 解决循环依赖的问题,但是不能完全解决,因为存在多线程问题
  5. - 二级缓存: 在创建实例bean和放入到一级缓存之间还有一段间隙. 如果在这之间从一级缓存拿实例, 肯定是返回null的. 为了避免这个问题, 增加了二级缓存.(多线程问题)
  6. <a name="Ca19M"></a>
  7. ## 到这里可以发现使用二级缓存就可以解决循环依赖中Aop的问题.那么为什Spring使用了三级缓存?
  8. <a name="DsJGU"></a>
  9. ## <br />aop创建时机
  10. **我们在创建bean 的时候, 会有很多Bean的后置处理器BeanPostProcessor. 如果有AOP, 会在什么时候创建呢? 在初始化以后, 调用BeanPostProcessor创建动态代理?**
  11. 结合上面的代码, 我们想一想, 其实在初始化以后创建动态代理就晚了. 为什么呢? 因为, 如果有循环依赖, 在初始化之后才调用, 那就不是动态代理. 其实我们这时候应该在实例化之后, 放入到二级缓存之前调用. 如果判断有循环依赖此时进行AOP,那么最佳位置应该是在判断二级缓存存在说明是循环依赖,此时进行aop然后将新的实例放入二级缓存
  12. 修改后代码如下:
  13. ```java
  14. public Object getSingleton(String beanName) {
  15. if (singletonObjects.containsKey(beanName)) {
  16. return singletonObjects.get(beanName);
  17. }else if (earlySingletonObjects.containsKey(beanName)){
  18. //新增二级缓存后,一级缓存没有从二级缓存中取
  19. /**
  20. * 第一次创建bean是正常的instanceBean. 他并不是循环依赖. 第二次进来判断, 这个bean已经存在了, 就说明是循环依赖了
  21. * 这时候通过动态代理创建bean. 然后将这个bean在放入到二级缓存中覆盖原来的instanceBean.
  22. * 这样我们在循环依赖的时候就完成了AOP的创建. 这是在二级缓存里创建的AOP
  23. */
  24. Object instance = new CglibProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName), beanName);
  25. earlySingletonObjects.put(beanName, instance);
  26. return earlySingletonObjects.get(beanName);
  27. }
  28. return null;
  29. }


创建CglibProxyBeanPostProcessor

  1. package com.itmck.mck;
  2. import com.itmck.spring.annotation.Component;
  3. import com.itmck.spring.core.SmartInstantiationAwareBeanPostProcessor;
  4. import com.itmck.spring.proxy.MyEnhancer;
  5. import com.itmck.spring.proxy.MyProxy;
  6. import net.sf.cglib.proxy.Enhancer;
  7. /**
  8. * 太阳当空照,花儿对我笑
  9. * <p>
  10. * Create by M ChangKe 2021/9/11 18:08
  11. **/
  12. @Component
  13. public class CglibProxyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
  14. @Override
  15. public Object getEarlyBeanReference(Object bean, String beanName) {
  16. // 假设A被切点命中 需要创建代理 @PointCut("execution(* *..InstanceA.*(..))")
  17. /**
  18. * 这里, 我们简单直接判断bean是不是InstanceA实例, 如果是, 就创建动态代理.
  19. * 这里没有去解析切点, 解析切点是AspectJ做的事.
  20. */
  21. if (bean instanceof UserA) {
  22. MyEnhancer myEnhancer = new MyEnhancer(new MyProxy(),bean);
  23. Enhancer enhancer = myEnhancer.getEnhancer();
  24. bean = enhancer.create();
  25. }
  26. return bean;
  27. }
  28. }


MyEnhancer

使用cglib代理需要引入pom

  1. <dependency>
  2. <groupId>cglib</groupId>
  3. <artifactId>cglib</artifactId>
  4. <version>3.3.0</version>
  5. </dependency>
  1. package com.itmck.spring.proxy;
  2. import net.sf.cglib.proxy.Enhancer;
  3. /**
  4. * 太阳当空照,花儿对我笑
  5. * <p>
  6. * Create by M ChangKe 2021/11/25 15:11
  7. **/
  8. public class MyEnhancer {
  9. private final MyProxy myProxy;
  10. private final Object object;
  11. public MyEnhancer(MyProxy myProxy, Object object) {
  12. this.myProxy = myProxy;
  13. this.object = object;
  14. }
  15. public Enhancer getEnhancer(){
  16. Enhancer enhancer = new Enhancer(); // 通过CGLIB动态代理获取代理对象的过程
  17. enhancer.setSuperclass(object.getClass()); // 设置enhancer对象的父类
  18. enhancer.setCallback(myProxy); // 设置enhancer的回调对象
  19. return enhancer;
  20. }
  21. }


MyProxy implements MethodInterceptor

  1. package com.itmck.spring.proxy;
  2. import net.sf.cglib.proxy.MethodInterceptor;
  3. import net.sf.cglib.proxy.MethodProxy;
  4. import java.lang.reflect.Method;
  5. public class MyProxy implements MethodInterceptor {
  6. /**
  7. *
  8. * @param o cglib生成的代理对象
  9. * @param method 被代理对象的方法
  10. * @param objects 传入方法的参数
  11. * @param methodProxy 代理的方法
  12. * @return
  13. * @throws Throwable
  14. */
  15. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
  16. System.out.println("这里可以插入执行关键代码之前的逻辑");
  17. Object o1 = methodProxy.invokeSuper(o, objects);//关键代码:
  18. System.out.println("这里可以插入执行关键代码之后的逻辑");
  19. return o1;
  20. }
  21. }

此时运行代码结果

  1. UserA#userB.run()
  2. UserB
  3. UserB#userA.run()
  4. 这里可以插入执行关键代码之前的逻辑
  5. UserA
  6. 这里可以插入执行关键代码之后的逻辑

通过上面发现:如果在getBean的时候写,不符合单一职责标准。后置处理器是在bean的创建过程中去给它增强的.所以三级缓存是为了单一职责


引入三级缓存

如何引入?

  • public final Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>();
  • 在createBean中实例化之后进行保存ObjectFactory 到三级缓存singletonFactories ```java private Object createBean(String beanName, BeanDefinition beanDefinition) { //使用一级缓存解决循环依赖 //在这里先判断一级缓存中是否存在,这里是解决循环依赖的关键,添加一个递归出口,防止无限递归 Object singleton = getSingleton(beanName); if (singleton != null) {

    1. return singleton;

    } // 正在创建 singletonsCurrentlyInCreation.add(beanName);

    Class<?> aClass = beanDefinition.getType(); Object instance = null; if (aClass.isAnnotationPresent(Component.class)) {

    1. try {
    2. instance = aClass.getConstructor().newInstance();//无参构造创建Bean
    3. //在这里直接进行aop不合理,因为没有进行判断,所以要先判断是否需要进行代理,如果需要才进行aop,在哪里判断?
    4. //当有循环依赖的时候,二级缓存不为null,所以在getSingleton()中判断
    5. //instance = new JdkProxyBeanPostProcessor().getEarlyBeanReference(instance, beanName);
    6. //实例化之后保 级缓存就是存函数接口的
    7. singletonFactories.put(beanName,() -> new CglibProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName), beanName));
    8. earlySingletonObjects.put(beanName, instance);//这里新增二级缓存存放新鲜反射出来的纯净Bean
    9. Field[] declaredFields = aClass.getDeclaredFields();
    10. for (Field field : declaredFields) {
    11. field.setAccessible(true);
    12. field.set(instance, createBean(field.getName(), beanDefinitionMap.get(field.getName())));//在这里调用自身方法进行递归操作获取bean
    13. }
    14. } catch (Exception e) {
    15. e.printStackTrace();
    16. }

    } /**

    • 第四步: 初始化
    • 初始化就是设置类的init-method.这个可以设置也可以不设置. 我们这里就不设置了 */

      //正常的代理实在初始化之后,就是这里进行,但是如果存在循环依赖必须在实例化之后进行 //instance = new JdkProxyBeanPostProcessor().getEarlyBeanReference(instance, beanName);

  1. // 由于递归完后A 还是原实例,, 所以要从二级缓存中拿到proxy 。
  2. if (earlySingletonObjects.containsKey(beanName)) {
  3. instance = earlySingletonObjects.get(beanName);
  4. }
  5. //将instance放入一级缓存,这里的Bean是完成了属性赋值,初始化等完整的单例Bean
  6. singletonObjects.put(beanName, instance);
  7. return instance;

}

  1. <a name="ElS8z"></a>
  2. ### <br />getSingleton()修改如下
  3. ```java
  4. public Object getSingleton(String beanName) {
  5. // 先从一级缓存中拿
  6. Object bean = singletonObjects.get(beanName);
  7. // 说明是循环依赖
  8. if (bean == null && singletonsCurrentlyInCreation.contains(beanName)) {
  9. bean = earlySingletonObjects.get(beanName);
  10. // 如果二级缓存没有就从三级缓存中拿
  11. if (bean == null) {
  12. // 从三级缓存中拿
  13. ObjectFactory<?> factory = singletonFactories.get(beanName);
  14. if (factory != null) {
  15. try {
  16. bean = factory.getObject(); // 拿到动态代理
  17. earlySingletonObjects.put(beanName, bean);
  18. //然后从二级缓存移除singletonFactory
  19. this.singletonFactories.remove(beanName);
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }
  25. }
  26. return bean;
  27. }

完整代码

  1. package com.itmck.spring.core;
  2. import com.itmck.mck.CglibProxyBeanPostProcessor;
  3. import com.itmck.spring.annotation.Component;
  4. import com.itmck.spring.annotation.ComponentScan;
  5. import com.itmck.spring.annotation.Scope;
  6. import java.beans.Introspector;
  7. import java.io.File;
  8. import java.lang.reflect.Field;
  9. import java.net.URL;
  10. import java.util.HashMap;
  11. import java.util.HashSet;
  12. import java.util.Map;
  13. import java.util.Set;
  14. import java.util.concurrent.ConcurrentHashMap;
  15. /**
  16. * 太阳当空照,花儿对我笑
  17. * <p>
  18. * Create by M ChangKe 2021/11/25 10:17
  19. *
  20. * 模拟spring读取配置文件以及创建Bean,引入三级缓存目的,存放ObjectFactory,单一自责
  21. *
  22. **/
  23. public class AnnotationConfigApplicationContext3 {
  24. /**
  25. * beanDefinitionMap 存放多个Bean定义 其中key为BeanName,value为BeanDefinition
  26. */
  27. private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
  28. /**
  29. * 单例池,如果创建的是单例对象则放入单例池中
  30. */
  31. private final Map<String, Object> singletonObjects = new HashMap<>(256);
  32. //早期Bean,还未被初始化以及属性赋值
  33. private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
  34. // 三级缓存
  35. public final Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>();
  36. //循环依赖标识
  37. public final Set<String> singletonsCurrentlyInCreation = new HashSet<>();
  38. /**
  39. * 通过构造方法传入配置类
  40. *
  41. * @param myConfigClass 配置类
  42. */
  43. public AnnotationConfigApplicationContext3(Class<?> myConfigClass) {
  44. scan(myConfigClass);
  45. refresh();
  46. }
  47. /**
  48. * 扫描配置类
  49. *
  50. * @param myConfigClass 配置类
  51. */
  52. private void scan(Class<?> myConfigClass) {
  53. if (myConfigClass.isAnnotationPresent(ComponentScan.class)) {
  54. //如果当前配置类上存在注解@ComponentScan,则代表当前类为配置类
  55. ComponentScan componentScan = myConfigClass.getAnnotation(ComponentScan.class);
  56. //获取value内容 com.itmck.mck
  57. String path = componentScan.value();
  58. path = path.replace(".", "/");//将com.itmck.mck-->com/itmck/mck
  59. //获取当前类加载器
  60. ClassLoader classLoader = this.getClass().getClassLoader();
  61. URL resource = classLoader.getResource(path);
  62. assert resource != null;
  63. File file = new File(resource.getFile());
  64. if (file.isDirectory()) {
  65. File[] files = file.listFiles();
  66. assert files != null;
  67. for (File f : files) {
  68. String absolutePath = f.getAbsolutePath();
  69. absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
  70. absolutePath = absolutePath.replace("\\", ".");
  71. Class<?> aClass = null;
  72. try {
  73. //通过类加载器,加载当前类信息
  74. aClass = classLoader.loadClass(absolutePath);
  75. } catch (ClassNotFoundException e) {
  76. e.printStackTrace();
  77. }
  78. assert aClass != null;
  79. if (aClass.isAnnotationPresent(Component.class)) {
  80. //如果当前类上存在存在@Component注解
  81. Component component = aClass.getAnnotation(Component.class);
  82. String beanName = component.value();
  83. if ("".equals(beanName)) {
  84. //如果没有给默认值,则使用类的首字母小写
  85. beanName = Introspector.decapitalize(aClass.getSimpleName());
  86. }
  87. //扫描的目的就是获取BeanDefinition
  88. BeanDefinition beanDefinition = new BeanDefinition();
  89. beanDefinition.setType(aClass);
  90. //判断是否存在Scope注解标记
  91. if (aClass.isAnnotationPresent(Scope.class)) {
  92. Scope scope = aClass.getAnnotation(Scope.class);
  93. String value = scope.value();
  94. beanDefinition.setScope(value);
  95. } else {
  96. beanDefinition.setScope("singleton");
  97. }
  98. beanDefinitionMap.put(beanName, beanDefinition);
  99. }
  100. }
  101. }
  102. }
  103. }
  104. /**
  105. * 创建Bean
  106. */
  107. private void refresh() {
  108. //在这里拿到beanDefinitionMap后即可对Bean进行创建
  109. beanDefinitionMap.forEach((beanName, beanDefinition) -> {
  110. if ("singleton".equals(beanDefinition.getScope())) {
  111. try {
  112. createBean(beanName, beanDefinition);
  113. } catch (Exception e) {
  114. e.printStackTrace();
  115. }
  116. }
  117. });
  118. }
  119. private Object createBean(String beanName, BeanDefinition beanDefinition) {
  120. //使用一级缓存解决循环依赖
  121. //在这里先判断一级缓存中是否存在,这里是解决循环依赖的关键,添加一个递归出口,防止无限递归
  122. Object singleton = getSingleton(beanName);
  123. if (singleton != null) {
  124. return singleton;
  125. }
  126. // 正在创建
  127. singletonsCurrentlyInCreation.add(beanName);
  128. Class<?> aClass = beanDefinition.getType();
  129. Object instance = null;
  130. if (aClass.isAnnotationPresent(Component.class)) {
  131. try {
  132. instance = aClass.getConstructor().newInstance();//无参构造创建Bean
  133. Object finalInstance = instance;
  134. singletonFactories.put(beanName, (ObjectFactory<?>)()-> new CglibProxyBeanPostProcessor().getEarlyBeanReference(finalInstance, beanName));
  135. earlySingletonObjects.put(beanName, instance);//这里新增二级缓存存放新鲜反射出来的纯净Bean
  136. Field[] declaredFields = aClass.getDeclaredFields();
  137. for (Field field : declaredFields) {
  138. field.setAccessible(true);
  139. field.set(instance, createBean(field.getName(), beanDefinitionMap.get(field.getName())));//在这里调用自身方法进行递归操作获取bean
  140. }
  141. } catch (Exception e) {
  142. e.printStackTrace();
  143. }
  144. }
  145. /**
  146. * 第四步: 初始化
  147. * 初始化就是设置类的init-method.这个可以设置也可以不设置. 我们这里就不设置了
  148. */
  149. // 由于递归完后A 还是原实例,, 所以要从二级缓存中拿到proxy 。
  150. if (earlySingletonObjects.containsKey(beanName)) {
  151. instance = earlySingletonObjects.get(beanName);
  152. }
  153. //将instance放入一级缓存,这里的Bean是完成了属性赋值,初始化等完整的单例Bean
  154. singletonObjects.put(beanName, instance);
  155. return instance;
  156. }
  157. public Object getSingleton(String beanName) {
  158. // 先从一级缓存中拿
  159. Object bean = singletonObjects.get(beanName);
  160. // 说明是循环依赖
  161. if (bean == null && singletonsCurrentlyInCreation.contains(beanName)) {
  162. bean = earlySingletonObjects.get(beanName);
  163. // 如果二级缓存没有就从三级缓存中拿
  164. if (bean == null) {
  165. // 从三级缓存中拿
  166. ObjectFactory<?> factory = singletonFactories.get(beanName);
  167. if (factory != null) {
  168. try {
  169. bean = factory.getObject(); // 拿到动态代理
  170. earlySingletonObjects.put(beanName, bean);
  171. //然后从二级缓存移除singletonFactory
  172. this.singletonFactories.remove(beanName);
  173. } catch (Exception e) {
  174. e.printStackTrace();
  175. }
  176. }
  177. }
  178. }
  179. return bean;
  180. }
  181. public Object getBean(String beanName) {
  182. if (!beanDefinitionMap.containsKey(beanName)) {
  183. throw new NullPointerException();
  184. }
  185. BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
  186. //如果是获取的Bean在单例池中存在则从单例池中取,否则新建
  187. if ("singleton".equals(beanDefinition.getScope())) {
  188. Object singletonBean = singletonObjects.get(beanName);
  189. if (singletonBean == null) {
  190. singletonBean = createBean(beanName, beanDefinition);
  191. }
  192. return singletonBean;
  193. } else {
  194. // 原型Bean
  195. return createBean(beanName, beanDefinition);
  196. }
  197. }
  198. /**
  199. * 通过通过BeanName一级Bean class获取Bean对象
  200. *
  201. * @param beanName Bean别名
  202. * @param tClass bean class类型
  203. * @param <T> 实例泛型
  204. * @return Bean对象
  205. */
  206. public <T> T getBean(String beanName, Class<T> tClass) {
  207. return tClass.cast(getBean(beanName));
  208. }
  209. }

运行结果与上述一致

总结

spring使用三级缓存解决循环依赖

  • 一级缓存能解决循环依赖,但是不能解决多线程环境下循环依赖
  • 二级缓存用于存放纯净Bean(实例化之后还未赋值以及初始化的Bean),并且能解决多线程下循环依赖.其次二级缓存也能解决aop
  • 三级缓存则是存放ObjectFactory用于创建aop之久的代理Bean.spring也是考虑职责单一

这样以来.职责明确.一级缓存单例池,二级缓存纯净Bean,三级缓存存放用于创建代理Bean的ObjectFactory.


在创建bean的时候, 在哪里创建的动态代理, 这个应该怎么回答呢?

很多人会说在初始化之后, 或者在实例化之后. 其实更严谨的说, 有两种情况: 第一种是在初始化之后调用 . 第二种是出现了循环依赖, 会在实例化之后调用