• Spring AOP面向切面编程


    目录

    1.AOP概览

    AOP(Aspect Oriented Programming),什么是面向切面编程?

    1)AOP是一种编程范式,不是编程语言

    编程范式概览

    • 面向过程编程

    • 面向对象编程

    • 函数式编程

    • 事件驱动编程

    • 面向切面编程

     

    2)AOP是为了解决特定问题,不是解决所有问题。AOP是OOP的补充,不是替代关系。

    AOP的初衷是关注点隔离

    切面隔离:将功能性需求和非功能性需求分离开来

    做系统设计时,通常将大系统做分解,按业务功能分解成一个个低耦合、高内聚的模块。

    分解后发现有趣的事情是,有些东西是公用的,或者跨越了多个模块。

    • 日志:对特定的操作输出日志来记录

    • 安全:在操作之前进行操作检查

    • 性能:统计每个方法的执行时间

    • 事务:方法开始前开始事务,方法结束后提交或回滚事务

    我们可以将这些通用模块写好,在实现业务模块的时候去调用就好了。

    但是,功能是实现了,但是业务代码中大部分都是日志、性能、事务等,几乎把真正的业务代码给淹没了!

    最好的方法是将日志、安全、事务这样的代码和业务代码完全隔离开来,因为他们的关注点和业务代码的关注点完全不同。

    他们之间的关系应该是正交的。如果把这个业务功能看成一层层面包的话, 这些日志/安全/事务 像不像一个个“切面”(Aspect) ?

    如果我们能让这些“切面“能和业务独立,  并且能够非常灵活的“织入”到业务方法中, 那就实现了面向切面编程(AOP)!

     

    AOP的应用场景

    • 审计日志:对特定的操作输出日志来记录

    • 权限控制:在操作之前进行操作检查

    • 性能监控:统计每个方法的执行时间

    • 事务控制:方法开始前开始事务,方法结束后提交或回滚事务

    • 缓存控制

    • 异常处理

     

    根据织入时机的不同,AOP可以分为以下3种实现方式

    1)编译期织入(AspectJ)

    2)类加载时织入(AspectJ 5+)

    3)运行时织入(Spring AOP)

     

    2.Spring AOP的使用举例

    Spring AOP实现权限控制:只有管理员可以进行修改操作

    @Service
    public class ProductService {
        public Product get(Long id) {
            System.out.println("get product id = " + id);
            return new Product(id, "aaa");
        }
        @AdminOnly
        public void insert(Product product) {
            System.out.println("insert product");
        }
    ​
        @AdminOnly
        public void delete(Long id) {
            System.out.println("delete product id = " + id);
        }
    }
    @Aspect  //1)表明这个是一个切面类
    @Component
    public class SecurityAspect {
        //2)切入点
        @Pointcut("@annotation(AdminOnly)")
        public void adminOnly() {
        }
        //3)通知
        @Before("adminOnly()")
        public void check() {
            String user = CurrentUserHolder.get();
            if (!"admin".equals(user)) {
                throw new RuntimeException("operation not allow");
            }
        }
    }

     

    PointCut切入点

    PointCut(切入点):一个方法或一组方法(可以通过通配符支持)。

    比如,“对于com.xxx这个包中所有类的execute方法” 。

    Advice通知

    Advice(通知):方法调用时需要做什么。比如,”在方法调用之前/之后 , 需要执行xxx操作“ 。

    具体的通知类型包括:

    • before:前置通知,在方法调用前执行。

    • after returning:方法返回通知,在方法正常返回时执行。

    • throwing:方法异常通知,在方法抛出异常时执行。

    • after:方法结束通知,包含了方法正常返回和方法抛出异常两种情况。

    • around:环绕通知。

     

    3.Spring AOP的实现原理

    3.1运行时织入

    根据织入时机的不同,AOP可以分为以下3种实现方式

    1)编译期织入(AspectJ)

    2)类加载时织入(AspectJ 5+)

    3)运行时织入(Spring AOP)

    Spring中的AOP实现是在运行时织入的。

    运行时织入是如何实现的呢?通过动态代理的方式。

    3.1.1代理模式

    什么是代理模式

    调用方Caller通过Proxy代理对象间接地与目标对象Target交互。

    两个关键点:

    1)Client客户端通过接口引用操作的对象Subject。且RealSubject真实对象和Proxy代理对象实现了同一个接口

    2)Proxy代理对象会持有RealSubject真实对象的引用,真正要执行的方法委托给真实对象来执行,自己则执行一些额外的逻辑

    public interface Subject {
        void request() throws Exception;
    }
    public class RealSubject implements Subject {
    ​
        public void request() {
            System.out.println("RealSubject execute request()");
        }
    }
    public class Proxy implements Subject {
    ​
        private RealSubject realSubject;
    ​
        public Proxy(RealSubject realSubject) {
            this.realSubject = realSubject;
        }
        /**
        * 在真实对象request()方法之前或之后,可以执行一些额外的操作
        */
        public void request() throws Exception{
            System.out.println("before");
            try {
                realSubject.request();
            } catch (Exception e) {
                System.out.println("ex:" + e.getMessage());
                throw e;
            } finally {
                System.out.println("after");
            }
        }
    }
    public class Client {
    ​
        public static void main(String[] args) throws Exception{
            Subject subject = new Proxy(new RealSubject());
            subject.request();
        }
    } 

    运行结果

    before
    RealSubject execute request()
    after

    上面代码展示的是静态代理的实现。

    静态代理有如下缺点:

    1)假设真实对象有100方法,则代理对象需要对100个方法进行委托。

    2)且在这100个方法中代理对象执行的额外逻辑是一样的。

    就像下面代码展示的那样。

    public interface Subject {
        void request() throws Exception;
        void request2() throws Exception;
        void request3() throws Exception;
        void request4() throws Exception;
     
    public class RealSubject implements Subject {
    ​
        public void request() {
            System.out.println("RealSubject execute request()");
        }
    ​
        public void request2() {
            System.out.println("RealSubject execute request2()");
        }
    ​
        public void request3() {
            System.out.println("RealSubject execute request3()");
        }
    ​
        public void request4() {
            System.out.println("RealSubject execute request4()");
        }
    }
    public class Proxy implements Subject {
    ​
        private RealSubject realSubject;
    ​
        public Proxy(RealSubject realSubject) {
            this.realSubject = realSubject;
        }
    ​
        public void request() throws Exception{
            System.out.println("before");
            try {
                realSubject.request();
            } catch (Exception e) {
                System.out.println("ex:" + e.getMessage());
                throw e;
            } finally {
                System.out.println("after");
            }
        }
        //静态代理的缺点:
        //由于Subject添加了request2()、request3()、request4()方法,代理类中也要实现相应的方法
        //而且代理对象在request2()、request3()、request4()等方法中额外需要执行的逻辑都是一样的。
        public void request2() throws Exception{
            System.out.println("before");
            try {
                realSubject.request2();
            } catch (Exception e) {
                System.out.println("ex:" + e.getMessage());
                throw e;
            } finally {
                System.out.println("after");
            }
        }
    ​
        public void request3() throws Exception{
            System.out.println("before");
            try {
                realSubject.request3();
            } catch (Exception e) {
                System.out.println("ex:" + e.getMessage());
                throw e;
            } finally {
                System.out.println("after");
            }
        }
    ​
        public void request4() throws Exception{
            System.out.println("before");
            try {
                realSubject.request4();
            } catch (Exception e) {
                System.out.println("ex:" + e.getMessage());
                throw e;
            } finally {
                System.out.println("after");
            }
        }   
    } 

    由于静态代理有上面的缺点,就产生了动态代理技术。

    动态代理有两种实现方式

    1)基于接口实现:JDK动态代理

    2)基于继承实现:cglib动态代理

    3.1.2 JDK动态代理

    将上面的静态代理实现,改为使用JDK动态代理后,代码如下。

    public class JdkProxySubject implements InvocationHandler {
    ​
        private RealSubject realSubject;
    ​
        public JdkProxySubject(RealSubject realSubject) {
            this.realSubject = realSubject;
        }
    ​
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("before");
            Object result = null;
            try {
               result = method.invoke(realSubject, args);
            } catch (Exception e) {
                throw e;
            } finally {
                System.out.println("after");
            }
            return result;
        }
    }
    public class Client {
    ​
        public static void main(String[] args) throws Exception {
            //通过调用Proxy.newProxyInstance生成代理对象
            //方法参数为:1)classLoader  2)要代理的接口 3)代理对象的InvocationHandler
            //(通过方法参数也可以看出来,JDK代理只能通过代理接口来来实现动态代理)
            Subject subject = (Subject) Proxy.newProxyInstance(Client.class.getClassLoader(),
                    new Class[]{Subject.class}, new JdkProxySubject(new RealSubject()));
            //调用代理对象的request方法。
            //(根据InvocationHandler接口的定义,可以知道实际调用的是JdkProxySubject里的invoke方法)
            subject.request();
        }
    }

    3.1.3 cglib动态代理

    将上面的静态代理实现,改为使用cglib动态代理后,代码如下。

    public class DemoMethodInterceptor implements MethodInterceptor {
    ​
        @Override
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("before in cglib");
            Object result = null;
            try {
                //注意:调用的是proxy.invokeSuper来调用目标类的方法
                result = methodProxy.invokeSuper(o, args);
            } catch (Exception e) {
                System.out.println("ex:" + e.getMessage());
                throw e;
            } finally {
                System.out.println("after in cglib");
            }
            return null;
        }
    }
    public class Client {
    ​
        public static void main(String[] args) throws Exception {
            //创建一个增强器
            Enhancer enhancer = new Enhancer();
            //设置目标类
            enhancer.setSuperclass(RealSubject.class);
            //设置拦截对象
            enhancer.setCallback(new DemoMethodInterceptor());
            //生成代理对象
            Subject subject = (Subject) enhancer.create();
            //调用代理对象的request方法
            subject.request();
        }
    }

    3.1.4 Spring如何创建代理bean

    动态代理有两种实现方式,JDK动态代理和cglib动态代理,那Spring是如何选择的?

     

    ProxyFactoryBean的getObject()方法

    @Override
      public Object getObject() throws BeansException {
        initializeAdvisorChain();
        //对singleton和prototype的类型进行区分,生成对应的proxy
        if (isSingleton()) {
          return getSingletonInstance();
        }
        else {
          if (this.targetName == null) {
            logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
                "Enable prototype proxies by setting the 'targetName' property.");
          }
          return newPrototypeInstance();
        }
      }

    getSingletonInstance()方法

      /**
       * Return the singleton instance of this class's proxy object,
       * lazily creating it if it hasn't been created already.
       * @return the shared singleton proxy
       */
      private synchronized Object getSingletonInstance() {
        if (this.singletonInstance == null) {
          this.targetSource = freshTargetSource();
          if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
            // Rely on AOP infrastructure to tell us what interfaces to proxy.
            Class<?> targetClass = getTargetClass();
            if (targetClass == null) {
              throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
            }
            setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
          }
          // Initialize the shared singleton instance.
          super.setFrozen(this.freezeProxy);
          this.singletonInstance = getProxy(createAopProxy());
        }
        return this.singletonInstance;
      }

    其中,生成代理实例的代码是这句。

    this.singletonInstance = getProxy(createAopProxy());

    可以将这句代码拆成下面两句。

    1)aopProxy = createAopProxy()。

    2)this.singletonInstance = getProxy(aopProxy) 。

    createAopProxy()

    createAopProxy()的方法如下。

    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
          activate();
        }
        return getAopProxyFactory().createAopProxy(this);
      }

    其中getAopProxyFactory()返回一个AopProxyFactory。在这里,返回的是AopProxyFactory的默认实现DefaultAopProxyFactory。

    DefaultAopProxyFactory的createAopProxy()方法

    /**
     * Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy
     * or a JDK dynamic proxy.
     *
     * <p>Creates a CGLIB proxy if one the following is true for a given
     * {@link AdvisedSupport} instance:
     * <ul>
     * <li>the {@code optimize} flag is set
     * <li>the {@code proxyTargetClass} flag is set
     * <li>no proxy interfaces have been specified
     * </ul>
     *
     * <p>In general, specify {@code proxyTargetClass} to enforce a CGLIB proxy,
     * or specify one or more interfaces to use a JDK dynamic proxy.
     */
    @SuppressWarnings("serial")
    public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    ​
      @Override
      public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        //如果满足下面3个条件,将使用cglib动态代理
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
          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.");
          }
          //以下两种情况除外
          //targetClass是接口   或者  targetClass本身就是使用jdk动态代理的proxy
          if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
          }
          return new ObjenesisCglibAopProxy(config);
        }
        //否则,使用jdk动态代理
        else {
          return new JdkDynamicAopProxy(config);
        }
      }
    ​
      /**
       * Determine whether the supplied {@link AdvisedSupport} has only the
       * {@link org.springframework.aop.SpringProxy} interface specified
       * (or no proxy interfaces specified at all).
       */
      private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        Class<?>[] ifcs = config.getProxiedInterfaces();
        return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
      }
    }
     

     

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

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

    3)如果目标对象实现了接口,且强制cglib代理,则使用cglib动态代理

    getProxy(aopProxy)

    protected Object getProxy(AopProxy aopProxy) {
        return aopProxy.getProxy(this.proxyClassLoader);
    }

    如果入参中的aopProxy是JdkDynamicAopProxy的实例的话,会调用JdkDynamicAopProxy类中的方法。

    如果入参中的aopProxy是ObjenesisCglibAopProxy的实例的话,会调用ObjenesisCglibAopProxy类中的方法。

    JdkDynamicAopProxy.getProxy()方法

    final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
      @Override
      public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
          logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
      }
    }
     

    可以看到JdkDynamicAopProxy实现了InvocationHandler接口,并通过Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)生成代理对象。

    ObjenesisCglibAopProxy.getProxy()方法

    与下面代码逻辑类似。

            Enhancer enhancer = new Enhancer();
            //设置目标类
            enhancer.setSuperclass(RealSubject.class);
            //设置拦截对象
            enhancer.setCallback(new DemoMethodInterceptor());
            //生成代理对象
            Subject subject = (Subject) enhancer.create();
            //调用代理对象的request方法
            subject.request();

     

    4.Spring AOP的实现原理

    4.1 链式调用

    多个AOP 切面是如何叠加起作用的?

    public class Proxy implements Subject {
    ​
        private RealSubject realSubject;
    ​
        public Proxy(RealSubject realSubject) {
            this.realSubject = realSubject;
        }
        /**
        * realSubject.request()是目标方法
        * 在目标方法调用前、调用后、发生异常时,都需要被拦截
        * aop是如何实现将这些调用串起来的?
        */
        public void request() throws Exception{
            //before
            //记录调用次数
            //权限控制,仅管理员可以操作
            //开启事务
            System.out.println("before:记录调用次数"); 
            System.out.println("before:进行权限控制,仅管理员可以进行后续操作");
            System.out.println("before:开启事务");
            try {
                realSubject.request();
            } catch (Exception e) {
                //afterThrowing
                //事务失败,回滚操作
                System.out.println("afterThrowing:事务失败,回滚操作 ex:" + e.getMessage());
                throw e;
            } finally {
                //afterReturning
                //事务成功,提交操作
                System.out.println("afterReturning:事务成功,提交操作");
            }
        }
    }

    4.1.1 职责链模式

    4.1.1.1 V1

    public abstract class Handler {
    ​
        private Handler successor;
    ​
        public Handler getSuccessor() {
            return successor;
        }
    ​
        public void setSuccessor(Handler successor) {
            this.successor = successor;
        }
    ​
        //对外暴露的方法
        public void execute() {
            handleProcess();
            if (successor != null) {
                successor.execute();
            }
        }
    ​
        // 需要子类实现
        protected abstract void handleProcess();
    }
    public class Client {
    ​
        static class HandlerA extends Handler {
    ​
            @Override
            protected void handleProcess() {
                System.out.println("handle by a");
            }
        }
    ​
        static class HandlerB extends Handler {
    ​
            @Override
            protected void handleProcess() {
                System.out.println("handle by b");
            }
        }
    ​
        static class HandlerC extends Handler {
    ​
            @Override
            protected void handleProcess() {
                System.out.println("handle by c");
            }
        }
        //缺点:各个handler之间的顺序需要显式指定
        //handlerA.setSuccessor(handlerB);
        //handlerB.setSuccessor(handlerC);
        public static void main(String[] args) {
            HandlerA handlerA = new HandlerA();
            HandlerB handlerB = new HandlerB();
            HandlerC handlerC = new HandlerC();
    ​
            handlerA.setSuccessor(handlerB);
            handlerB.setSuccessor(handlerC);
    ​
            handlerA.execute();
        }
    }

    运行结果

    handle by a
    handle by b
    handle by c

    4.1.1.2 V2

    public abstract class ChainHandler {
    ​
        public void execute(Chain chain) {
            handleProcess();
            chain.proceed();
        }
    ​
        protected abstract void handleProcess();
    }
    public class Chain {
        //将各个handler保存在handlers这个list中
        //各个handler之间的执行顺序由chain来维持
        private List<ChainHandler> handlers;
        private int index = 0;
    ​
        public Chain(List<ChainHandler> handlers) {
            this.handlers = handlers;
        }
    ​
        public void proceed() {
            if (index >= handlers.size()) {
                return;
            }
            handlers.get(index++).execute(this);
        }
    }
    public class ChainClient {
        static class ChainHandlerA extends ChainHandler {
            @Override
            protected void handleProcess() {
                System.out.println("handle by a");
            }
        }
        static class ChainHandlerB extends ChainHandler {
            @Override
            protected void handleProcess() {
                System.out.println("handle by b");
            }
        }
        static class ChainHandlerC extends ChainHandler {
            @Override
            protected void handleProcess() {
                System.out.println("handle by c");
            }
        }
    ​
        public static void main(String[] args) {
            /**
            在list中的顺序决定了handler的执行顺序
            */
            List<ChainHandler> handlers = Arrays.asList(
                    new ChainHandlerA(),
                    new ChainHandlerB(),
                    new ChainHandlerC()
            );
    ​
            Chain chain = new Chain(handlers);
            chain.proceed();
        }
    }

    运行结果

    handle by a
    handle by b
    handle by c

    4.1.2 Spring内部实现

    以JDK动态代理为例,调用目标对象的方法时,实际上调用的是代理对象的invoke方法。

    JdkDynamicAopProxy的invoke方法

     
     
    /**
     * Implementation of {@code InvocationHandler.invoke}.
     * <p>Callers will see exactly the exception thrown by the target,
     * unless a hook method throws an exception.
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    MethodInvocation invocation;
    Object oldProxy = null;
    boolean setProxyContext = false;
    ​
    TargetSource targetSource = this.advised.targetSource;
    Class<?> targetClass = null;
    Object target = null;
    ​
    try {
    if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
    // The target does not implement the equals(Object) method itself.
    return equals(args[0]);
    }
    else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
    // The target does not implement the hashCode() method itself.
    return hashCode();
    }
    else if (method.getDeclaringClass() == DecoratingProxy.class) {
    // There is only getDecoratedClass() declared -> dispatch to proxy config.
    return AopProxyUtils.ultimateTargetClass(this.advised);
    }
    else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
    // Service invocations on ProxyConfig with the proxy config...
    return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
    }
    ​
    Object retVal;
    ​
    if (this.advised.exposeProxy) {
    // Make invocation available if necessary.
    oldProxy = AopContext.setCurrentProxy(proxy);
    setProxyContext = true;
    }
    ​
    // May be null. Get as late as possible to minimize the time we "own" the target,
    // in case it comes from a pool.
    target = targetSource.getTarget();
    if (target != null) {
    targetClass = target.getClass();
    }
    ​
    // Get the interception chain for this method.
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    ​
    // Check whether we have any advice. If we don't, we can fallback on direct
    // reflective invocation of the target, and avoid creating a MethodInvocation.
    if (chain.isEmpty()) {
    // We can skip creating a MethodInvocation: just invoke the target directly
    // Note that the final invoker must be an InvokerInterceptor so we know it does
    // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
    }
    else {
    // We need to create a method invocation...
    invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    // Proceed to the joinpoint through the interceptor chain.
    retVal = invocation.proceed();
    }
    ​
    // Massage return value if necessary.
    Class<?> returnType = method.getReturnType();
    if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
    // Special case: it returned "this" and the return type of the method
    // is type-compatible. Note that we can't help if the target sets
    // a reference to itself in another returned object.
    retVal = proxy;
    }
    else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
    throw new AopInvocationException(
    "Null return value from advice does not match primitive return type for: " + method);
    }
    return retVal;
    }
    finally {
    if (target != null && !targetSource.isStatic()) {
    // Must have come from TargetSource.
    targetSource.releaseTarget(target);
    }
    if (setProxyContext) {
    // Restore old proxy.
    AopContext.setCurrentProxy(oldProxy);
    }
    }
    }

    JdkDynamicAopProxy的invoke方法核心代码如下:

          //1).得到目标方法的拦截器链
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
          //2). 调用拦截器链
          //如果chain是空的,直接调用target对象的method
    if (chain.isEmpty()) {
    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
    }
          //如果chain不是空的,进行拦截器链的调用
    else {
    invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    // Proceed to the joinpoint through the interceptor chain.
    retVal = invocation.proceed();
    }

    1)拦截器链是如何生成的

    我们顺着this.advised.getInterceptorsAndDynamicInterceptionAdvice往下走。

    /**
     * Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects
     * for the given method, based on this configuration.
     * @param method the proxied method
     * @param targetClass the target class
     * @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
     */
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
    cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
    this, method, targetClass);
    this.methodCache.put(cacheKey, cached);
    }
    return cached;
    } 

    上面的this.advisorChainFactory其实是DefaultAdvisorChainFactory。

    public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
    ​
    @Override
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
    Advised config, Method method, Class<?> targetClass) {
    ​
    // This is somewhat tricky... We have to process introductions first,
    // but we need to preserve order in the ultimate list.
    List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        //遍历config.getAdvisors
    for (Advisor advisor : config.getAdvisors()) {
    if (advisor instanceof PointcutAdvisor) {
    // Add it conditionally.
    PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
    if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
              //调用registry.getInterceptors得到advisor的MethodInterceptor
    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
              //调用pointcutAdvisor.getPointcut().getMethodMatcher()得到pointcut的MethodMatcher
    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
              //调用interceptorList.add将拦截器加入到拦截器链中
    if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
    if (mm.isRuntime()) {
    // Creating a new object instance in the getInterceptors() method
    // isn't a problem as we normally cache created chains.
    for (MethodInterceptor interceptor : interceptors) {
    interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
    }
    }
    else {
    interceptorList.addAll(Arrays.asList(interceptors));
    }
    }
    }
    }
    else if (advisor instanceof IntroductionAdvisor) {
    IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
    if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
    Interceptor[] interceptors = registry.getInterceptors(advisor);
    interceptorList.addAll(Arrays.asList(interceptors));
    }
    }
    else {
    Interceptor[] interceptors = registry.getInterceptors(advisor);
    interceptorList.addAll(Arrays.asList(interceptors));
    }
    }
    ​
    return interceptorList;
    }
    ​
    /**
     * Determine whether the Advisors contain matching introductions.
     */
    private static boolean hasMatchingIntroductions(Advised config, Class<?> actualClass) {
    for (int i = 0; i < config.getAdvisors().length; i++) {
    Advisor advisor = config.getAdvisors()[i];
    if (advisor instanceof IntroductionAdvisor) {
    IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
    if (ia.getClassFilter().matches(actualClass)) {
    return true;
    }
    }
    }
    return false;
    }
    }

    List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, Class<?> targetClass)

    其实这里的config就是ProxyFactoryBean的实例。(config传入了个AdvisedSupport实例,ProxyFactoryBean继承了AdvisedSupport)

    继续找ProxyFactoryBean的代码。

    ProxyFactoryBean的getObject方法调用时,会对adviceChain进行初始化(如果未初始化的话)。

     
    @Override
    public Object getObject() throws BeansException {
        //adviceChain拦截器链的初始化
    initializeAdvisorChain();
    if (isSingleton()) {
    return getSingletonInstance();
    }
    else {
    if (this.targetName == null) {
    logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
    "Enable prototype proxies by setting the 'targetName' property.");
    }
    return newPrototypeInstance();
    }
    }

    initializeAdvisorChain的内部实现:

    因为ProxyFactoryBean实现了BeanFactoryAware接口,因此可以拿到当前的容器实例beanFactory。

    通过调用this.beanFactory.get(beanName)方法将各个advice bean拿出来,然后加入到list中。

    initializeAdvisorChain的具体内部实现如下。

    /**
     * Create the advisor (interceptor) chain. Advisors that are sourced
     * from a BeanFactory will be refreshed each time a new prototype instance
     * is added. Interceptors added programmatically through the factory API
     * are unaffected by such changes.
     */
    private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
    if (this.advisorChainInitialized) {
    return;
    }
    ​
    if (!ObjectUtils.isEmpty(this.interceptorNames)) {
    if (this.beanFactory == null) {
    throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
    "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
    }
    ​
    // Globals can't be last unless we specified a targetSource using the property...
    if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
    this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
    throw new AopConfigException("Target required after globals");
    }
    ​
    // Materialize interceptor chain from bean names.
    for (String name : this.interceptorNames) {
    if (logger.isTraceEnabled()) {
    logger.trace("Configuring advisor or advice '" + name + "'");
    }
    ​
    if (name.endsWith(GLOBAL_SUFFIX)) {
    if (!(this.beanFactory instanceof ListableBeanFactory)) {
    throw new AopConfigException(
    "Can only use global advisors or interceptors with a ListableBeanFactory");
    }
    addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
    name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
    }
    ​
    else {
    // If we get here, we need to add a named interceptor.
    // We must check if it's a singleton or prototype.
    Object advice;
    if (this.singleton || this.beanFactory.isSingleton(name)) {
    // Add the real Advisor/Advice to the chain
    advice = this.beanFactory.getBean(name);
    }
    else {
    // It's a prototype Advice or Advisor: replace with a prototype.
    // Avoid unnecessary creation of prototype bean just for advisor chain initialization.
    advice = new PrototypePlaceholderAdvisor(name);
    }
    addAdvisorOnChainCreation(advice, name);
    }
    }
    }
    ​
    this.advisorChainInitialized = true;
    }

    总结,在ProxyFactoryBean的getObject方法中,会初始化拦截器链,相关的bean是通过调用beanFactory.get(beanName)方法得到的。

     

    2)拦截器链是如何链式调用的

    ReflectiveMethodInvocation.proceed执行拦截器链的调用。

    下面摘录了ReflectiveMethodInvocation的部分代码。

     
    //ReflectiveMethodInvocation实现了接口ProxyMethodInvocation,而ProxyMethodInvocation是MethodInvocation的子接口。
    //因此,ReflectiveMethodInvocation实现了MethodInvocation接口。
    public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
    ​
    protected final Object proxy;
    ​
    protected final Object target;
    ​
    protected final Method method;
    ​
    protected Object[] arguments;
    ​
    private final Class<?> targetClass;
    ​
    /**
     * List of MethodInterceptor and InterceptorAndDynamicMethodMatcher
     * that need dynamic checks.
     */
      //拦截器列表
    protected final List<?> interceptorsAndDynamicMethodMatchers;
    ​
    /**
     * Index from 0 of the current interceptor we're invoking.
     * -1 until we invoke: then the current interceptor.
     */
    private int currentInterceptorIndex = -1;
    ​
    @Override
    public Object proceed() throws Throwable {
    //We start with an index of -1 and increment early.
        //如果拦截器list到了最后了,运行目标方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    return invokeJoinpoint();
    }
    //根据currentInterceptorIndex得到list中的拦截器
    Object interceptorOrInterceptionAdvice =
    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        //1.如果拦截器中不仅有Interceptor,还需要进行动态方法匹配DynamicMethodMatcher
        //InterceptorAndDynamicMethodMatcher包含了Interceptor和DynamicMethodMatcher,
        //其中DynamicMethodMatcher用于运行时检查,用于在运行时判断方法是否需要拦截
        //(说明:MethodMatcher方法匹配分静态和动态两种
        //个人理解:
        //静态检查:比如你要拦截的方法名是精确的,就是某个类的某个方法,可以在程序非运行时,就可判断是否需要拦截
        //动态检查:比如你要拦截的某个方法,且要求入参为“aaa”,这种肯定需要运行时判断)
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
    // Evaluate dynamic method matcher here: static part will already have
    // been evaluated and found to match.
    InterceptorAndDynamicMethodMatcher dm =
    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
          //1.1 如果匹配上了,调用interceptor的invoke方法
    if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            //如果匹配上了,调用拦截器方法
            //注意:interceptor.invoke(this)传入的是this。
            //而ReflectiveMethodInvocation实现了MethodInvocation接口
            //因此,传入的是一个MethodInvocation实例。
    return dm.interceptor.invoke(this);
    }
          //1.2 如果没有匹配上,
    else {
    // Dynamic matching failed.
    // Skip this interceptor and invoke the next in the chain.
    return proceed();
    }
    }
        //2. 如果拦截器就是个interceptor,调用invoker方法
    else {
    // It's an interceptor, so we just invoke it: The pointcut will have
    // been evaluated statically before this object was constructed.
    return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
    }
    }
    public interface MethodInterceptor extends Interceptor {
    ​
    /**
     * Implement this method to perform extra treatments before and
     * after the invocation. Polite implementations would certainly
     * like to invoke {@link Joinpoint#proceed()}.
     * @param invocation the method invocation joinpoint
     * @return the result of the call to {@link Joinpoint#proceed();
     * might be intercepted by the interceptor
     * @throws Throwable if the interceptors or the target object
     * throws an exception
     */
    Object invoke(MethodInvocation invocation) throws Throwable;
    } 

    MethodBeforeAdviceInterceptor:会在目标方法运行之前进行拦截。

    public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
    private MethodBeforeAdvice advice;
    /**
     * Create a new MethodBeforeAdviceInterceptor for the given advice.
     * @param advice the MethodBeforeAdvice to wrap
     */
    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
    Assert.notNull(advice, "Advice must not be null");
    this.advice = advice;
    }
    ​
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
    return mi.proceed();
    }
    } 

    AfterReturningAdviceInterceptor:会在目标方法返回后进行拦截

    public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
    private final AfterReturningAdvice advice;
    /**
     * Create a new AfterReturningAdviceInterceptor for the given advice.
     * @param advice the AfterReturningAdvice to wrap
     */
    public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
    Assert.notNull(advice, "Advice must not be null");
    this.advice = advice;
    }
    ​
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
    Object retVal = mi.proceed();
    this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
    return retVal;
    }
    }

    3)Spring使用职责链模式实现拦截器链链式调用

    将上面调用拦截器链的简化下,如下。

    public interface MethodInterceptor {
    ​
        Object invoke(MethodInvocation mi);
    }
    public class MethodBeforeInterceptor implements MethodInterceptor {
    ​
        @Override
        public Object invoke(MethodInvocation mi) {
            before();
            return mi.proceed();
        }
    ​
        private void before() {
            System.out.println("Method before");
        }
    }
    public class AfterReturningInterceptor implements MethodInterceptor {
    ​
        @Override
        public Object invoke(MethodInvocation mi) {
            Object retVal = mi.proceed();
            afterReturning();
            return retVal;
        }
    ​
        private void afterReturning() {
            System.out.println("afterReturning");
        }
    }
    public interface MethodInvocation {
    ​
        Object proceed();
    }
    public class ReflectiveMethodInvocation implements MethodInvocation{
    ​
        private List<MethodInterceptor> interceptors;
    ​
        public ReflectiveMethodInvocation(List<MethodInterceptor> interceptors) {
            this.interceptors = interceptors;
        }
    ​
        private int currentInterceptorIndex = -1;
    ​
        public Object proceed() {
            if (currentInterceptorIndex == interceptors.size() - 1) {
                System.out.println("invoke target method");
                return "obj after invoke target method";
            }
            return interceptors.get(++currentInterceptorIndex).invoke(this);
        }
    }
    public class Client {
    ​
        public static void main(String[] args) {
            List<MethodInterceptor> interceptors = Arrays.asList(
                    new AfterReturningInterceptor(),
                    new MethodBeforeInterceptor()
            );
            ReflectiveMethodInvocation invocation = new ReflectiveMethodInvocation(interceptors);
            invocation.proceed();
        }
    }

    结果如下:

    Method before
    invoke target method
    afterReturning

    (这里抛个思考题:

    运行结果与List<MethodInterceptor>中interceptor的顺序有关吗?

    把new AfterReturningInterceptor()和new MethodBeforeInterceptor()换下顺序,结果会不同吗?

    答案:无关,不会。

     

    5. ProxyFactory实现AOP

    通过配置的方式使用AOP时,是通过ProxyFactoryBean的getObject()方法得到代理对象的。

    Spring 提供ProxyFactory类,可以通过编写代码的方式创建代理对象。

            TargetImpl target = new TargetImpl();
            ProxyFactory proxyFactory = new ProxyFactory(target);
            proxyFactory.addAdvisor(yourAdvisor);
            proxyFactory.addAdvice(yourAdvice);
            TargetImpl targetProxy = (TargetImpl)proxyFactory.getProxy();

    ProxyFactory类提供的方法如下。

    /**
     * Factory for AOP proxies for programmatic use, rather than via a bean
     * factory. This class provides a simple way of obtaining and configuring
     * AOP proxies in code.
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     * @author Rob Harrop
     * @since 14.03.2003
     */
    @SuppressWarnings("serial")
    public class ProxyFactory extends ProxyCreatorSupport {
    
        /**
         * Create a new ProxyFactory.
         */
        public ProxyFactory() {
        }
      
        public ProxyFactory(Object target) {
            setTarget(target);
            setInterfaces(ClassUtils.getAllInterfaces(target));
        }
    
        public ProxyFactory(Class<?>... proxyInterfaces) {
            setInterfaces(proxyInterfaces);
        }
    
        public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) {
            addInterface(proxyInterface);
            addAdvice(interceptor);
        }
    
        public ProxyFactory(Class<?> proxyInterface, TargetSource targetSource) {
            addInterface(proxyInterface);
            setTargetSource(targetSource);
        }
    
        public Object getProxy() {
            return createAopProxy().getProxy();
        }
    
        public Object getProxy(ClassLoader classLoader) {
            return createAopProxy().getProxy(classLoader);
        }
    
        @SuppressWarnings("unchecked")
        public static <T> T getProxy(Class<T> proxyInterface, Interceptor interceptor) {
            return (T) new ProxyFactory(proxyInterface, interceptor).getProxy();
        }
    
        @SuppressWarnings("unchecked")
        public static <T> T getProxy(Class<T> proxyInterface, TargetSource targetSource) {
            return (T) new ProxyFactory(proxyInterface, targetSource).getProxy();
        }
    
        public static Object getProxy(TargetSource targetSource) {
            if (targetSource.getTargetClass() == null) {
                throw new IllegalArgumentException("Cannot create class proxy for TargetSource with null target class");
            }
            ProxyFactory proxyFactory = new ProxyFactory();
            proxyFactory.setTargetSource(targetSource);
            proxyFactory.setProxyTargetClass(true);
            return proxyFactory.getProxy();
        }
    }

     

     

  • 相关阅读:
    Win10 VS2013 PCL1.8.1和依赖项VTK8.0.1, QHuall(2.15.2), FLANN1.9.1,Boost1.59.0,Zbil1.2.11和libPNG1.6.34编译安装
    Boost log中的几个问题
    Linux 使用静态库注意事项
    Windows中lib和DLL区别和使用
    CMake: ELF文件加载动态库的位置
    CMake 默认编译、链接选项
    ld 链接选项-L,-rpath-link,-rpath
    动态库的链接和链接选项-L,-rpath-link,-rpath
    Linux共享对象之编译参数 -fPIC
    ny509 因子和阶乘
  • 原文地址:https://www.cnblogs.com/yeyang/p/12579875.html
Copyright © 2020-2023  润新知