测试类代码
PermissionService serviceObj = new PermissionService();
ProgramaticAspect programaticAspect = new ProgramaticAspect();
// create a factory that can generate a proxy for the given target object
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(serviceObj);
// proxyFactory.addAspect(ProgramaticAspect.class);
proxyFactory.addAspect(programaticAspect);
// proxyFactory.setProxyTargetClass(true);//是否需要使用CGLIB代理
PermissionService proxy = proxyFactory.getProxy();
proxy.dataAccessOperation(22,"abd");
创建AOP工厂
- new AspectJProxyFactory(serviceObj)
setInterfaces
接口轮询挨个处理
获取对象的所有接口,是spring提供的方法,我们写代码的时候如果有需要,也可以直接用。
setTarget
只是单纯的存到了变量。
往工厂添加Aspect
WeakReference & WeakHashMap
- 弱引用WeakReference:GC时如果对象只有弱引用,会被回收。
- WeakHashMap :key是WeakReference
获取Aspect元数据
AspectMetadata构造函数
代码
流程图
- 从类获取AjType
只是单纯的从WeakHashMap里存取数据,实际就是传入的class
- 类是否Aspect
clazz.getAnnotation(Aspect.class) != null
- 存在DeclarePrecedence
从该类递归找,是否类上有注解DeclarePrecedence,是否方法上有注解ajcDeclarePrecedence
- AjTypeImpl.getPerClause.getKind()
根据Aspect注解的value,组装不同的PerClause实例。Spring支持4种:
-
- SINGLETON(默认的)
- PERTARGET
- PERTHIS
- PERTYPEWITHIN
如果不在这四种之列,都抛错
添加Advisor
new SingletonMetadataAwareAspectInstanceFactory(aspectInstance, aspectName)
就是一些简单的赋值
addAdvisorsFromAspectInstanceFactory
getAdvisors
getAdvisorMethods
ReflectionUtils.doWithMethods也是spring提供的现成方法,传入类,回调方法,方法筛选条件,就可以对符合条件的方法做相同的事情。
- 同一个Aspect中的advisor排序逻辑
getAdvisor
- new InstantiationModelAwarePointcutAdvisorImpl
先普通赋值一堆变量
如果是PerThis、PerTarget或者PerWithin类型的:
普通的:
几个new实际调用的都是公共父类AbstractAspectJAdvice的构造函数。所以只有AfterReturning和AfterThrowing多一步工作。
校验Aspect
从工厂获取代理对象
PermissionService proxy = proxyFactory.getProxy();
createAopProxy()
分成3个动作,activate,getAopProxyFactory以及createAopProxy。
activate()基本上啥都没做
搜了下暂时没有找到添加监听器的代码,可能是为了方便业务需要的话,业务自行添加。
getAopProxyFactory
createAopProxy
CGLIB代理
JDK动态代理
NativeDetector.inNativeImage() 系统参数org.graalvm.nativeimage.imagecode
getProxy()
CGLIB
createProxyClassAndInstance(enhancer, callbacks);
这里很有意思,甚至针对不同jvm都有不同策略。
JDK
执行业务方法
CGLIB
实际执行的是代理实例的方法。
可以加系统参数把生成的代理类文件都生成出来(因为我是在测试类里调用的,所以放在static代码块里。如果是写main函数测的,在main函数里加就可以了):
static{
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\git\aspectj-demo\target");
}
- 代理类中的方法PermissionService4d61ccdd
public final String dataAccessOperation(int var1, String var2) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$dataAccessOperation$0$Method, new Object[]{new Integer(var1), var2}, CGLIB$dataAccessOperation$0$Proxy) : super.dataAccessOperation(var1, var2);
}
- DynamicAdvisedInterceptor.intercept
获取执行链
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)
CglibMethodInvocation & proceed()
如果是toString或者hash等方法,就走上面的,只处理参数,再调用原本方法。
其他的就先创建CglibMethodInvocation,再调用proceed方法
创建CglibMethodInvocation的话基本上就是一些普通的赋值,此外的话还使用BridgeMethodResolver拿到了对应方法的Method对象。
JDK动态代理
强制使用CGLIB
其他知识
生成代理类到文件
static {
System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", true);
//放这里不行,时序不对,得传参-Djdk.proxy.ProxyGenerator.saveGeneratedFiles=true
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\git\aspectj-demo\target");
}
BridgeMethodResolver
在org.springframework.core里,这个类是spring提供的,为了方便Method反射,把一些Method对象做了一个缓存。