Spring Aop源码解析(二)------ 代理对象详解


代理对象的生成

  advisor对象已经生成完毕之前已经介绍完了,现在来看代理对象的生成,以及代理对象是如何使用advisor的。

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

		// Create proxy if we have advice.
		//已经获取到所有符合条件的advisor
		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, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {
		
		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}
		//创建proxyFactory对象
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);
		
		if (!proxyFactory.isProxyTargetClass()) {
			//根据beanName检查对应的beandefinition的PRESERVE_TARGET_CLASS_ATTRIBUTE属性,
			//返回true,则ProxyTargetClass设置为true
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				//类没有实现接口的话,则ProxyTargetClass设置为true
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
		
		//将传入进来的specificInterceptors进一步包装
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		//将advisors设置进来
		proxyFactory.addAdvisors(advisors);
		//把被代理实例放入进来
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);
	
		proxyFactory.setFrozen(this.freezeProxy);
		//AbstractAdvisorAutoProxyCreator的advisorsPreFiltered方法返回true
		if (advisorsPreFiltered()) {
			//preFiltered被设置为true
			proxyFactory.setPreFiltered(true);
		}
		
		//创建代理对象
		return proxyFactory.getProxy(getProxyClassLoader());
	}
	protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
		// Handle prototypes correctly...
		//这里添加实例化interceptorNames容器中存的beanName作为advisor
		//可以通过实现BeanPostProcess接口和PriorityOrdered接口(要在AnnotationAwareAspectJAutoProxyCreator(实现了Ordered接口)注册到容器之前实例化),往interceptorNames容器中放入beanName
		Advisor[] commonInterceptors = resolveInterceptorNames();
		
		List<Object> allInterceptors = new ArrayList<>();
		if (specificInterceptors != null) {
			//将原本的之前匹配的advisors加入到allInterceptors中
			allInterceptors.addAll(Arrays.asList(specificInterceptors));
			if (commonInterceptors.length > 0) {
				//默认为true
				if (this.applyCommonInterceptorsFirst) {
					//commonInterceptors 放在最前面 最先执行
					allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
				}
				//改为falsed的话,则添加到后面
				else {
					allInterceptors.addAll(Arrays.asList(commonInterceptors));
				}
			}
		}
		if (logger.isTraceEnabled()) {
			int nrOfCommonInterceptors = commonInterceptors.length;
			int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
			logger.trace("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
					" common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
		}
		
		Advisor[] advisors = new Advisor[allInterceptors.size()];
		for (int i = 0; i < allInterceptors.size(); i++) {
			advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
		}
		return advisors;
	}
	private Advisor[] resolveInterceptorNames() {
		BeanFactory bf = this.beanFactory;
		ConfigurableBeanFactory cbf = (bf instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) bf : null);
		List<Advisor> advisors = new ArrayList<>();
		//循环interceptorNames
		for (String beanName : this.interceptorNames) {
			if (cbf == null || !cbf.isCurrentlyInCreation(beanName)) {
				Assert.state(bf != null, "BeanFactory required for resolving interceptor names");
				//实例化bean
				Object next = bf.getBean(beanName);
				//将bean包装为Advisor放入advisors中
				advisors.add(this.advisorAdapterRegistry.wrap(next));
			}
		}
		return advisors.toArray(new Advisor[0]);
	}
	public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
		//已经是Advisor了,直接返回
		if (adviceObject instanceof Advisor) {
			return (Advisor) adviceObject;
		}
		//可以没有pointCut,但必须实现Advice接口
		if (!(adviceObject instanceof Advice)) {
			throw new UnknownAdviceTypeException(adviceObject);
		}
		Advice advice = (Advice) adviceObject;	
		//实现了MethodInterceptor,包装为DefaultPointcutAdvisor(PointCut为Pointcut.TRUE)
		if (advice instanceof MethodInterceptor) {
			// So well-known it doesn't even need an adapter.
			return new DefaultPointcutAdvisor(advice);
		}
		//没有实现MethodInterceptor接口
		//adapters 包含 MethodBeforeAdviceAdapter AfterReturningAdviceAdapter ThrowsAdviceAdapter
		for (AdvisorAdapter adapter : this.adapters) {
			// Check that it is supported.
			//必须是实现AfterReturningAdvice MethodBeforeAdvice ThrowsAdvice接口中一种
			//包装为DefaultPointcutAdvisor
			if (adapter.supportsAdvice(advice)) {
				return new DefaultPointcutAdvisor(advice);
			}
		}
		throw new UnknownAdviceTypeException(advice);
	}
	public Object getProxy(@Nullable ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		//isOptimize默认false
		//isProxyTargetClass没有在EnableAspectJAutoProxy注解去配置,则默认为false
		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.");
			}
			//实现了接口,或者已经是被jdk动态代理的类
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				//则采用jdk动态代理
				return new JdkDynamicAopProxy(config);
			}
			//采用cglib动态代理
			return new ObjenesisCglibAopProxy(config);
		}
		//ProxyTargetClass为false,则采用jdk动态代理
		else {
			//config为proxyFactory,将config赋值给JdkDynamicAopProxy中的advised字段
			return new JdkDynamicAopProxy(config);
		}
	}
	//已jdk动态代理为例
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		//生成代理对象返回
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	 }

代理对象的具体拦截逻辑

  以jdk动态代理为例,来看JdkDynamicAopProxy的具体的拦截逻辑。

	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		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);
			}
			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;
			
			//如果配置的exposeProxy为true,则将代理对象放入threadLocal中
			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.
			//对当前被调用的方法和符合的advisor的poincut进行match,拿到所有符合的advice,将所有的advice做为MethodInterceptor类型的list集合返回(方法拦截链)
			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()) {
				// 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...
				//包装为ReflectiveMethodInvocation对象
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				// advice和目标方法调用
				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);
			}
		}
	}
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
		MethodCacheKey cacheKey = new MethodCacheKey(method);
		//第一次进来没有
		List<Object> cached = this.methodCache.get(cacheKey);
		if (cached == null) {
			//获取被调用方法可用的方法拦截链
			cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
					this, method, targetClass);
			//后续再次调用,直接从methodCache获取到
			this.methodCache.put(cacheKey, cached);
		}
		return cached;
	}
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
		Advisor[] advisors = config.getAdvisors();
		List<Object> interceptorList = new ArrayList<>(advisors.length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		Boolean hasIntroductions = null;
		
		//循环所有的advisors
		for (Advisor advisor : advisors) {
			//InstantiationModelAwarePointcutAdvisorImpl实现了PointcutAdvisor接口
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				//先调用ClassFilter的matches方法
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
				    //再调用MethodMatcher的matches方法
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					boolean match;
					//引介类型的MethodMatcher 
					if (mm instanceof IntroductionAwareMethodMatcher) {
						if (hasIntroductions == null) {
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
						}
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					}
					//非引介类型
					else {
						match = mm.matches(method, actualClass);
					}
					//匹配成功
					if (match) {
						//将advice包装为MethodInterceptor返回
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						//如果MethodMatcher的isRuntime返回true(可以自己实现MethodMatcher接口,重写isRuntime,返回为true,可以不只匹配到方法级别判断是否拦截,还可以匹配到参数内容判断是否拦截)
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							//包装为InterceptorAndDynamicMethodMatcher对象
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			//引介类型的advisor,只做ClassFilter匹配。
			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;
	}
	public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<>(3);
		Advice advice = advisor.getAdvice();
		//如果advice实现了MethodInterceptor
		if (advice instanceof MethodInterceptor) {
			interceptors.add((MethodInterceptor) advice);
		}
		//adapters 包含 MethodBeforeAdviceAdapter AfterReturningAdviceAdapter ThrowsAdviceAdapter
		for (AdvisorAdapter adapter : this.adapters) {
			//判断advice是否实现 MethodBeforeAdvice AfterReturningAdvice ThrowsAdvice接口
			if (adapter.supportsAdvice(advice)) {
				//将advice封装为 MethodBeforeAdviceInterceptor  AfterReturningAdviceInterceptor ThrowsAdviceInterceptor返回
				interceptors.add(adapter.getInterceptor(advisor));
			}
		}
		if (interceptors.isEmpty()) {
			throw new UnknownAdviceTypeException(advisor.getAdvice());
		}
		return interceptors.toArray(new MethodInterceptor[0]);
	}
	public Object proceed() throws Throwable {
		
		//proceed方法会被多次调用,知道调用完所有的方法拦截链的方法,最后调用目标方法

		// We start with an index of -1 and increment early.
		//currentInterceptorIndex 初始为-1
		//currentInterceptorIndex 等于interceptorsAndDynamicMethodMatchers方法拦截链的大小-1
		//也就是,方法拦截链的方法已经全部调用到了
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			//反射调用目标方法
			return invokeJoinpoint();
		}
		
		//++this.currentInterceptorIndex
		//根据下标拿到方法拦截链里的方法
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		//如果是InterceptorAndDynamicMethodMatcher类型
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
			//this.arguments (目标方法的参数)控制更细粒度的拦截
			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
				//调用拦截方法
				return dm.interceptor.invoke(this);
			}
			else {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				//递归调用proceed方法,执行其他拦截方法
				return proceed();
			}
		}
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
			//调用拦截方法
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

  来看看常用的几个注解生成的拦截逻辑

public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable {

	public AspectJAroundAdvice(
			Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

		super(aspectJAroundAdviceMethod, pointcut, aif);
	}


	@Override
	public boolean isBeforeAdvice() {
		return false;
	}

	@Override
	public boolean isAfterAdvice() {
		return false;
	}

	@Override
	protected boolean supportsProceedingJoinPoint() {
		return true;
	}

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		if (!(mi instanceof ProxyMethodInvocation)) {
			throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
		}
		ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
		//将MethodInvocation封装到ProceedingJoinPoint 中
		ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
		JoinPointMatch jpm = getJoinPointMatch(pmi);
		//反射调用拦截方法,这里ProceedingJoinPoint参数参入给了拦截方法,自己手动调用proceed方法,完成全部调用。
		return invokeAdviceMethod(pjp, jpm, null, null);
	}

	/**
	 * Return the ProceedingJoinPoint for the current invocation,
	 * instantiating it lazily if it hasn't been bound to the thread already.
	 * @param rmi the current Spring AOP ReflectiveMethodInvocation,
	 * which we'll use for attribute binding
	 * @return the ProceedingJoinPoint to make available to advice methods
	 */
	protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) {
		return new MethodInvocationProceedingJoinPoint(rmi);
	}

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

	
	//调用目标方法之前
	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		//反射调用before方法
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		//递归调用proceed方法,执行其他的拦截方法
		return mi.proceed();
	}

}
public class AspectJAfterAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	public AspectJAfterAdvice(
			Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

		super(aspectJBeforeAdviceMethod, pointcut, aif);
	}


	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			//递归调用proceed方法,执行其他拦截器方法
			return mi.proceed();
		}
		finally {
			//反射执行拦截方法
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}

	@Override
	public boolean isBeforeAdvice() {
		return false;
	}

	@Override
	public boolean isAfterAdvice() {
		return true;
	}

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


	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		//递归调用proceed方法,执行其他的拦截方法,拿到返回值
		Object retVal = mi.proceed();
		//调用拦截方法
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}

}
public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	public AspectJAfterThrowingAdvice(
			Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

		super(aspectJBeforeAdviceMethod, pointcut, aif);
	}


	@Override
	public boolean isBeforeAdvice() {
		return false;
	}

	@Override
	public boolean isAfterAdvice() {
		return true;
	}

	@Override
	public void setThrowingName(String name) {
		setThrowingNameNoCheck(name);
	}
		
	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			//递归调用proceed方法,执行其他的拦截方法,
			return mi.proceed();
		}
		catch (Throwable ex) {
			if (shouldInvokeOnThrowing(ex)) {
				//执行拦截方法
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
	}

	/**
	 * In AspectJ semantics, after throwing advice that specifies a throwing clause
	 * is only invoked if the thrown exception is a subtype of the given throwing type.
	 */
	private boolean shouldInvokeOnThrowing(Throwable ex) {
		return getDiscoveredThrowingType().isAssignableFrom(ex.getClass());
	}
}

  到此,aop的主要流程就解析完毕了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值