spring高质量系列-AOP

spring支持的AOP的方式有:AspecJ,ProxyFactoryBean,ProxyFactory
其中:AspectJ是目前大家最常用的 起到集成AspectJ和Spring,ProxyFactoryBean是将我们的AOP和IOC融合起来,而ProxyFactory 则是只能通过代码硬编码进行编写 一般都是给spring自己使用

AnnotationAwareAspectJAutoProxyCreator 通过继承SmartInstantiationAwareBeanPostProcessor 来将AsepctJ融入spring 内部生成的代理对象是采用ProxyFactory

涉及到的几个关键类

ProxyConfig:为上面三个类提供配置属性
AdvisedSupport:继承ProxyConfig,实现了Advised。封装了对通知(Advise)和通知器(Advisor)的操作
ProxyCreatorSupport:继承AdvisedSupport,其帮助子类(上面三个类)创建JDK或者cglib的代理对象
Advised:可以获取拦截器和其他 advice, Advisors和代理接口

涉及到的几个关键概念

Advice:通知,定义在连接点做什么,比如我们在方法前后进行日志打印
pointcut:切点,决定advice应该作用于那个连接点,比如根据正则等规则匹配哪些方法需要增强
Pointcut 目前有getClassFilter(类匹配),getMethodMatcher(方法匹配),Pointcut TRUE (全匹配)
JoinPoint:连接点,就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的钱、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。其他如AspectJ还可以让你在构造器或属性注入时都行,不过那不是咱们关注的,只要记住,和方法有关的前前后后都是连接点。
advisor:把pointcut和advice连接起来

ProxyFactory

 public static void main(String[] args) {
        MarshallService marshallService = new MarshallService();
        ProxyFactory proxyFactory = new ProxyFactory(marshallService);
        proxyFactory.addAdvice(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] args, Object target) throws Throwable {
                System.out.println("MethodBeforeAdvice1 method=" + method.getName());
            }
        });


        proxyFactory.addAdvice(new MarshallAdvice());
        MarshallService proxy = (MarshallService) proxyFactory.getProxy();
        proxy.say1();
        proxy.say2();
    }

1.ProxyFactory proxyFactory = new ProxyFactory(marshallService); 分别设置AdvisedSupport类的targetSource,interfaces,并且清空methodCache

targetSource:我们需要代理的原始对象,interfaces:该原始对象实现的接口,methodCache:保存某个方法对应的advisor chain List
3.proxyFactory.addAdvice(new MarshallAdvice()); 添加advice,先判断advice的类型,然后将其包装成不同的advisor,一般都是默认的DefaultPointcutAdvisor,然添加进入集合advisors,并且更新相应的数组advisorArray(为了方便操作)
4 . MarshallService proxy = (MarshallService) proxyFactory.getProxy(); 获取代理对象
5 . 首先调用了父类ProxyCreatorSupport的createAopProxy去激活(即激活相关的监听事件),然后获取AopProxyFactory,通过这factory获取AopProxy(ObjenesisCglibAopProxy,JdkDynamicAopProxy),通过AopProxy获取真正的代理对象

cglib

6.AopProxy.getProxy()方法对于cglib主要是设置enhancer的Callback,这些callback会在代理对象执行方法时候调用,callback的类型有
MethodInterceptor:这就是我们aop,因为 MethodInterceptor的效率不高,它需要产生不同类型的字节码,并且需要生成一些运行时对象(InvocationHandler就不需要),所以Cglib提供了其它的接口供我们选择
NoOp:简单地把方法调用委托给了被代理类的原方法(本例中是Person),不做任何其它的操作
LazyLoader:,它也提供了一个方法:Object loadObject() throws Exception;,loadObject()方法会在第一次被代理类的方法调用时触发,它返回一个代理类的对象,这个对象会被存储起来然后负责所有被代理类方法的调用
Dispatcher :也是提供了loadObject()方法,这个方法同样地返回一个代理对象,这个对象同样可以代理原方法的调用。不过它们之间不同的地方在于,Dispatcher的loadObject()方法在每次发生对原方法的调用时都会被调用并返回一个代理对象来调用原方法。也就是说Dispatcher的loadObject()方法返回的对象并不会被存储起来,可以类比成Spring中的Prototype类型,而LazyLoader则是lazy模式的Singleton
InvocationHandler:它的使用方式和MethodInterceptor差不多,所有对invoke()方法的参数proxy对象的方法调用都会被委托给同一个InvocationHandler,所以可能会导致无限循环
FixedValue:同样也提供了一个loadObject()方法,不过这个方法返回的不是代理对象,而是原方法调用想要的结果。也就是说,在这个Callback里面,看不到任何原方法的信息,也就没有调用原方法的逻辑,不管原方法是什么都只会调用loadObject()并返回一个结果。听起来可能有些没有,但是配合CllbackFilter可以强制使某个方法返回固定的值,并且带来的开销很小。需要注意的是,如果loadObject()方法的返回值并不能转换成原方法的返回值类型,那么会抛出类型转换异常。

jdk

  1. 除了生成字节码不一样其他的都类似 都是调用方法时候被拦截然后通过ProxyCreatorSupport类getInterceptorsAndDynamicInterceptionAdvice获取每个方法对应的advice
    8.spring 的AspectJ代理好像就是使用ProxyFactory去生成代理

ProxyFactoryBean

具体代码如下

    MarshallProxyFactoryBean marshallProxyFactoryBean = (MarshallProxyFactoryBean)applicationContext.getBean("&MarshallProxyFactoryBean");
下面三个属性 也可以通过xml配置
        //advic
        marshallProxyFactoryBean.setInterceptorNames(new String[]{"MarshallAdvice"});
        //代理类实现的接口,如果没有就是cglib
        marshallProxyFactoryBean.setProxyInterfaces(new Class[]{MarshallInterface.class});
        //需要生成proxy的对象
        marshallProxyFactoryBean.setTarget(new MarshallService());
具体生成proxy
        marshallProxyFactoryBean.getObject();
  1. getObject 就是通过initializeAdvisorChain初始化advisor
    2.通过advisorAdapterRegistry 包装咱们的advice,逻辑是如果本身就是advisor 直接返回,如果是MethodInterceptor,包装成DefaultPointcutAdvisor(拦截所有方法),看是否是属于AdvisorAdapter(MethodBeforeAdviceAdapter,AfterReturningAdviceAdapter,ThrowsAdviceAdapter),也包装成,包装成DefaultPointcutAdvisor
    3.最终都是调用CglibAopProxy或者JdkDynamicAopProxy 获取动态代理对象

AspectJProxyFactory

就是通过@AspectJ 获取对应的class 然后从class里面获取Pointcut 即获取匹配哪些类的哪些方法的规则,然后在获取各个advice 组装起来
最终通过getProxy获取代理对象 通过父类统一初始化advisor和method的映射关系

总结 AspectJProxyFactory,ProxyFactoryBean,ProxyFactory 大体逻辑都是填充AdvisedSupport(ProxyCreatorSupport是其子类)的,然后交给父类ProxyCreatorSupport,然后得到JDK或者CGLIB的AopProxy,代理调用时候被invoke或者intercept方法拦截 (分别在JdkDynamicAopProxy和ObjenesisCglibAopProxy的中)并且在这两个方法中调用ProxyCreatorSupport的getInterceptorsAndDynamicInterceptionAdvice方法去初始化advice和各个方法直接映射关系并缓存

你可能感兴趣的:(spring高质量系列-AOP)