手写高仿真Spring框架
流行词:顶层设计 AOP 仿真
参考代码:https://gitee.com/li-lixiang/lean-spring-2.0.git
在前面的blog中,已经实现Spring IOC、DI、MVC,并调试代码展示前后交互结果。接下来学习Spring核心AOP,高仿手写AOP实现逻辑。
顶层设计
实现日志监控
用代理类进行解耦,AopProxy接口,有jdk实现方式与cglib实现方式
JDK实现AopProxy
定义AopProxy,用invoke方法增强原有方法,按照拦截器链去执行增强方法invoke。
AOP具体实现
在原有依赖注入的时候,需要增加AOP的情况,优化原有ApplicationContext->refresh->doAutowired->getBean->stantiateBean方法。当需要实例化的类符合切面表达式时,则进行切入(将用proxy增强后的实例代替)。
private Object instantiateBean(String beanName, GPBeanDefinition gpBeanDefinition) {
//1、拿到要实例化的对象的类名
String className = gpBeanDefinition.getBeanClassName();
//2、反射实例化,得到一个对象
Object instance = null;
try {
// gpBeanDefinition.getFactoryBeanName()
//假设默认就是单例,细节暂且不考虑,先把主线拉通
if(this.factoryBeanObjectCache.containsKey(className)){
instance = this.factoryBeanObjectCache.get(className);
}else {
Class<?> clazz = Class.forName(className);
instance = clazz.newInstance();
//当需要实例化的类符合切面表达式时,则进行切入(将用proxy增强后的实例代替)
GPAdvisedSupport config = instantionAopConfig(gpBeanDefinition);
config.setTargetClass(clazz);
config.setTarget(instance);
//符合PointCut的规则的话,创建代理对象
if(config.pointCutMatch()) {
instance = createProxy(config).getProxy();
}
this.factoryBeanObjectCache.put(className,instance);
this.factoryBeanObjectCache.put(gpBeanDefinition.getFactoryBeanName(),instance);
}
}catch (Exception e){
e.printStackTrace();
}
return instance;
}
初始化配置
instantionAopConfig
设置方法执行器链
在AdviceSupport->setTargetClass->parse方法中封装方法的拦截器链
作业:完成around切面方法拦截器
在切面中增加around方法,在service执行前和执行后执行around方法
实现步骤:
- 在application.properties中增加配置如下
#环绕执行 aspectAround=around
- 在GPAppConfig中增加aspectAround属性
private String aspectAround;
- 在GPAdvisedSupport中,增加拦截器链对around方法的切入
//around if(!(null == config.getAspectAround() || "".equals(config.getAspectAround()))) { //创建一个Advivce advices.add(new GPMethodAroundAdviceInterceptor(aspectMethods.get(config.getAspectAround()),aspectClass.newInstance())); }
- 创建类GPMethodAroundAdviceInterceptor
/** * Copyright (C), 2015-2020, XXX有限公司 * FileName: GPMethodAroundAdviceInterceptor * Author: lilx * Date: 2020/12/5 14:46 * Description: 环绕执行 * History: * <author> <time> <version> <desc> * 作者姓名 修改时间 版本号 描述 */ package com.gupaoedu.vip.spring.formework.aop.aspect; import com.gupaoedu.vip.spring.formework.aop.intercept.GPMethodInterceptor; import com.gupaoedu.vip.spring.formework.aop.intercept.GPMethodInvocation; import java.lang.reflect.Method; /** * 〈一句话功能简述〉<br> * 〈环绕执行〉 * * @author lilx * @create 2020/12/5 * @since 1.0.0 */ public class GPMethodAroundAdviceInterceptor extends GPAbstractAspectAdvice implements GPAdvice, GPMethodInterceptor { private GPJoinPoint joinPoint; public GPMethodAroundAdviceInterceptor(Method aspectMethod, Object aspectTarget) { super(aspectMethod, aspectTarget); } public void around(int i){ if(i==0){ System.out.println("GPMethodAroundAdviceInterceptor.around(...) start"); }else{ System.out.println("GPMethodAroundAdviceInterceptor.around(...) end"); } } @Override public Object invoke(GPMethodInvocation mi) throws Throwable { //从被织入的代码中才能拿到,JoinPoint this.joinPoint = mi; around(0); Object retVal = mi.proceed(); around(1); return retVal; } }
- 完成
运行结果:
把其他切面方法注释掉,如下日志