1.项目架构:
本文只提供重点代码,具体实现请参考文末源码。
采用三级缓存解决循环依赖,原理参考 手写spring框架预备知识:三级缓存解决循环依赖问题
2. 启动类
在main函数中注册自己,并添加ComponentScan注解
@ComponentScan
public class SpringApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = new ApplicationContext(SpringApplication.class);
}
}
3.封装bean信息
需要封装的bean类型
//注册配置信息
private Class<?> configClazz;
/**
* 注册配置类解析器
*/
private BeanDefinitionReader reader;
/**
* 存放所有的bean对象原始信息
*/
private Map<String, BeanDefinition> beanDefinitionMap;
/**
* 存放beanPostProcessor集合,自定义bean的前后处理逻辑
*/
private CopyOnWriteArrayList<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
/**
* 存放aopProcessor集合,自定义切面逻辑
*/
private CopyOnWriteArrayList<AopProcessor> aopProcessors = new CopyOnWriteArrayList<>();
/**
* 一级缓存,存放经过完整生命周期的单例bean对象
*/
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
/**
* 二级缓存,存放提前进行aop代理的bean对象
*/
private ConcurrentHashMap<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();
/**
* 三级缓存,存放构造器创建的原始bean对象
*/
private ConcurrentHashMap<String, Object> singletonFactories = new ConcurrentHashMap<>();
/**
* 记录正在创建中的bean,用于判断是否出现循环依赖
*/
private Set<String> creatingSet = Collections.newSetFromMap(new ConcurrentHashMap<>());
完成具体的封装操作
public ApplicationContext(Class<?> configClazz) {
this.configClazz = configClazz;
//初始化spring容器
refresh();
}
public void refresh() {
//解析配置文件扫描路径
reader = new BeanDefinitionReader(configClazz);
//封装class文件为beanDefinition对象
beanDefinitionMap = reader.loadBeanDefinitions();
// System.out.println("beanDefinitionMap = " + beanDefinitionMap);
// 注册所有的BeanPostProcessor,需要提前创建对象
loadBeanPostProcessors();
// System.out.println("beanPostProcessors = " + beanPostProcessors);
//注册所有的AopProcessor,需要提前创建对象
loadAopProcessor();
// System.out.println("aopProcessors = " + aopProcessors);
//提前创建所有的bean对象
doCreate();
}
3.创建bean对象
一个完整的生命周期需要经过构造器创建→依赖注入→Aop处理
private void doCreate() {
for (String beanName : beanDefinitionMap.keySet()) {
createBean(beanDefinitionMap.get(beanName));
}
}
/**
* 核心功能,根据beanDefinition创建对应的对象
*
* @param beanDefinition
* @return 创建后的对象
*/
private Object createBean(BeanDefinition beanDefinition) {
Class<?> clazz = beanDefinition.getClazz();
String beanName = beanDefinition.getBeanName();
//如果已经被提前创建则直接返回
if (singletonObjects.containsKey(beanName)) {
return singletonObjects.get(beanName);
}
Object instance = null;
try {
//1.构造器创建原始bean
instance = clazz.getDeclaredConstructor().newInstance();
//放入creatingSet和三级缓存中
singletonFactories.put(beanName, instance);
creatingSet.add(beanName);
//2.如果不是懒加载则执行依赖注入
if (!beanDefinition.isLazy()) {
dependencyInjection(clazz, instance);
}
//3.进行Aop
//先判断是否已经提前aop过
if (earlySingletonObjects.containsKey(beanName)) {
instance = earlySingletonObjects.get(beanName);
} else {
instance = createBeanAfterDI(beanDefinition);
}
//4.放入单例池并清空二级缓存
singletonObjects.put(beanName, instance);
earlySingletonObjects.remove(beanName);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException("创建" + beanName + "对象失败");
}
return instance;
}
3.1 依赖注入
未出现循环依赖则递归创建对象,出现循环依赖则提前进行Aop创建对象,这里是解决循环依赖的关键。
private void dependencyInjection(Class<?> clazz, Object instance) {
for (Field declaredField : clazz.getDeclaredFields()) {
//属性上有依赖注入的注解
if (declaredField.isAnnotationPresent(AutoWired.class)) {
String fieldBeanName = BeanUtils.getDefaultBeanName(declaredField.getType());
// System.out.println("fieldBeanName = " + fieldBeanName);
AutoWired autoWired = declaredField.getAnnotation(AutoWired.class);
BeanDefinition fieldBeanDefinition = beanDefinitionMap.get(fieldBeanName);
declaredField.setAccessible(true);
try {
if (singletonObjects.containsKey(fieldBeanName)) {
//从单例池中寻找注入的对象
declaredField.set(instance, singletonObjects.get(fieldBeanName));
} else if (earlySingletonObjects.containsKey(fieldBeanName)) {
//从二级缓存中寻找注入的对象
declaredField.set(instance, earlySingletonObjects.get(fieldBeanName));
} else {
//创建新对象
//判断该对象是否正在创建
if (!creatingSet.contains(fieldBeanName)) {
//没有循环依赖则直接创建对象
Object bean = createBean(fieldBeanDefinition);
declaredField.set(instance, bean);
} else {
//出现循环依赖则提前进行aop创建对象
Object earlyBean = createBeanAfterDI(fieldBeanDefinition);
declaredField.set(instance, earlyBean);
}
}
} catch (IllegalAccessException e) {
if (autoWired.require()) {
throw new RuntimeException("给" + clazz.getSimpleName() + "注入" + fieldBeanName + "失败");
}
}
}
}
}
3.2 Aop动态代理
有接口则用jdk动态代理,否则使用cjlib动态代理,此处是创建bean的最后一步,是执行扩展功能的地方,Aop本质上其实也是一种扩展功能。
private Object createBeanAfterDI(BeanDefinition beanDefinition) {
String beanName = beanDefinition.getBeanName();
Class<?> clazz = beanDefinition.getClazz();
try {
//从三级缓存中获取原始bean对象
Object bean = singletonFactories.get(beanName);
//执行bean初始化前逻辑
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
beanPostProcessor.postProcessBeforeInitialization(bean, beanName);
}
//执行自定义初始化
if (InitializingBean.class.isAssignableFrom(clazz)) {
InitializingBean initializingBean = (InitializingBean) bean;
initializingBean.afterPropertiesSet();
}
//执行bean初始化前的逻辑
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
beanPostProcessor.postProcessAfterInitialization(bean, beanName);
}
//-------------------------AOP入口-----------------------
for (AopProcessor aopProcessor : aopProcessors) {
String pointCut = aopProcessor.getPointCut();
if (BeanUtils.aopMatch(pointCut, clazz.getName())) {
//匹配到切面,则创建代理对象执行切面逻辑
if (clazz.getInterfaces().length > 0) {
//如果有接口,使用jdk动态代理
JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy(bean, aopProcessor);
bean = jdkDynamicProxy.getProxyBean();
} else {
//没有接口用cglib
CglibProxy cglibProxy = new CglibProxy(bean, aopProcessor);
bean = cglibProxy.getProxyBean();
}
}
}
//向二级缓存添加bean对象
earlySingletonObjects.put(beanName, bean);
//删除三级缓存的bean对象和creatingSet
singletonFactories.remove(beanName);
creatingSet.remove(beanName);
return bean;
} catch (Exception e) {
throw new RuntimeException(beanName + "的Aop处理失败");
}
}
4.结果测试
该部分进行结果的测试,测试spring容器的ioc和aop功能以及循环依赖的问题。测试结构如下;
User类
@Component
@Scope("prototype")//测试循环依赖的时候需要取消注释
public class UserImpl implements User {
@AutoWired
private CglibTest cglibTest;
public void print(){
System.out.println("User中注入了:" + cglibTest);
}
}
UserService类
@Service
public class UserServiceImpl implements UserService {
@AutoWired
private User user;
public void print(){
System.out.println("userService中注入了:" + user);
user.print();
}
}
CglibTest类
@Component
public class CglibTest {
@AutoWired
private UserService userService;
public void print() {
System.out.println("cglibTest中注入了:" + userService);
userService.print();
}
}
4.1 测试ioc容器(未开启Aop和功能扩展类)
启动类
@ComponentScan
public class SpringApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = new ApplicationContext(SpringApplication.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanDefinitionNames) {
System.out.println("beanName = " + beanName);
Object bean1 = applicationContext.getBean(beanName);
Object bean2 = applicationContext.getBean(beanName);
System.out.println("bean1 = " + bean1);
System.out.println("bean2 = " + bean2);
System.out.println("-----------------------------");
}
// System.out.println("循环依赖测试开始*******************************");
// CglibTest cglibTest = (CglibTest) applicationContext.getBean("cglibTest");
// cglibTest.print();
// System.out.println("循环依赖测试结束*******************************");
}
}
结果:
分析:结果中可以看到所有的bean都被注册进单例池中,但是User类由于指定了属性为原型类,所以两次获得的bean对象并不相同,并且缓存中只有一级缓存中还有对象,其余缓存均已清空。
4.2 测试Aop和循环依赖
添加aop类和扩展类,只给impl包下的对象执行aop操作
@Component
@Aspect
public class AopTest {
@PointCut("spring.test.impl.*")
public void pointcut(){}
@Before
public void before(ProceedingJoinPoint joinPoint) {
String beanName = joinPoint.getBeanName();
System.out.println(beanName + "aop方法执行前");
}
@After
public void after(ProceedingJoinPoint joinPoint){
String beanName = joinPoint.getBeanName();
System.out.println(beanName + "aop方法执行后");
}
}
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println(beanName + "初始化前");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println(beanName + "初始化后");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
启动类:
@ComponentScan
public class SpringApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = new ApplicationContext(SpringApplication.class);
// String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
// for (String beanName : beanDefinitionNames) {
// System.out.println("beanName = " + beanName);
// Object bean1 = applicationContext.getBean(beanName);
// Object bean2 = applicationContext.getBean(beanName);
// System.out.println("bean1 = " + bean1);
// System.out.println("bean2 = " + bean2);
// System.out.println("-----------------------------");
// }
System.out.println("循环依赖测试开始*******************************");
CglibTest cglibTest = (CglibTest) applicationContext.getBean("cglibTest");
cglibTest.print();
System.out.println("循环依赖测试结束*******************************");
}
}
结果:
分析:所有对象在初始化前后都执行了我们自定义的扩展功能,并且每个impl包下的方法在执行前后都会执行自定义aop逻辑。而从打印结果中来看,即使出现循环依赖现象,每一个bean对象都能成功的注入想要的属性,并且初始化顺序也符合最开始的创建逻辑,即A要注入B,B要注入C,C要注入A,判断A和C出现循环依赖,则需要提前创建A,然而B和C没有出现循环依赖,则先创建C,再创建B。其中A对应CglibTest,B对应UserService,C对应User。