AOP主线源码

137 阅读3分钟

测试类代码

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

  • 弱引用WeakReferenceGC时如果对象只有弱引用,会被回收。
  • 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");
}

  • 代理类中的方法PermissionServiceEnhancerBySpringCGLIBEnhancerBySpringCGLIB4d61ccdd
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对象做了一个缓存。