Spring AOP原理

来源:互联网 发布:批图软件下载 编辑:程序博客网 时间:2024/06/06 08:45

Spring利用动态代理技术实现了AOP增强功能。这个动态代理是通过Java的动态代理或CGLIB技术实现。具体根据代理对象实现的是类或者接口来决定。

Spring AOP的过程跟我们平时使用动态代理的过程是很相似的,只不过它帮助我们自动组装了增强方法与代理对象,这样我们就可以更加灵活,因为我们可以选择增强触发的时机,而且更加关注我们要做的事情。从原理以及源代码的角度,整个过程还是分为两个阶段,

第一个阶段是生成代理对象,这个过程根据代理对象是否实现了接口来选择使用不同的工厂生成代理对象。

第二个阶段是invoke阶段,也就是方法调用阶段。所有的切入点判断、advice增强都是在这个阶段完成的。个人理解只有这样才能算是动态代理吧。



1 生成代理对象

1.1 getObject

先来回忆一下我们是如何在程序中拿到代理对象的

InstanceInterface bean=(InstanceInterface) applicationContext.getBean("beanFactory");

我们是通过ProxyFactoryBean这个工厂bean得到的代理对象。根据工厂Bean的特点,它一定实现了FactoryBean接口,也就一定包含有getObject方法,没错,这就是获得代理对象的入口。这个方法实现的也很简单:

public Object getObject() throws BeansException {//初始化advisor方法链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.");}//返回prototype实例return newPrototypeInstance();}}

1.2 getSingletonInstance

这个方法调用了AopProxy的工厂方法来得到代理对象

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

1.3构造代理工厂

@Overridepublic 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()) {//如果目标对象实现了接口  则构造一个JDK动态代理工程return new JdkDynamicAopProxy(config);}//否则构造一个CGLIB动态代理工厂return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}}

1.4 得到代理对象

这里由于构造了两个工厂,因此其生成代理对象的方式也有所不同

1.4.1 JDK生成代理对象

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);findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);//非常熟悉的JDK生成代理对象的方式return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);}

1.4.2  CGLIB生成代理对象

public Object getProxy(ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());}try {Class<?> rootClass = this.advised.getTargetClass();Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");Class<?> proxySuperClass = rootClass;if (ClassUtils.isCglibProxyClass(rootClass)) {proxySuperClass = rootClass.getSuperclass();Class<?>[] additionalInterfaces = rootClass.getInterfaces();for (Class<?> additionalInterface : additionalInterfaces) {this.advised.addInterface(additionalInterface);}}// Validate the class, writing log messages as necessary.validateClassIfNecessary(proxySuperClass, classLoader);// 配置CGLIB enhancer对象Enhancer enhancer = createEnhancer();if (classLoader != null) {enhancer.setClassLoader(classLoader);if (classLoader instanceof SmartClassLoader &&((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {enhancer.setUseCache(false);}}enhancer.setSuperclass(proxySuperClass);enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));Callback[] callbacks = getCallbacks(rootClass);Class<?>[] types = new Class<?>[callbacks.length];for (int x = 0; x < types.length; x++) {types[x] = callbacks[x].getClass();}// fixedInterceptorMap only populated at this point, after getCallbacks call aboveenhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));enhancer.setCallbackTypes(types);// Generate the proxy class and create a proxy instance.return createProxyClassAndInstance(enhancer, callbacks);}catch (CodeGenerationException ex) {throw new AopConfigException("Could not generate CGLIB subclass of class [" +this.advised.getTargetClass() + "]: " +"Common causes of this problem include using a final class or a non-visible class",ex);}catch (IllegalArgumentException ex) {throw new AopConfigException("Could not generate CGLIB subclass of class [" +this.advised.getTargetClass() + "]: " +"Common causes of this problem include using a final class or a non-visible class",ex);}catch (Exception ex) {// TargetSource.getTarget() failedthrow new AopConfigException("Unexpected AOP exception", ex);}}

1.5 小结

到此为止,spring就通过了proxyFactoryBean为我们生成了代理对象,目前这个代理对象还没有进行任何增强方法的织入,只是将Advisor对象注入到了这个对象里面。下面我们来看看spring是如何实现AOP的。

2 JDK动态代理与invoke方法驱动AOP增强

我们知道在使用动态代理的时候,我们尽管看上去是调用的目标对象接口或实现类的方法,实际上执行的确是代理对象的invoke方法。在Spring AOP中自然也不例外,那么这个invoke方法是定义在哪里呢?我们以JDK生成动态代理的方式来解释这一过程。

2.1 invoke方法

这个invoke方法实际上定义在JdkDynamicAopProxy类中,他实现了我们熟悉的InvocationHandler接口。这个方法是整个AOP过程的提纲,整个过程的几个核心步骤都在此处进行了调用。特别需要注意的是,对于equalshashcode方法,spring是不会对他们进行增强处理的。

@Overridepublic 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 {//对于equals  hashcode方法不做AOP增强,直接执行方法if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {// The target does not implement the equals(Object) method itself.return equals(args[0]);}if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {// The target does not implement the hashCode() method itself.return hashCode();}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.// 获得AOP拦截方法链 在这里面完成了pointcut与advice的匹配 它确定了这个方法都需要有哪些增强处理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()) {// 如果方法链为空,那么不执行任何增强处理,直接调用方法retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);}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);}}}

2.2 获取匹配的advice方法

这个方法是在获得advice方法链,实际上利用AdvisorChainFactory工厂得到这些对象。

这里设置了缓存,也就是说只有第一次调用这个方法时,才会有这个获取匹配的advice对象的。需要理解的是,advice被定义在advisor里面,而整个方法链可能有多少advisor,也就是说可能有多个methodbefore afterrunning之类的方法围绕在实际方法周围,这些方法在这里进行匹配,然后放到一个list中。

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {//缓存对象MethodCacheKey cacheKey = new MethodCacheKey(method);List<Object> cached = this.methodCache.get(cacheKey);if (cached == null) {//通过工厂得到匹配的advice对象cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);this.methodCache.put(cacheKey, cached);}return cached;}

2.2.1 装配拦截器

这个方法定义在DefaultAdvisorChainFactory类中,在这里完成了pointcut与advice的匹配。其中两个重要的语句分别在20行和24行。他们分别完成了advice的封装以及pointcut与method的匹配两个工作。

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();//便利所有的advisor for (Advisor advisor : config.getAdvisors()) {if (advisor instanceof PointcutAdvisor) {// Add it conditionally.// 获得方法切入点PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {//获得advisor中定义的advice对象,也就是methodBeforeAdvice  afterRunningAdvice 和ThrowsAdvice  MethodInterceptor[] interceptors = registry.getInterceptors(advisor);//得到一个方法匹配器MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();//进行方法匹配,如果这个方法符合pointcut中的定义,就把advice对象拦截器加入到结果集中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;}

2.2.2 封装advice

先来回想一下我们是如何定义advice的。我们可以分别实现MethodBeforeAdvice AfterReturningAdvice 和ThrowsAdvice这三个接口来定义三个增强的动作,然后在spring配置文件中配置了他们与pointcut的关系,成为一个advisor。在spring进行AOP增强的时候,需要把这三种advice进行一次包装,也就是在把他们其中定义的增强方法与实际方法联系起来,构造一个方法“链”,这个就是封装advice的过程。

整个过程的入口为2.2.1中的20行getInterceptors方法。顾名思义,它就是获得所有拦截器的一个方法。进入到这个方法,发现突然出现了一个陌生的东西,AdvisorAdapter,还有一个this. adapters。他们其实是MethodBeforeAdviceAfterReturningAdvice和ThrowsAdvice的装配器。在这里的作用就是为了确定我们定义的advice到底是哪种或者哪几种类型的advice。

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {// 这个list是固定大小的  因为一个advice中 最多有三种类型的拦截器,也就是同时实现了三种类型的接口List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);Advice advice = advisor.getAdvice();//如果这个advice实现了MethodInterceptor接口 就把它直接加入进去if (advice instanceof MethodInterceptor) {interceptors.add((MethodInterceptor) advice);}//判断advice属于三个类型的中那几种类型 for (AdvisorAdapter adapter : this.adapters) {if (adapter.supportsAdvice(advice)) {//对这个方法进行包装interceptors.add(adapter.getInterceptor(advisor));}}if (interceptors.isEmpty()) {throw new UnknownAdviceTypeException(advisor.getAdvice());}return interceptors.toArray(new MethodInterceptor[interceptors.size()]);}

Spring中为三种advice均定义了对应类型的装配器adapter,他们的实现方法几乎是一样的,我们来看其中一个就能理解上面的代码了。

class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {@Override//判断这个advice是否属于当前类型的advicepublic boolean supportsAdvice(Advice advice) {return (advice instanceof AfterReturningAdvice);}@Override//对这个adivce进行包装public MethodInterceptor getInterceptor(Advisor advisor) {AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();return new AfterReturningAdviceInterceptor(advice);}}

2.2.3 三种类型的interceptor

经过了上面一步,我们定义的advice已经被封装了对应了Interceptor,在这三种类型的Interceptor中,进行了编织工作,也就是把我们定义的增强方法与实际方法进行了组合,下面我们分别看看他们是如何实现的。

(1)AfterReturningAdviceInterceptor

这里有一个invoke方法,可以看到实际方法在增强方法之前得到调用,也就起到了后处理的作用。这里的proceed暂且认为是方法调用,在后面会看到它是如何实现的。

@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {//调用实际方法Object retVal = mi.proceed();//调用自定义的增强方法this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());return retVal;}

(2) MethodBeforeAdviceInterceptor

这里有一个invoke方法,可以看到实际方法在增强方法之后得到调用,起到了前置增强的作用。

@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {// 调用自定义增强方法this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );//调用实际方法return mi.proceed();}

(3)  ThrowsAdviceInterceptor

这里面的代码就没有上面的那么简单了,但是逻辑还是比较清晰的。在invoke中定义了一个trycatch,把实际方法放入到try语句块中,一旦抛出异常,就会被捕获,然后去寻找我们是否定义了对应的异常处理方法,调用我们定义的处理方法进行处理。这实际上也就是一个更高级一点的try catch语句块而已

/** * Determine the exception handle method. Can return null if not found. * @param exception the exception thrown * @return a handler for the given exception type */private Method getExceptionHandler(Throwable exception) {Class<?> exceptionClass = exception.getClass();if (logger.isTraceEnabled()) {logger.trace("Trying to find handler for exception of type [" + exceptionClass.getName() + "]");}Method handler = this.exceptionHandlerMap.get(exceptionClass);while (handler == null && !exceptionClass.equals(Throwable.class)) {exceptionClass = exceptionClass.getSuperclass();handler = this.exceptionHandlerMap.get(exceptionClass);}if (handler != null && logger.isDebugEnabled()) {logger.debug("Found handler for exception of type [" + exceptionClass.getName() + "]: " + handler);}return handler;}@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {try {return mi.proceed();}catch (Throwable ex) {Method handlerMethod = getExceptionHandler(ex);if (handlerMethod != null) {invokeHandlerMethod(mi, ex, handlerMethod);}throw ex;}}private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable {Object[] handlerArgs;if (method.getParameterTypes().length == 1) {handlerArgs = new Object[] { ex };}else {handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};}try {method.invoke(this.throwsAdvice, handlerArgs);}catch (InvocationTargetException targetEx) {throw targetEx.getTargetException();}}

2.3   proceed方法链调用

前面有一个地方提到了一个proceed方法,我们再回到2.1invoke方法中,整个2.2过程讲的就是45行代码获得方法链的过程。经过了这个过程,我们已经得到了定义AOP需要的方法链,下面就应该进行方法调用了。这里面涉及两个关键方法,proceed和invokeJoinpointUsingReflection,他们分别是在还有方法链和方法链已经为空的时候调用的。

2.3.1    invokeJoinpointUsingReflection

它是定义在AopUtils工具类中的一个静态方法,实现的很简单,就是用反射去调用目标方法。

public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)throws Throwable {// Use reflection to invoke the method.try {ReflectionUtils.makeAccessible(method);//调用实际方法return method.invoke(target, args);}catch (InvocationTargetException ex) {// Invoked method threw a checked exception.// We must rethrow it. The client won't see the interceptor.throw ex.getTargetException();}catch (IllegalArgumentException ex) {throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +method + "] on target [" + target + "]", ex);}catch (IllegalAccessException ex) {throw new AopInvocationException("Could not access method [" + method + "]", ex);}}

2.3.2  proceed

这个方法驱动整个方法链的方法,它实际上是一个递归的过程。它从方法链list中依次获得对应的interceptor,并调用的他们invoke方法,再回想2.2.3中提到的proceed,调用invoke以后会递归地再次调用proceed方法,这样就驱动了整个方法链的调用,也就完成了AOP的过程。

public Object proceed() throws Throwable {//如果方法链已经到了最后一个方法,那就是目标方法,直接调用该方法,使用的是2.3.1中的反射if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}//依次从方法链list中获得相对应的 interceptorObject interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// Evaluate dynamic method matcher here: static part will already have// been evaluated and found to match.InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {return dm.interceptor.invoke(this);}else {// Dynamic matching failed.// Skip this interceptor and invoke the next in the chain.return proceed();}}else {//调用对应interceptor中的invoke方法return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}

3 CGLIB与intercept方法驱动AOP增强

在前面介绍了通过JDK动态代理的方式实现了AOP增强,它的核心是invoke触发了方法链的调动。CGLIB的整个过程是十分类似的,关键的方法也都是一样的,只不过在使用GCLIB生成代理对象的时候,advisor被设置在CALLBACK里,其关键语句在CglibAopProxy类(本例源自Spring4.1.5版本,在3.2版本中,这个类名为Cglib2AopProxy)中的getCallBacks方法中。

Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

所有的advice对象被封装在了DynamicAdvisedInterceptor这个内部类对象中,而正是这个类里面定义的intercept方法驱动了AOP过程。

看这个方法的源代码,几乎是跟invoke方法一样的,而且连注释都是一致的。只有一个地方是不同的,对于proceed的调用,cglib使用的是CglibMethodInvocation的方法,而jdk使用的是ReflectiveMethodInvocation,而他们的关系是继承关系,也就是说CGLIB在进入到AOP增强的实现部分与JDK动态代理的部分没有区别。

@Overridepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;Class<?> targetClass = null;Object target = null;try {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 = getTarget();if (target != null) {targetClass = target.getClass();}//获得方法链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);Object retVal;// Check whether we only have one InvokerInterceptor: that is,// no real advice, but just reflective invocation of the target.if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {// 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.retVal = methodProxy.invoke(target, args);}else {// 递归调用方法链retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}retVal = processReturnType(proxy, target, method, retVal);return retVal;}finally {if (target != null) {releaseTarget(target);}if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}}}

4 SpringAOP过程总结

经过了上面的分析,发现AOP的过程并不复杂。就如开篇所说,它分为两个部分

第一是得到代理对象,这里根据目标对象的不同,可以使用JDK动态代理或者CGLIB来生成代理对象,对于Advisor,仅是将他们设置到对应的对象中,并没有进行任何其他的处理

第二个过程是AOP方法驱动的过程,对于目标方法的调用,他们或是驱动了invoke方法,或是调用了intercept方法,这样就进入到AOP增强的过程。在这个过程中,完成了获得advice方法,封装advice方法到对应的interceptor,组装advice方法链,递归调用proceed方法这一系列的过程,这样就完成了AOP增强的功能。







 












1 0