原创

探秘Spring AOP(下)

探秘Spring AOP(上) http://debuggg.com/article/258

JDK与Cglib代理对比

  • JDK只能针对右接口的类的接口方法进行动态代理
  • Cglib基于继承来实现代理,无法对static、final类进行代理
  • Cglib基于集成来实现代理,无法对private,static方法进行代理

Spring如何创建代理bean

  • AbstractAutoProxyCreator
    • wrapIfNecessary
    • createProxy
    • getProxy
  • ProxyFactory
    • createAopProxy
  • ProxyCreatorSupport
    • createAopProxy
  • DefaultAopProxyFactory

以下是DefaultAopProxyFactory的jdk源代码

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    public DefaultAopProxyFactory() {
    }

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
            return new JdkDynamicAopProxy(config);
        } else {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
            } else {
                return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
            }
        }
    }

可以看出:里面经过判断,有两种生成代理对象的方式:其实也就是JDK和Cglib

  • new JdkDynamicAopProxy(config))
  • new ObjenesisCglibAopProxy(config)

总结:

  • 如果目标对象实现了接口,则默认采用JDK动态代理

  • 如果目标对象没有实现接口,则采用Cglib进行动态代理

  • 如果目标对象实现了几口,且强制cglib代理,则使用cglib代理

    • @SpringBootApplication
      //强制使用cglib代理
      @EnableAspectJAutoProxy(proxyTargetClass = true)
      public class AopDemoApplication {
          public static void main(String[] args){
              SpringApplication.run(AopDemoApplicaiton.class,args)
          }
      }
      

AOP如何链式调用

责任链设计模式:

什么是责任链模式?

责任链模式就是采用一个抽象类,该类有一个自己类的对象(此对象用于存储链式的下一个节点),这样,就可以在调用该类功能之后,再拿到下一个类的引用,并调用下一个类的方法(类似于递归)

简单的实现方式(有冗余代码,类之间有关联关系,不推荐):

一个Handler(抽象类),一个Client(客户端类)

Handler.java

public abstract class Handler {
    private Handler succesor;

    public Handler getSuccesor() {
        return succesor;
    }

    public void setSuccesor(Handler succesor) {
        this.succesor = succesor;
    }

    public void execute(){
        handleProcess();
        if(succesor != null){
            succesor.execute();
        }
    }

    protected abstract void handleProcess();
}

Client.java

public class Client {
    static class HandlerA extends Handler {
        @Override
        protected void handleProcess() {
            System.out.println("handler by a");
        }
    }

    static class HandlerB extends Handler{
        @Override
        protected void handleProcess() {
            System.out.println("handler by b");
        }
    }

    static class HandlerC extends Handler{
        @Override
        protected void handleProcess() {
            System.out.println("handler by c");
        }
    }

    public static void main(String[] args) {
        HandlerA handlerA = new HandlerA();
        HandlerB handlerB = new HandlerB();
        HandlerC handlerC = new HandlerC();

        handlerA.setSuccesor(handlerB);
        handlerB.setSuccesor(handlerC);

        handlerA.execute();
    }

}

解耦的方式

通过一个List来存储对象集合,然后使用游标的形式(下标++)来完成遍历

ChainHandler.java

public abstract class ChainHandler {
    public void execute(Chain chain){
        handleProcess();
        chain.proceed();
    }

    abstract void handleProcess();
}

Chain.java

public class Chain {
    private List<ChainHandler> list;

    public Chain(List<ChainHandler> list) {
        this.list = list;
    }

    int index = 0;

    public void proceed(){
        if(index >= list.size()){
            return;
        }
        this.list.get(index++).execute(this);
    }
}

ChainClient.java

public class ChainClient {
    static class ChainHandlerA extends ChainHandler{
        @Override
        void handleProcess() {
            System.out.println("chainhandler by chain a");
        }
    }
    static class ChainHandlerB extends ChainHandler{
        @Override
        void handleProcess() {
            System.out.println("chainhandler by chain b");
        }
    }
    static class ChainHandlerC extends ChainHandler{
        @Override
        void handleProcess() {
            System.out.println("chainhandler by chain c");
        }
    }

    public static void main(String[] args) {
        new Chain(Arrays.asList(
            new ChainHandlerA(),
            new ChainHandlerB(),
            new ChainHandlerC()
        )).proceed();
    }
}

Around环绕方式的参数:ProceedingJoinPoint的几个方法介绍

proceed():执行方法

getSignature():获取声明信息

Signature类如下:

public interface Signature {
    String toString();

    String toShortString();

    String toLongString();
    //方法名
    String getName();
    //权限修饰符
    int getModifiers();
    //返回值类型
    Class getDeclaringType();

    String getDeclaringTypeName();
}

getArgs():获取目标方法的参数列表

getTarget():返回被织入增强处理的目标对象

getThis():返回AOP框架为目标对象生成的代理对象

总结

要点清单

  • AOP适用范围及优势
  • AOP的概念及Spring切面表达式
  • AOP的实现原理及运用

使用SpringAOP的注意事项/坑

  • 不宜把重要的业务逻辑放到aop中处理
  • 无法拦截static、final、private方法
  • 无法拦截内部方法调用,因为内部调用时this.invoke(),
    • 解决方案:内部调用的时候,就不要使用this,可以从ioc容器里面去拿Bean,那个bean就是被代理的,就可以实现内部方法调用了
正文到此结束
本文目录