上一篇我的博客《使用aop和注解实现日志记录》中提到了代理模式,那么这篇博客我们好好来理一下设计模式中的“代理模式”是如何在aop中设计和使用的。


 


1:首先,我先解释一下设计模式中“代理模式”的定义


什么是代理模式?


 


代理模式,也叫委托模式,其定义是给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。它包含了三个角色:


 


Subject:抽象主题角色。可以是抽象类也可以是接口,是一个最普通的业务类型定义。


 


RealSubject:具体主题角色,也就是被代理的对象,是业务逻辑的具体执行者。


 


Proxy:代理主题角色。负责读具体主题角色的引用,通过真实角色的业务逻辑方法来实现抽象方法,并在前后可以附加自己的操作。


 


用类图来表示的话大概如下:


Spring AOP中代理模式的使用_动态代理


 


比如:我的上一篇我的博客《使用aop和注解实现日志记录》中,我的核心方法业务逻辑是执行addYaml方法,但是我需要在执行 addYaml方法前后输出关联的日志信息以方便后期出现异常时进行问题定位。


 


这时我可以直接把输出相关日志的代码加在addYaml方法中实现,也可以通过静态代理的方式单独写一个代理类实现addYaml方法,然后进行代理,具体实现见文章最后的参考文献。


考虑到相关的方法前后都要输出相关日志,并且方法众多,我不可能给所有的方法都实现一个代理类。所以Spring Framework框架利用Java反射+拦截的机制用动态代理的方式解决这一个问题。


 


Spring中AOP的实现采用的就是动态代理。


 


先简单放一张《使用aop和注解实现日志记录》中我debug时堆栈中的对象信息。如图我们可以看到methodInvocation={CglibAopProxy……},可以明确看到有使用CGLIB 动态代理。Spring AOP中代理模式的使用_设计模式_02


 


而JDK 动态代理和 CGLIB 动态代理均是实现 Spring AOP 的基础。我们可以看下AOP的部分底层源码:



public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {



 


 


    @Override


    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {


        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.");


            }


            // 判断目标类是否是接口或者目标类是否Proxy类型,若是则使用JDK动态代理


            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {


                return new JdkDynamicAopProxy(config);


            }


            // 使用CGLIB的方式创建代理对象


            return new ObjenesisCglibAopProxy(config);


        }


        else {


            // 上面条件都不满足就使用JDK的提供的代理方式生成代理对象


            return new JdkDynamicAopProxy(config);


        }


    }


}


 


 


    源码的判断逻辑并不难,主要是根据目标类是否是接口或者Proxy类型来判断使用哪种代理模式创建代理对象,使用的代理模式正是JDK动态代理和CGLIB 动态代理技术。