您现在的位置是:首页 > 文章详情

Spring AOP源码解析——AOP动态代理原理和实现方式

日期:2018-11-28点击:594

Spring介绍

Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和AOP的容器框架,主要是针对JavaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,MyBatis框架等组合使用。

 

AOP介绍

AOP是什么

AOP技术利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

 

AOP相关概念

方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现。

连接点(Joinpoint): 程序执行过程中明确的点,如方法的调用或特定的异常被抛出。

通知(Advice): 在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。Spring中定义了四个advice: BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice

切入点(Pointcut): 指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。 Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上

目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象。

AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。

 

AOP原理

AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于 JDK 动态代理、CGLIB 等在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。Spring AOP则采用的是动态代理来实现。

在本节中,我们只分中JDK动态代理的实现方式。

 

源码解析

准备工作

首先定义一个Spring AOP的配置文件spring-aop.xml。

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">     <aop:config>         <aop:aspect id="TestAspect" ref="aspect">             <aop:pointcut id="pointcut" expression="execution(* org.study.spring.aop.*.*(..))"/>             <aop:before method="doBefore" pointcut-ref="pointcut"/>         </aop:aspect>     </aop:config>     <bean id="aspect" class="org.study.spring.aop.Aspect"/>     <bean id="test" class="org.study.spring.aop.Test"/></beans>

由于我们只分析JDK动态代理的实现方式,所以需要定义一个接口。

public interface ITest{     public void doSomething(); }

目标对象实现上面定义的接口。

public class Test implements ITest {     public void doSomething() {         System.out.println("do something");     } }

定义Aspect,这里我们以前置通知为例。

public class Aspect {     public void doBefore(JoinPoint jp) {         System.out.println("do before");     } }

编写程序入口代码,可以直接打断点进行调试。

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); Test bean = context.getBean("test", Test.class); bean.doSomething();

开始解析

根据上节对bean创建和初始化过程的分析,我们来到AbstractAutowireCapableBeanFactory.java类的initializeBean方法。在这个方法里Spring会对创建完成的Bean进行初始化,我们重点关注applyBeanPostProcessorsAfterInitializaton这个方法。

 /**  * Initialize the given bean instance, applying factory callbacks  * as well as init methods and bean post processors.  * <p>Called from {@link #createBean} for traditionally defined beans,  * and from {@link #initializeBean} for existing bean instances.  * @param beanName the bean name in the factory (for debugging purposes)  * @param bean the new bean instance we may need to initialize  * @param mbd the bean definition that the bean was created with  * (can also be {@code null}, if given an existing bean instance)  * @return the initialized bean instance (potentially wrapped)  * @see BeanNameAware  * @see BeanClassLoaderAware  * @see BeanFactoryAware  * @see #applyBeanPostProcessorsBeforeInitialization  * @see #invokeInitMethods  * @see #applyBeanPostProcessorsAfterInitialization  */ protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { invokeAwareMethods(beanName, bean); return null; } }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }

进入applyBeanPostProcessorsAfterInitializaton方法,继续往下。

 @Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { result = beanProcessor.postProcessAfterInitialization(result, beanName); if (result == null) { return result; } } return result; }

接着进入AbstractAutoProxyCreator.java类的postProcessAfterInitialization方法中,继续往下。

 /**  * Create a proxy with the configured interceptors if the bean is  * identified as one to proxy by the subclass.  * @see #getAdvicesAndAdvisorsForBean  */ @Override public Object postProcessAfterInitialization(Object bean, String beanName)  throws BeansException {   if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }

打开wrapIfNecessary方法,我们可以看到,Spring在这里先获取配置好的Advisor信息,然后调用createProxy方法为目标对象创建了代理,接着将创建的代理对象返回。

/**  * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.  * @param bean the raw bean instance  * @param beanName the name of the bean  * @param cacheKey the cache key for metadata access  * @return a proxy wrapping the bean, or the raw bean instance as-is  */ protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (beanName != null && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }

进入createProxy方法,Spring根据传入的advisor配置信息,初始化ProxyFactory然后获取并返回代理对象,我们直接看最后一行proxyFactory.getProxy(getProxyClassLoader())。

/**  * Create an AOP proxy for the given bean.  * @param beanClass the class of the bean  * @param beanName the name of the bean  * @param specificInterceptors the set of interceptors that is  * specific to this bean (may be empty, but not null)  * @param targetSource the TargetSource for the proxy,  * already pre-configured to access the bean  * @return the AOP proxy for the bean  * @see #buildAdvisors  */ protected Object createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); }else { evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); for (Advisor advisor : advisors) { proxyFactory.addAdvisor(advisor); } proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } return proxyFactory.getProxy(getProxyClassLoader()); }

接着进入ProxyFactory.java类的getProxy方法,只有一行代码。我们分为两个部分来分析:

第一部分,调用createAopProxy方法初始化AopProxy。

第二部分,调用getProxy方法获取代理对象。

/**  * Create a new proxy according to the settings in this factory.  * <p>Can be called repeatedly. Effect will vary if we've added  * or removed interfaces. Can add and remove interceptors.  * <p>Uses the given class loader (if necessary for proxy creation).  * @param classLoader the class loader to create the proxy with  * (or {@code null} for the low-level proxy facility's default)  * @return the proxy object  */ public Object getProxy(ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); }

我们先来看看AopProxy是如何被初始化的。

初始化AopProxy

先进入ProxyCreatorSupport.java类的createAopProxy方法。这就是生成代理的入口,你会发现传入的参数是是this,其实传入的就是this的父类AdvisedSupport.java中的advisor等生成代理的核心参数。

/**  * Subclasses should call this to get a new AOP proxy. They should <b>not</b>  * create an AOP proxy with {@code this} as an argument.  */ protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } return getAopProxyFactory().createAopProxy(this); }

打开DefaultAopProxyFactory.java类中的createAopProxy方法。Spring根据代理的目标对象是否实现了接口,来返回JdkDynamicAopProxy的动态代理或者CGLIB的代理,并且传入advisor核心参数(JdkDynamicAopProxy这个实现了InvocationHandler,要实现invoke的关键就是传入的advisor)。

@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."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }

接着进入JdkDynamicAopProxy.java类中的JdkDynamicAopProxy方法,将传入的AdvisedSupport赋值到advised里。

/**  * Construct a new JdkDynamicAopProxy for the given AOP configuration.  * @param config the AOP configuration as AdvisedSupport object  * @throws AopConfigException if the config is invalid. We try to throw an informative  * exception in this case, rather than let a mysterious failure happen later.  */ public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException { Assert.notNull(config, "AdvisedSupport must not be null"); if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) { throw new AopConfigException("No advisors and no TargetSource specified"); } this.advised = config; }

到这里,AopProxy已初始化完成。接下来我们来看,Spring是如何获取代理对象的。

获取代理对象

先进入getProxy方法,这里我们重点关注newProxyInstance这个方法。

@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); }

接着进入Proxy.java类的newProxyInstance方法,这是java reflect包提供的原生创建代理类的方法。就是在这里,目标对象的代理对象完成了创建并返回。

 /**      * Returns an instance of a proxy class for the specified interfaces      * that dispatches method invocations to the specified invocation      * handler.      *      * <p>{@code Proxy.newProxyInstance} throws      * {@code IllegalArgumentException} for the same reasons that      * {@code Proxy.getProxyClass} does.      *      * @param   loader the class loader to define the proxy class      * @param   interfaces the list of interfaces for the proxy class      *          to implement      * @param   h the invocation handler to dispatch method invocations to      * @return  a proxy instance with the specified invocation handler of a      *          proxy class that is defined by the specified class loader      *          and that implements the specified interfaces      * @throws  IllegalArgumentException if any of the restrictions on the      *          parameters that may be passed to {@code getProxyClass}      *          are violated      * @throws  SecurityException if a security manager, <em>s</em>, is present      *          and any of the following conditions is met:      *          <ul>      *          <li> the given {@code loader} is {@code null} and      *               the caller's class loader is not {@code null} and the      *               invocation of {@link SecurityManager#checkPermission      *               s.checkPermission} with      *               {@code RuntimePermission("getClassLoader")} permission      *               denies access;</li>      *          <li> for each proxy interface, {@code intf},      *               the caller's class loader is not the same as or an      *               ancestor of the class loader for {@code intf} and      *               invocation of {@link SecurityManager#checkPackageAccess      *               s.checkPackageAccess()} denies access to {@code intf};</li>      *          <li> any of the given proxy interfaces is non-public and the      *               caller class is not in the same {@linkplain Package runtime package}      *               as the non-public interface and the invocation of      *               {@link SecurityManager#checkPermission s.checkPermission} with      *               {@code ReflectPermission("newProxyInPackage.{package name}")}      *               permission denies access.</li>      *          </ul>      * @throws  NullPointerException if the {@code interfaces} array      *          argument or any of its elements are {@code null}, or      *          if the invocation handler, {@code h}, is      *          {@code null}      */     @CallerSensitive     public static Object newProxyInstance(ClassLoader loader,                                           Class<?>[] interfaces,                                           InvocationHandler h)         throws IllegalArgumentException    {         Objects.requireNonNull(h);          final Class<?>[] intfs = interfaces.clone();         final SecurityManager sm = System.getSecurityManager();           if (sm != null) {             checkProxyAccess(Reflection.getCallerClass(), loader, intfs);         }        /*          * Look up or generate the designated proxy class.          */         Class<?> cl = getProxyClass0(loader, intfs);        /*          * Invoke its constructor with the designated invocation handler.          */         try {                       if (sm != null) {                 checkNewProxyPermission(Reflection.getCallerClass(), cl);             }                        final Constructor<?> cons = cl.getConstructor(constructorParams);                        final InvocationHandler ih = h;                        if (!Modifier.isPublic(cl.getModifiers())) {                 AccessController.doPrivileged(new PrivilegedAction<Void>() {                                        public Void run() {                         cons.setAccessible(true);                                                return null;                     }                 });             }            return cons.newInstance(new Object[]{h});         } catch (IllegalAccessException|InstantiationException e) {                                    throw new InternalError(e.toString(), e);         } catch (InvocationTargetException e) {             Throwable t = e.getCause();                           if (t instanceof RuntimeException) {                                    throw (RuntimeException) t;             } else {                                     throw new InternalError(t.toString(), t);             }         } catch (NoSuchMethodException e) {                                throw new InternalError(e.toString(), e);         }     }

以上就完成了创建并获取代理对象的整个过程。

 

总结

通过这次源码分析,我们应该知道AOP动态代理的原理是什么,也知道Spring是如何根据目标对象去创建并获取代理对象的。其实,整个过程的本质就是Spring根据配置文件,利用反射和目标对象实现所的接口创建了代理对象。然后将代理对象返回,与原对象进行替换,从而实现了动态代理。如果还有不明白的地方,可以对照着Spring的源码自己动手理解一下,希望能对大家有所帮助。


原文链接:https://blog.roncoo.com/article/125948
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章