模拟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对象创建出来后:
2.1 Spring如何管理Bean
public class TestDemo {
public static void main(String[] args) {
ApplicationContext context=new AnnotationConfigApplicationContext("com.itmck.beans");
UserServiceImpl bean = context.getBean("userServiceImpl",UserServiceImpl.class);
bean.sayHi();
}
}
通过AnnotationConfigApplicationContext构造函数可知,我们要自定义spring的ioc容器,首先需要如下:
- 扫描配置生成BeanDefinitionMap
遍历BeanDefinitionMap创建Bean实例
public class AnnotationConfigApplicationContext {
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
}
2.2模拟spring
2.2.1 创建容器
我们创建了AnnotationConfigApplicationContext并且拥有一个扫描方法,一个刷新方法(创建Bean方法),还有getBean()方法.简单架子如下所示:
说明:
- AnnotationConfigApplicationContext(Class<?> myConfigClass) 通过构造方法传入配置类
- scan(myConfigClass) 扫描获取Bean定义
- refresh() 创建Bean
- 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() {
}
/**
* 通过BeanName获取Bean对象
*
* @param beanName Bean别名
* @return Bean对象
*/
public Object getBean(String beanName) {
return null;
}
/**
* 通过通过BeanName一级Bean class获取Bean对象
*
* @param beanName Bean别名
* @param tClass bean class类型
* @param <T> 实例泛型
* @return Bean对象
*/
public <T> T getBean(String beanName, Class<T> tClass) {
return tClass.cast(getBean(beanName));
}
}
<a name="YWJAA"></a>
### 2.2.2 定义注解
创建注解用于标记bean
- @Component
```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 Component {
String value() default "";
}
- @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 {
}
- @ComponentScan
```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;
/**
* 类扫描注解
*
* 太阳当空照,花儿对我笑
* <p>
* Create by M ChangKe 2021/9/11 16:44
**/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
String value() default "";
}
- @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 {
String value() default "";
}
<a name="D6GNa"></a>
### 2.2.3 创建BeanDefinition
扫描的目的就是扫描出BeanDefinition集合.BeanDefinition中包含了Bean类型,是否单例,是否懒加载....等
```java
package com.itmck.spring.core;
/**
* 太阳当空照,花儿对我笑
* <p>
* Create by M ChangKe 2021/9/11 17:28
**/
public class BeanDefinition {
/**
* bean类型
*/
private Class<?> type;
/**
* 是否是单例
*/
private String scope;
/**
* 是否是懒加载
*/
private boolean isLazy;
//省略getter/setter...
}
2.2.4 创建scan(),refresh()以及getBean()方法
package com.itmck.spring.core;
import com.itmck.spring.annotation.Component;
import com.itmck.spring.annotation.ComponentScan;
import com.itmck.spring.annotation.Scope;
import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
* 太阳当空照,花儿对我笑
* <p>
* Create by M ChangKe 2021/11/25 10:17
**/
public class AnnotationConfigApplicationContext {
/**
* beanDefinitionMap 存放多个Bean定义 其中key为BeanName,value为BeanDefinition
*/
private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
/**
* 单例池,如果创建的是单例对象则放入单例池中
*/
private final Map<String, Object> singletonObjects = new HashMap<>(256);
/**
* 通过构造方法传入配置类
*
* @param myConfigClass 配置类
*/
public AnnotationConfigApplicationContext(Class<?> myConfigClass) {
scan(myConfigClass);
refresh();
}
/**
* 扫描配置类
*
* @param myConfigClass 配置类
*/
private void scan(Class<?> myConfigClass) {
if (myConfigClass.isAnnotationPresent(ComponentScan.class)) {
//如果当前配置类上存在注解@ComponentScan,则代表当前类为配置类
ComponentScan componentScan = myConfigClass.getAnnotation(ComponentScan.class);
//获取value内容 com.itmck.mck
String path = componentScan.value();
path = path.replace(".", "/");//将com.itmck.mck-->com/itmck/mck
//获取当前类加载器
ClassLoader classLoader = this.getClass().getClassLoader();
URL resource = classLoader.getResource(path);
assert resource != null;
File file = new File(resource.getFile());
if (file.isDirectory()) {
File[] files = file.listFiles();
assert files != null;
for (File f : files) {
String absolutePath = f.getAbsolutePath();
absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
absolutePath = absolutePath.replace("\\", ".");
Class<?> aClass = null;
try {
//通过类加载器,加载当前类信息
aClass = classLoader.loadClass(absolutePath);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
assert aClass != null;
if (aClass.isAnnotationPresent(Component.class)) {
//如果当前类上存在存在@Component注解
Component component = aClass.getAnnotation(Component.class);
String beanName = component.value();
if ("".equals(beanName)) {
//如果没有给默认值,则使用类的首字母小写
beanName = Introspector.decapitalize(aClass.getSimpleName());
}
//扫描的目的就是获取BeanDefinition
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setType(aClass);
//判断是否存在Scope注解标记
if (aClass.isAnnotationPresent(Scope.class)) {
Scope scope = aClass.getAnnotation(Scope.class);
String value = scope.value();
beanDefinition.setScope(value);
} else {
beanDefinition.setScope("singleton");
}
beanDefinitionMap.put(beanName, beanDefinition);
}
}
}
}
}
/**
* 创建Bean
*/
private void refresh() {
//在这里拿到beanDefinitionMap后即可对Bean进行创建
beanDefinitionMap.forEach((beanName, beanDefinition) -> {
if ("singleton".equals(beanDefinition.getScope())) {
try {
Object bean = createBean(beanName, beanDefinition);
singletonObjects.put(beanName, bean);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private Object createBean(String beanName, BeanDefinition beanDefinition) {
Class<?> aClass = beanDefinition.getType();
Object instance = null;
if (aClass.isAnnotationPresent(Component.class)) {
try {
instance = aClass.getConstructor().newInstance();//无参构造创建Bean
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
String name = field.getName();
field.setAccessible(true);
field.set(instance, getBean(name));
}
} catch (Exception e) {
e.printStackTrace();
}
}
return instance;
}
/**
* 通过BeanName获取Bean对象
*
* @param beanName Bean别名
* @return Bean对象
*/
public Object getBean(String beanName) {
if (!beanDefinitionMap.containsKey(beanName)) {
throw new NullPointerException();
}
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
//如果是获取的Bean在单例池中存在则从单例池中取,否则新建
if ("singleton".equals(beanDefinition.getScope())) {
Object singletonBean = singletonObjects.get(beanName);
if (singletonBean == null) {
singletonBean = createBean(beanName, beanDefinition);
singletonObjects.put(beanName, singletonBean);
}
return singletonBean;
} else {
// 原型Bean
return createBean(beanName, beanDefinition);
}
}
/**
* 通过通过BeanName一级Bean class获取Bean对象
*
* @param beanName Bean别名
* @param tClass bean class类型
* @param <T> 实例泛型
* @return Bean对象
*/
public <T> T getBean(String beanName, Class<T> tClass) {
return tClass.cast(getBean(beanName));
}
}
到此位置,已经成功创建spring-m并初始化了相关方法.下一步就是应用案例测试
2.2.5 框架测试
2.2.5.1 创建 OneConfig.class
package com.itmck.one;
import com.itmck.spring.annotation.ComponentScan;
@ComponentScan("com.itmck.one")
public class OneConfig {
}
2.2.5.2 创建User对象
package com.itmck.one;
import com.itmck.spring.annotation.Autowired;
import com.itmck.spring.annotation.Component;
@Component
public class User {
public void run() {
System.out.println("User#run() is running...");
}
}
2.2.5.3 测试
package com.itmck.one;
import com.itmck.mck.MyConfig;
import com.itmck.mck.UserA;
import com.itmck.mck.UserB;
import com.itmck.spring.core.AnnotationConfigApplicationContext;
import com.itmck.spring.core.AnnotationConfigApplicationContext2;
/**
* 太阳当空照,花儿对我笑
* <p>
* Create by M ChangKe 2021/11/24 9:36
**/
public class TestDemo2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
User user = applicationContext.getBean("user", User.class);
user.run();
}
}
运行结果 User#run() is running…
注:上述代码是针对单个Bean进行扫描以及创建的简单流程梳理,但spring中远不止这些.
循环依赖
什么是循环依赖?
- 循环依赖就是A依赖B,B依赖A,互相依赖.主要分为一个类之间,两个类,多个类之间的依赖
- 循环依赖分为构造器依赖和属性依赖,众所周知的是Spring能够解决属性的循环依赖(set注入)
如何解决循环依赖?
简单来说,解决循环依赖就是加一个出口,方式死循环.
怎样增加出口?简单说就是增加一个缓存
模拟spring解决循环依赖
spring中使用三级缓存解决循环依赖
- singletonObjects 单例池
- earlySingletonObjects 纯净bean(刚实例化的Bean)
- 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() {
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(){
System.out.println("UserB");
} //略get/set
}
<a name="e6Zj3"></a>
### 一级缓存
<a name="omP4n"></a>
#### 一级缓存如何解决?
首先引入 ** private final Map<String, Object> singletonObjects = new HashMap<>(256); 作为一级缓存**<br />修改createBean()方法是关键.因为A依赖B,在创建A的时候给A属性赋值,这时需要创建B.然后创建B又依赖到A....循环往复.怎么办????
- **调用createBean()进行递归创建**
- **防止递归循环需要添加一个出口函数**
```java
private Object createBean(String beanName, BeanDefinition beanDefinition) {
//使用一级缓存解决循环依赖
//1================在这里先判断一级缓存中是否存在,这里是解决循环依赖的关键,添加一个递归出口,防止无限递归====
Object singleton = getSingleton(beanName);
if (singleton != null) {
return singleton;
}
//================在这里先判断一级缓存中是否存在,这里是解决循环依赖的关键,添加一个递归出口,防止无限递归=====
Class<?> aClass = beanDefinition.getType();
Object instance = null;
if (aClass.isAnnotationPresent(Component.class)) {
try {
instance = aClass.getConstructor().newInstance();//无参构造创建Bean
//2==================将instance放入一级缓存======================
singletonObjects.put(beanName,instance);//将instance放入一级缓存
//==================将instance放入一级缓存======================
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
//**在这里调用自身方法进行递归操作获取bean**
field.set(instance,createBean(field.getName(), beanDefinitionMap.get(field.getName())));
}
} catch (Exception e) {
e.printStackTrace();
}
}
return instance;
}
public Object getSingleton(String beanName) {
if (singletonObjects.containsKey(beanName)) {
return singletonObjects.get(beanName);
}
return null;
}
测试
package com.itmck;
import com.itmck.mck.MyConfig;
import com.itmck.mck.UserA;
import com.itmck.mck.UserB;
import com.itmck.one.OneConfig;
import com.itmck.one.User;
import com.itmck.spring.core.AnnotationConfigApplicationContext;
import com.itmck.spring.core.AnnotationConfigApplicationContext2;
/**
* 太阳当空照,花儿对我笑
* <p>
* Create by M ChangKe 2021/11/24 9:36
**/
public class MckSpringApplication {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext2 applicationContext = new AnnotationConfigApplicationContext2(MyConfig.class);
UserA userA = applicationContext.getBean("userA", UserA.class);
UserB userB1 = userA.getUserB();
System.out.println("UserA#userB.run()");
userB1.run();
UserB userB = applicationContext.getBean("userB", UserB.class);
UserA userA1 = userB.getUserA();
System.out.println("UserB#userA.run()");
userA1.run();
}
}
结果如下,表示循环依赖已经解决
UserA#userB.run()
UserB
UserB#userA.run()
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) {
return singleton;
} Class<?> aClass = beanDefinition.getType(); Object instance = null; if (aClass.isAnnotationPresent(Component.class)) {
try {
instance = aClass.getConstructor().newInstance();//无参构造创建Bean
earlySingletonObjects.put(beanName, instance);//这里新增二级缓存存放新鲜反射出来的纯净Bean
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
field.set(instance, createBean(field.getName(), beanDefinitionMap.get(field.getName())));//在这里调用自身方法进行递归操作获取bean
}
} catch (Exception e) {
e.printStackTrace();
}
} //初始化在这里 //init——— singletonObjects.put(beanName, instance);//将instance放入一级缓存,这里的Bean是完成了属性赋值,初始化等完整的单例Bean return instance; }
/**
- 通过判断 *
- @param beanName Bean别名
- @return Bean对象
*/
public Object getSingleton(String beanName) {
if (singletonObjects.containsKey(beanName)) {
}else if (earlySingletonObjects.containsKey(beanName)){return singletonObjects.get(beanName);
} return null;//新增二级缓存后,一级缓存没有从二级缓存中取
return earlySingletonObjects.get(beanName);
}
上述代码注意:注意:earlySingletonObjects.put(beanName, instance)与singletonObjects.put(beanName, instance)位置<br />最后运行结果与上述一致
<a name="I2Okh"></a>
### 总结:一级缓存和二级缓存的作用
- 一级缓存: 解决循环依赖的问题,但是不能完全解决,因为存在多线程问题
- 二级缓存: 在创建实例bean和放入到一级缓存之间还有一段间隙. 如果在这之间从一级缓存拿实例, 肯定是返回null的. 为了避免这个问题, 增加了二级缓存.(多线程问题)
<a name="Ca19M"></a>
## 到这里可以发现使用二级缓存就可以解决循环依赖中Aop的问题.那么为什Spring使用了三级缓存?
<a name="DsJGU"></a>
## <br />aop创建时机
**我们在创建bean 的时候, 会有很多Bean的后置处理器BeanPostProcessor. 如果有AOP, 会在什么时候创建呢? 在初始化以后, 调用BeanPostProcessor创建动态代理?**
结合上面的代码, 我们想一想, 其实在初始化以后创建动态代理就晚了. 为什么呢? 因为, 如果有循环依赖, 在初始化之后才调用, 那就不是动态代理. 其实我们这时候应该在实例化之后, 放入到二级缓存之前调用. 如果判断有循环依赖此时进行AOP,那么最佳位置应该是在判断二级缓存存在说明是循环依赖,此时进行aop然后将新的实例放入二级缓存
修改后代码如下:
```java
public Object getSingleton(String beanName) {
if (singletonObjects.containsKey(beanName)) {
return singletonObjects.get(beanName);
}else if (earlySingletonObjects.containsKey(beanName)){
//新增二级缓存后,一级缓存没有从二级缓存中取
/**
* 第一次创建bean是正常的instanceBean. 他并不是循环依赖. 第二次进来判断, 这个bean已经存在了, 就说明是循环依赖了
* 这时候通过动态代理创建bean. 然后将这个bean在放入到二级缓存中覆盖原来的instanceBean.
* 这样我们在循环依赖的时候就完成了AOP的创建. 这是在二级缓存里创建的AOP
*/
Object instance = new CglibProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName), beanName);
earlySingletonObjects.put(beanName, instance);
return earlySingletonObjects.get(beanName);
}
return null;
}
创建CglibProxyBeanPostProcessor
package com.itmck.mck;
import com.itmck.spring.annotation.Component;
import com.itmck.spring.core.SmartInstantiationAwareBeanPostProcessor;
import com.itmck.spring.proxy.MyEnhancer;
import com.itmck.spring.proxy.MyProxy;
import net.sf.cglib.proxy.Enhancer;
/**
* 太阳当空照,花儿对我笑
* <p>
* Create by M ChangKe 2021/9/11 18:08
**/
@Component
public class CglibProxyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 假设A被切点命中 需要创建代理 @PointCut("execution(* *..InstanceA.*(..))")
/**
* 这里, 我们简单直接判断bean是不是InstanceA实例, 如果是, 就创建动态代理.
* 这里没有去解析切点, 解析切点是AspectJ做的事.
*/
if (bean instanceof UserA) {
MyEnhancer myEnhancer = new MyEnhancer(new MyProxy(),bean);
Enhancer enhancer = myEnhancer.getEnhancer();
bean = enhancer.create();
}
return bean;
}
}
MyEnhancer
使用cglib代理需要引入pom
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
package com.itmck.spring.proxy;
import net.sf.cglib.proxy.Enhancer;
/**
* 太阳当空照,花儿对我笑
* <p>
* Create by M ChangKe 2021/11/25 15:11
**/
public class MyEnhancer {
private final MyProxy myProxy;
private final Object object;
public MyEnhancer(MyProxy myProxy, Object object) {
this.myProxy = myProxy;
this.object = object;
}
public Enhancer getEnhancer(){
Enhancer enhancer = new Enhancer(); // 通过CGLIB动态代理获取代理对象的过程
enhancer.setSuperclass(object.getClass()); // 设置enhancer对象的父类
enhancer.setCallback(myProxy); // 设置enhancer的回调对象
return enhancer;
}
}
MyProxy implements MethodInterceptor
package com.itmck.spring.proxy;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MyProxy implements MethodInterceptor {
/**
*
* @param o cglib生成的代理对象
* @param method 被代理对象的方法
* @param objects 传入方法的参数
* @param methodProxy 代理的方法
* @return
* @throws Throwable
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("这里可以插入执行关键代码之前的逻辑");
Object o1 = methodProxy.invokeSuper(o, objects);//关键代码:
System.out.println("这里可以插入执行关键代码之后的逻辑");
return o1;
}
}
此时运行代码结果
UserA#userB.run()
UserB
UserB#userA.run()
这里可以插入执行关键代码之前的逻辑
UserA
这里可以插入执行关键代码之后的逻辑
通过上面发现:如果在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) {
return singleton;
} // 正在创建 singletonsCurrentlyInCreation.add(beanName);
Class<?> aClass = beanDefinition.getType(); Object instance = null; if (aClass.isAnnotationPresent(Component.class)) {
try {
instance = aClass.getConstructor().newInstance();//无参构造创建Bean
//在这里直接进行aop不合理,因为没有进行判断,所以要先判断是否需要进行代理,如果需要才进行aop,在哪里判断?
//当有循环依赖的时候,二级缓存不为null,所以在getSingleton()中判断
//instance = new JdkProxyBeanPostProcessor().getEarlyBeanReference(instance, beanName);
//实例化之后保 级缓存就是存函数接口的
singletonFactories.put(beanName,() -> new CglibProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName), beanName));
earlySingletonObjects.put(beanName, instance);//这里新增二级缓存存放新鲜反射出来的纯净Bean
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
field.set(instance, createBean(field.getName(), beanDefinitionMap.get(field.getName())));//在这里调用自身方法进行递归操作获取bean
}
} catch (Exception e) {
e.printStackTrace();
}
} /**
- 第四步: 初始化
初始化就是设置类的init-method.这个可以设置也可以不设置. 我们这里就不设置了 */
//正常的代理实在初始化之后,就是这里进行,但是如果存在循环依赖必须在实例化之后进行 //instance = new JdkProxyBeanPostProcessor().getEarlyBeanReference(instance, beanName);
// 由于递归完后A 还是原实例,, 所以要从二级缓存中拿到proxy 。
if (earlySingletonObjects.containsKey(beanName)) {
instance = earlySingletonObjects.get(beanName);
}
//将instance放入一级缓存,这里的Bean是完成了属性赋值,初始化等完整的单例Bean
singletonObjects.put(beanName, instance);
return instance;
}
<a name="ElS8z"></a>
### <br />getSingleton()修改如下
```java
public Object getSingleton(String beanName) {
// 先从一级缓存中拿
Object bean = singletonObjects.get(beanName);
// 说明是循环依赖
if (bean == null && singletonsCurrentlyInCreation.contains(beanName)) {
bean = earlySingletonObjects.get(beanName);
// 如果二级缓存没有就从三级缓存中拿
if (bean == null) {
// 从三级缓存中拿
ObjectFactory<?> factory = singletonFactories.get(beanName);
if (factory != null) {
try {
bean = factory.getObject(); // 拿到动态代理
earlySingletonObjects.put(beanName, bean);
//然后从二级缓存移除singletonFactory
this.singletonFactories.remove(beanName);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return bean;
}
完整代码
package com.itmck.spring.core;
import com.itmck.mck.CglibProxyBeanPostProcessor;
import com.itmck.spring.annotation.Component;
import com.itmck.spring.annotation.ComponentScan;
import com.itmck.spring.annotation.Scope;
import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* 太阳当空照,花儿对我笑
* <p>
* Create by M ChangKe 2021/11/25 10:17
*
* 模拟spring读取配置文件以及创建Bean,引入三级缓存目的,存放ObjectFactory,单一自责
*
**/
public class AnnotationConfigApplicationContext3 {
/**
* beanDefinitionMap 存放多个Bean定义 其中key为BeanName,value为BeanDefinition
*/
private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
/**
* 单例池,如果创建的是单例对象则放入单例池中
*/
private final Map<String, Object> singletonObjects = new HashMap<>(256);
//早期Bean,还未被初始化以及属性赋值
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
// 三级缓存
public final Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>();
//循环依赖标识
public final Set<String> singletonsCurrentlyInCreation = new HashSet<>();
/**
* 通过构造方法传入配置类
*
* @param myConfigClass 配置类
*/
public AnnotationConfigApplicationContext3(Class<?> myConfigClass) {
scan(myConfigClass);
refresh();
}
/**
* 扫描配置类
*
* @param myConfigClass 配置类
*/
private void scan(Class<?> myConfigClass) {
if (myConfigClass.isAnnotationPresent(ComponentScan.class)) {
//如果当前配置类上存在注解@ComponentScan,则代表当前类为配置类
ComponentScan componentScan = myConfigClass.getAnnotation(ComponentScan.class);
//获取value内容 com.itmck.mck
String path = componentScan.value();
path = path.replace(".", "/");//将com.itmck.mck-->com/itmck/mck
//获取当前类加载器
ClassLoader classLoader = this.getClass().getClassLoader();
URL resource = classLoader.getResource(path);
assert resource != null;
File file = new File(resource.getFile());
if (file.isDirectory()) {
File[] files = file.listFiles();
assert files != null;
for (File f : files) {
String absolutePath = f.getAbsolutePath();
absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
absolutePath = absolutePath.replace("\\", ".");
Class<?> aClass = null;
try {
//通过类加载器,加载当前类信息
aClass = classLoader.loadClass(absolutePath);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
assert aClass != null;
if (aClass.isAnnotationPresent(Component.class)) {
//如果当前类上存在存在@Component注解
Component component = aClass.getAnnotation(Component.class);
String beanName = component.value();
if ("".equals(beanName)) {
//如果没有给默认值,则使用类的首字母小写
beanName = Introspector.decapitalize(aClass.getSimpleName());
}
//扫描的目的就是获取BeanDefinition
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setType(aClass);
//判断是否存在Scope注解标记
if (aClass.isAnnotationPresent(Scope.class)) {
Scope scope = aClass.getAnnotation(Scope.class);
String value = scope.value();
beanDefinition.setScope(value);
} else {
beanDefinition.setScope("singleton");
}
beanDefinitionMap.put(beanName, beanDefinition);
}
}
}
}
}
/**
* 创建Bean
*/
private void refresh() {
//在这里拿到beanDefinitionMap后即可对Bean进行创建
beanDefinitionMap.forEach((beanName, beanDefinition) -> {
if ("singleton".equals(beanDefinition.getScope())) {
try {
createBean(beanName, beanDefinition);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private Object createBean(String beanName, BeanDefinition beanDefinition) {
//使用一级缓存解决循环依赖
//在这里先判断一级缓存中是否存在,这里是解决循环依赖的关键,添加一个递归出口,防止无限递归
Object singleton = getSingleton(beanName);
if (singleton != null) {
return singleton;
}
// 正在创建
singletonsCurrentlyInCreation.add(beanName);
Class<?> aClass = beanDefinition.getType();
Object instance = null;
if (aClass.isAnnotationPresent(Component.class)) {
try {
instance = aClass.getConstructor().newInstance();//无参构造创建Bean
Object finalInstance = instance;
singletonFactories.put(beanName, (ObjectFactory<?>)()-> new CglibProxyBeanPostProcessor().getEarlyBeanReference(finalInstance, beanName));
earlySingletonObjects.put(beanName, instance);//这里新增二级缓存存放新鲜反射出来的纯净Bean
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
field.set(instance, createBean(field.getName(), beanDefinitionMap.get(field.getName())));//在这里调用自身方法进行递归操作获取bean
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 第四步: 初始化
* 初始化就是设置类的init-method.这个可以设置也可以不设置. 我们这里就不设置了
*/
// 由于递归完后A 还是原实例,, 所以要从二级缓存中拿到proxy 。
if (earlySingletonObjects.containsKey(beanName)) {
instance = earlySingletonObjects.get(beanName);
}
//将instance放入一级缓存,这里的Bean是完成了属性赋值,初始化等完整的单例Bean
singletonObjects.put(beanName, instance);
return instance;
}
public Object getSingleton(String beanName) {
// 先从一级缓存中拿
Object bean = singletonObjects.get(beanName);
// 说明是循环依赖
if (bean == null && singletonsCurrentlyInCreation.contains(beanName)) {
bean = earlySingletonObjects.get(beanName);
// 如果二级缓存没有就从三级缓存中拿
if (bean == null) {
// 从三级缓存中拿
ObjectFactory<?> factory = singletonFactories.get(beanName);
if (factory != null) {
try {
bean = factory.getObject(); // 拿到动态代理
earlySingletonObjects.put(beanName, bean);
//然后从二级缓存移除singletonFactory
this.singletonFactories.remove(beanName);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return bean;
}
public Object getBean(String beanName) {
if (!beanDefinitionMap.containsKey(beanName)) {
throw new NullPointerException();
}
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
//如果是获取的Bean在单例池中存在则从单例池中取,否则新建
if ("singleton".equals(beanDefinition.getScope())) {
Object singletonBean = singletonObjects.get(beanName);
if (singletonBean == null) {
singletonBean = createBean(beanName, beanDefinition);
}
return singletonBean;
} else {
// 原型Bean
return createBean(beanName, beanDefinition);
}
}
/**
* 通过通过BeanName一级Bean class获取Bean对象
*
* @param beanName Bean别名
* @param tClass bean class类型
* @param <T> 实例泛型
* @return Bean对象
*/
public <T> T getBean(String beanName, Class<T> tClass) {
return tClass.cast(getBean(beanName));
}
}
运行结果与上述一致
总结
spring使用三级缓存解决循环依赖
- 一级缓存能解决循环依赖,但是不能解决多线程环境下循环依赖
- 二级缓存用于存放纯净Bean(实例化之后还未赋值以及初始化的Bean),并且能解决多线程下循环依赖.其次二级缓存也能解决aop
- 三级缓存则是存放ObjectFactory用于创建aop之久的代理Bean.spring也是考虑职责单一
这样以来.职责明确.一级缓存单例池,二级缓存纯净Bean,三级缓存存放用于创建代理Bean的ObjectFactory.
在创建bean的时候, 在哪里创建的动态代理, 这个应该怎么回答呢?
很多人会说在初始化之后, 或者在实例化之后. 其实更严谨的说, 有两种情况: 第一种是在初始化之后调用 . 第二种是出现了循环依赖, 会在实例化之后调用