写文章

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

2018-11-28 12:38:32

2601 | 0 | 0

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的源码自己动手理解一下,希望能对大家有所帮助。


0

收藏
分享