重新学习Spring AOP 之源码分析
Spring AOP 源码分析
寻找入口
Spring 的AOP 是通过接入BeanPostProcessor 后置处理器开始的,它是Spring IOC 容器经常使用到的一个特性,这个Bean 后置处理器是一个监听器,可以监听容器触发的Bean 声明周期事件。后置处理器向容器注册以后,容器中管理的Bean 就具备了接收IOC 容器事件回调的能力。
BeanPostProcessor 的使用非常简单,只需要提供—个实现接口BeanPostProcessor 的实现类,然后
在Bean 的配置文件中设置即可。
1 、Bean PostProcessor 源码
public interface BeanPostProcessor {//为在Bean 的初始化前提供回调入口default Object postProcessBeforeinitialization(Object bean, String beanName) throws BeansException {return bean;//为在Bean 的初始化之后提供回调入口default Object postProcessAfterinitialization(Object bean, String beanName) throws BeansException {return bean;}}
这两个回调的入口都是和容器管理的Bean 的生命周期事件紧密相关,可以为用户提供在Spring IOC容器初始化Bean 过程中自定义的处理操作。
2、AbstractAutowireCapableBeanFactory 类对容器生成的Bean 添加后置处理器
BeanPostProcessor 后置处理器的调用发生在Spring IOC 容器完成对Bean 实例对象的创建和属性的依赖注入完成之后,在对Spring 依赖注入的源码分析过程中我们知道,当应用程序第一次调用getBean()方法(lazy-init 预实例化除外)向Spring IOC 容器索取指定Bean 时触发Spring IOC 容器创建Bean 实例对象并进行依赖注入的过程,其中真正实现创建Bean 对象并进行依赖注入的方法是AbstractAutowireCapableBeanFactory 类的doCreateBean()方法,主要源码如下:
//真正创建Bean 的方法protected Object doCreateBean (final String beanName, final RootBeanDefini tion mbd, final @Nullable Obj'ect [] args)throws BeanCreationException {//创建Bean 实例对象•••Object exposedObject = bean;try {//对Bean 属性进行依赖注入populateBean(beanName, mbd , instanceWrapper);//在对Bean 实例对象生成和依赖注入完成以后, 开始对Bean 实例对象//进行初始化,为Bean 实例对象应用BeanPostProcessor 后置处理器exposedObject = initializeBean (beanName, exposedObject, mbd);catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex) .getBeanName()) ) {throw (BeanCreationException ) ex;else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}•••//为应用返回所需要的实例对象return exposedObject;}
从上面的代码中我们知道,为Bean实例对象添加BeanPostProcessor 后置处理器的入口的是
initiaIizeBean()方法。
3、initializeBean()方法为容器产生的Bean 实例对象添加BeanPostProcessor 后置处理器
同样在AbstractAutowireCapableBeanFactory 类中, initializeBean()方法实现为容器创建的Bean实例对象添加BeanPostProcessor 后置处理器,源码如下:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {//JDK的安全机制验证权限if (System.getSecurityManager() != null) {//实现privilegedAction接口的匿名内部类AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {//为Bean实例对象包装相关属性,如名称,类加载器,所属容器等invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;//对BeanPostProcessor后置处理器的PostProcessorsBeforeInitialization//灰调方法的调用,为bean初始化之前做一些处理if (mbd == null || !mbd.isSynthetic()) {//执行后置处理的beforwrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}//调用Bean实例对象的初始化的方法,这个初始化方法实在spring bean定义位置文件中//通过init-method属性指定的try {//执行bean的声明周期回调中的init方法invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}//对BeanPostProcessor后置处理器的PostProcessorsBeforeInitialization//灰调方法的调用,为bean初始化之后做一些处理if (mbd == null || !mbd.isSynthetic()) {//执行后置处理器的after方法wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessBeforeInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;}public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;}
BeanPostProcessor 是一个接口其初始化前的操作方法和初始化后的操作方法均委托其实现子类来实现,在Spring 中, BeanPostProcessor 的实现子类非常的多,分别完成不同的操作,如:AOP 面向切面谝程的注册通知适配器、Bean 对象的数据校验、Bean 继承属性、方法的合并等等,我们以最简单的AOP 切面织入来简单了解主要的功能。下面我们来分析其中一个创建AOP 代理对象的子类AbstractAutoProxyCreator 类。该类重写了postProcessAfterlnitialization()方法。
选择代理策略
进入postProcessAfterlnitialization()方浩,我们发现调到了一个非常核心的方法wraplfNecessary(),
其源码如下:
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;}protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && 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;}//获取这个bean的advice// Create proxy if we have advice.//扫描所有相关方法(point原始方法)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;}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);proxyFactory.addAdvisors(advisors);proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}return proxyFactory.getProxy(getProxyClassLoader());}
整个过程跟下来,我发现最终调用的是proxyFactory.getProxy()方法。到这里我们大概能够猜到
proxyFactory 有JDK 和CGLib 的,那么我们该如何选择呢?最终调用的是DefaultAopProxyFactory的createAopProxy()方法:
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);}}
调用代理方法
分析调用逻辑之前先上类图,看看Spring 中主要的AOP 组件:
上面我们已经了解到Spring提供了两种方式来生成代理方式有JDKProxy和CGLib。下面我们来研究—下Spring如何使用JDK来生成代理对象,具体的生成代码放在JdkDynamicAopProxy这个类中,
直接上相关代码:
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);}
通过注释我们应该已经看得非常明白代理对象的生成过程,此处不再赘述。下面的问题是,代理对象生成了,那切面是如何织入的?
我们知追Invocation Handler 是JDK 动态代理的核心,生成的代理对象的方法调用都会委托到InvocationHandler.invok()方法。而从JdkDynamicAopProxy 的涌码我们可以看到这个类其实也实
现了InvocationHandler ,下面我们分析Spring AOP 是如何织入切面的直接上源码看invoke()方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {MethodInvocation invocation;Object oldProxy = null;boolean setProxyContext = false;TargetSource targetSource = this.advised.targetSource;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);}//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;}// Get as late as possible to minimize the time we "own" the target,// in case it comes from a pool.//获得目标对象的类target = targetSource.getTarget();Class<?> targetClass = (target != null ? target.getClass() : null);// Get the interception chain for this method.//获取可以应用到此方法上的Interceptor列表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.//获取可以应用到此方法的通知(Interceptor),直接反射调用method.invoke(target,args)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 != Object.class && 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);}}}
主要实现思路可以简述为:首先获取应用到此方法上的通知链(Interceptor Chain) 。如果有通知,则
应用通知,并执行JoinPoint ;如果没有通知,则直接反射执行JoinPoint。而这里的关键是通知链是如何获取的以及它又是如何执行的呢?现在来逐一分析。首先,从上面的代码可以看到,通知链是通过Advised. getlntercepto rsAndDynamiclnterceptionAdvice()这个方法来获取的,我们来看下这个方法的实现逻辑:
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;}
通过上面的涌码我们可以看到,实际获取通知的实现逻辑宾实是由AdvisorChainFactory 的getInterceptorsAndDynamiclntercepti onAdvice()方法来完成的,且获取到的结果会被缓存。下面来
分析getInterceptorsAndDynamiclnterceptionAdvice()方法的实现:
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();for (Advisor advisor : config.getAdvisors()) {if (advisor instanceof PointcutAdvisor) {// Add it conditionally.PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {MethodInterceptor[] interceptors = registry.getInterceptors(advisor);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;}
这个方法执行完成后, Advised 中配置能够应用到连接点(JoinPoint) 或者目标类(Target Object)的Advisor 全部被转化成了Method Interceptor ,接下来我们再看下得到的拦截器链是怎么起作用的。
if (chain.isEmpty()) {Object[] argsToUse = AopProxyUtils.adaptArgumentsifNecessary(Method, args);retVal = AopUtils.invokeJoinpointUsingReflection(target, Method, argsToUse);}else {//创建Methodinvocationinvocation= new ReflectiveMethodinvocation(proxy, target, Method, args, targetClass, chain);retVal = invocation.proceed();}
从这段代码可以看出,如果得到的拦截器链为空,则直接反射调用目标方法,否则创建
Methodlnvocation, 调用proceed()方法,触发拦截器链的执行,来看下具体代码
public Object proceed() throws Throwable {//如果Interceptor 执行完了,则执行joinPointif (this. currentinterceptorindex == this. interceptorsAndDynamicMethodMatchers. size() - 1) {return invokeJoinpoint();}Object interceptorOrinterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get (++this.currentinterceptorindex) ;//如果要动态匹配joinPointInterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrinterceptionAdvice;//动态匹配:运行时参数是否满足匹配条件if (dm.MethodMatcher.matches(this.Method, this . targetClass, this.arguments)) {return dm.interceptor.invoke(this) ;}else {/ /动态匹配失败时, 略过当前Intercetpor, 调用下一个Interceptorreturn proceed();} }else {//执行当前Intercetporreturn ( (Methodinterceptor) interceptorOrinterceptionAdvice).invoke(this);}
至此,通知链就完美地形成了。我们再往下来看invokeJoinpointUsing Reflection()方法,其实就是反射调用:
public static Object invokeJoinpointUsingReflection(@Nullable 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. getTal"'.getException();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);}}}
Spring AOP 源码就分析到这儿,相信小伙伴们应该有了基本思路,下面时序图
触发通知
在为AopProxy 代理对象配置拦截器的实现中,有—个取得拦截器的配置过程,这个过程由DefaultAdvisorChainFactory实现,这个工厂类负责生成拦截器链,在它的getlnterceptorsAndDynamiclnterceptionAdvice 方法中,有—个适配器和注册过程,通过配置Spring 预先设计好的拦截器, Spring 加入了它对AOP 实现的处理。
GlobalAdvisorAdapterRegistry 负责拦截器的适配和注册过程。
public abstract class GlobalAdvisorAdapterRegistry {/*** Keep track of a single instance so we can return it to classes that request it.*/private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();/*** Return the singleton {@link DefaultAdvisorAdapterRegistry} instance.*/public static AdvisorAdapterRegistry getInstance() {return instance;}/*** Reset the singleton {@link DefaultAdvisorAdapterRegistry}, removing any* {@link AdvisorAdapterRegistry#registerAdvisorAdapter(AdvisorAdapter) registered}* adapters.*/static void reset() {instance = new DefaultAdvisorAdapterRegistry();}}
而GlobalAdvisorAdapterRegistry 起到了适配器和单例模式的作用,提供了一个DefaultAdvisorAdapterRegistry , 它用来完成各种通知的适配和注册过程。
("serial")public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {private final List<AdvisorAdapter> adapters = new ArrayList<>(3);/*** Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.*/public DefaultAdvisorAdapterRegistry() {registerAdvisorAdapter(new MethodBeforeAdviceAdapter());registerAdvisorAdapter(new AfterReturningAdviceAdapter());registerAdvisorAdapter(new ThrowsAdviceAdapter());}public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {if (adviceObject instanceof Advisor) {return (Advisor) adviceObject;}if (!(adviceObject instanceof Advice)) {throw new UnknownAdviceTypeException(adviceObject);}Advice advice = (Advice) adviceObject;if (advice instanceof MethodInterceptor) {// So well-known it doesn't even need an adapter.return new DefaultPointcutAdvisor(advice);}for (AdvisorAdapter adapter : this.adapters) {// Check that it is supported.if (adapter.supportsAdvice(advice)) {return new DefaultPointcutAdvisor(advice);}}throw new UnknownAdviceTypeException(advice);}public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {List<MethodInterceptor> interceptors = new ArrayList<>(3);Advice advice = advisor.getAdvice();if (advice instanceof MethodInterceptor) {interceptors.add((MethodInterceptor) 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[0]);}public void registerAdvisorAdapter(AdvisorAdapter adapter) {this.adapters.add(adapter);}}
DefaultAdvisor AdapterRegistry 设置了一系列的是配置,正是这些适配器的实现,为Spring AOP 提供了编织能力。下面以MethodBef oreAdviceAdapter 为例,看具体的实现..
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {public boolean supportsAdvice(Advice advice) {return (advice instanceof MethodBeforeAdvice);}public MethodInterceptor getInterceptor(Advisor advisor) {MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();return new MethodBeforeAdviceInterceptor(advice);}}
Spring AOP 为了实现advice 的织入, 设计了特定的拦截器对这些功能进行了封装。我们接着看MethodBeforeAdvicelnterceptor 如何完成封装的?
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {private final 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;}public Object invoke(MethodInvocation mi) throws Throwable {this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());return mi.proceed();}}
可以看到, invoke 方法中, 首先触发了advice 的before 回调, 然后才是proceed。AfterReturningAdvicelnterceptor 的源码:
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;}public Object invoke(MethodInvocation mi) throws Throwable {Object retVal = mi.proceed();this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());return retVal;}}
ThrowsAdvicelnterceptor 的源码:
public 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.getParameterCount() == 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();}}
至此, 我们知道了对目标对象的增强是通过拦截器实现的。
总结,Spring 博大精深,需要温故知新。
