为什么可以这么做,因为我们的bean是单例的,而且是字段注入(setter注入)的,单例意味着只需要创建一次对象,后面就可以从缓存中取出来,字段注入,意味着我们无需调用构造方法进行注入。
如果是原型bean,那么就意味着每次都要去创建对象,无法利用缓存;
如果是构造方法注入,那么就意味着需要调用构造方法注入,也无法利用缓存。
需要aop怎么办?我们上面的方案看起来很美好,但是还有一个问题,如果我们的bean创建出来,还要做一点加工,怎么办?也许,你没有理解这句话的意思,再说的明白点,如果beanA和【beanB的代理对象】循环依赖,或者【beanA的代理对象】和beanB循环依赖,再或者【beanA的代理对象】和【beanB的代理对象】循环依赖,怎么办?
这里说的创建代理对象仅仅是“加工”的其中一种可能。
遇到这种情况,我们总不能把创建完的对象直接扔到缓存把?我们这么做的话,如果【beanA的代理对象】和【beanB的代理对象】循环依赖,我们最终获取的beanA中的beanB还是beanB,并非是beanB的代理对象。
聪明的你,一定在想,这还不简单吗:
我们创建完对象后,判断这个对象是否需要代理,如果需要代理,创建代理对象,然后把代理对象放到earlySingletonObjects不就OJ8K了?
就像这样:
这确实可以,但是,这违反了Spring的初衷,Spring的初衷是希望在bean生命周期的最后几步才去aop,如果像上面说的这么做,就意味着一旦创建完对象,Spring就会去aop了,这就违反了Spring的初衷,所以Spring并没有这么做。
但是如果真的出现了aop bean循环依赖,就没办法了,只能先去aop,但是如果没有出现循环依赖,Spring并不希望在这里就进行aop,所以Spring引入了Map<String, ObjectFactory<?>>,ObjectFactory是一个函数式接口,可以理解为工厂方法,当创建完对象后,把【获得这个对象的工厂方法】放入这个map,等真的发生循环依赖,就去执行这个【获得这个对象的工厂方法】,获取加工完成的对象。
下面直接放出代码:
public class Cycle { // 单例池,里面放的是完整的bean,已完成填充属性 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(); // 存放的是 加工bean的工厂方法 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(); // 存放的是提前暴露出来的bean,没有经历过spring完整的生命周期,没有填充属性 private final Map<String, Object> earlySingletonObjects = new HashMap<>(); private final Set<String> singletonsCurrentlyInCreation = new HashSet<>(); static Map<String, Class<?>> map = new HashMap<>(); static { map.put("orderService", OrderService.class); map.put("userService", UserService.class); } public void init() { for (Map.Entry<String, Class<?>> stringClassEntry : map.entrySet()) { createBean(stringClassEntry.getKey()); } } private Object createBean(String beanName) { Object instance = null; try { instance = map.get(beanName).getConstructor().newInstance(); } catch (Exception ex) { } Object finalInstance = instance; this.singletonFactories.put(beanName, () -> { // 创建代理对象 return finalInstance; }); populateBean(instance); this.singletonObjects.put(beanName, instance); return instance; } public Object getBean(String beanName) { // 尝试从singletonObjects中取, Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject != null) { return singletonObject; } // 尝试从earlySingletonObjects取 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject != null) { return singletonObject; } // 尝试从singletonFactories取出工厂方法 ObjectFactory<?> objectFactory = this.singletonFactories.get(beanName); if (objectFactory != null) { singletonObject = objectFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); return singletonObject; } return createBean(beanName); } private void populateBean(Object object) { Field[] fields = object.getClass().getDeclaredFields(); for (Field field : fields) { if (field.getAnnotation(CodeBearAutowired.class) != null) { Object value = getBean(field.getName()); try { field.setAccessible(true); field.set(object, value); } catch (IllegalAccessException ignored) { } } } } }