Spring AOP 要实现的是在我们原来写的代码的基础上,进行一定的包装,如在方法执行前、方法返回后、方法抛出异常后等地方进行一定的拦截处理或者增强处理。Aop依赖于IOC,Aop可以看做是调用IOC的后置处理器来实现的。 默认地,如果使用接口的,用 JDK 提供的动态代理实现,如果没有接口,使用 CGLIB 实现。Spring 3.2 以后,spring-core 直接就把 CGLIB 和 ASM 的源码包括进来了,这也是为什么我们不需要显式的引入这两个依赖。
开源php源码, 作为 Java 开发者,我们都很熟悉 AspectJ 这个词,甚至于我们提到 AOP 的时候,想到的往往就是 AspectJ,但真实情况是Spring虽然提供了AspectJ的支持,但只用到的AspectJ的切点解析和匹配。比如 @Aspect、@Pointcut、@Before、@After 、@Around 等注解都是来自于 AspectJ,利用AspectJ的解析execution、@Annotation等表达式的能力去解析,因为AspectJ也是一个优秀的框架,Spring为了不重复造轮子嘛,就利用到了这些。但是动态代理功能的实现是纯 Spring AOP 自己实现的。AspectJ 能干很多 Spring AOP 干不了的事情,它是 AOP 编程的完全解决方案。Spring AOP 致力于解决的是企业级开发中最普遍的 AOP 需求(方法织入),而不是力求成为一个像 AspectJ 一样的 AOP 编程完全解决方案。
在性能方面,由于Spring AOP 是基于代理实现的,在容器启动的时候需要生成代理实例,在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ 那么好。
Spring AOP术语解释
问题:为什么spring 不使用AspectJ全套的东西呢?而是只使用了部分呢?
猜测原因如下:
spring源码讲解。相同点 :
不同点:
代理类型 | JDK | Cglib |
---|---|---|
使用场景 | 目标类实现了接口,且未指定ProxyTargetClass = true | 目标类未实现接口 |
代理类的字节码文件数量 | 根据接口生成1个$proxy.class文件 | 根据具体类生成多个cglib.class文件 |
调用 原始方法 的方式 | 反射 | 直接调用(正因为直接调用速度快,所以cglib在调用时比jdk快) |
在被增强的方法中调用其他方法时 | 其他方法不会被增强,动态代理类只调用一次 | 其他方法会被增强,因为每一个方法都会调用动态代理类! |
代码形式 | InvocationHandler.invoke | MethodInterceptor.intercept |
@Aspect //切面
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DataSourceAspect {protected Logger logger = LoggerFactory.getLogger(getClass());//切入点,寻找带有@DataSource注解的方法@Pointcut("@annotation(com.chinalife.policy_manage.common.datasource.annotation.DataSource) " +"|| @within(com.chinalife.policy_manage.common.datasource.annotation.DataSource)")public void dataSourcePointCut() {}//环绕通知 ProceedingJoinPoint 连接点/切入点@Around("dataSourcePointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {MethodSignature signature = (MethodSignature) point.getSignature();//获取目标类Class targetClass = point.getTarget().getClass();//获取目标方法Method method = signature.getMethod();//获取目标类上的@DataSource注解DataSource targetDataSource = (DataSource)targetClass.getAnnotation(DataSource.class);//获取目标方法上的@DataSource注解DataSource methodDataSource = method.getAnnotation(DataSource.class);//如果@DataSource注解不为空,执行增强逻辑if(targetDataSource != null || methodDataSource != null){String value;if(methodDataSource != null){value = methodDataSource.value();}else {value = targetDataSource.value();}DynamicContextHolder.push(value);logger.debug("set datasource is {}", value);}try {return point.proceed();} finally {DynamicContextHolder.poll();logger.debug("clean datasource");}}
}
public class LogAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {String methodName = method.getName();System.out.println("执行目标方法【" + methodName + "】的<前置通知>,入参" + Arrays.asList(args));}
}
public class LogInterceptor implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println(getClass()+"调用方法前");Object ret=invocation.proceed();System.out.println(getClass()+"调用方法后");return ret;}
}
然后把他们注册进容器中!即可实现增强逻辑,运行结果如下: @Bean public NameMatchMethodPointcutAdvisor tulingLogAspect() { NameMatchMethodPointcutAdvisor advisor=new NameMatchMethodPointcutAdvisor(); // 通知(Advice) :是我们的通知类 // 通知者(Advisor):是经过包装后的细粒度控制方式。 advisor.setAdvice(tulingLogAdvice()); advisor.setMappedNames("div"); return advisor; }
js框架原理?Aop源码大概分为以下几步:
AopAutoConfiguration
类中带有@EnableAspectJAutoProxy
,项目启动即开启对spring AOP的支持,该注解注册了AnnotationAwareAspectJAutoProxyCreator
类,该类实现了bean的后置处理器,可以在类创建过程中做一些其他操作postProcessBeforeInstantiation
方法中,解析切面类,把通知封装成Advisor,并放入缓存advisorsCache中!postProcessAfterInitialization
方法中,拿到缓存中所有的Advisor,根据切入点PointCut与当前bean做匹配,匹配成功与否决定是否需要创建动态代理!如果匹配到了,则根据实际情况创建动态代理 在spring boot项目中,项目启动时会自动加载许多自动配置类,以完成项目结构!其中就有AopAutoConfiguration
,该类的作用就是为项目提供Aop的支持,一种是jdk
动态代理,一种是cglib
动态代理
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
//自动配置类
public class AopAutoConfiguration {@Configuration(proxyBeanMethods = false)@ConditionalOnClass(Advice.class)static class AspectJAutoProxyingConfiguration {@Configuration(proxyBeanMethods = false)//开启自动代理:@EnableAspectJAutoProxy@EnableAspectJAutoProxy(proxyTargetClass = false)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",matchIfMissing = false)//jdk动态代理static class JdkDynamicAutoProxyConfiguration {}@Configuration(proxyBeanMethods = false)@EnableAspectJAutoProxy(proxyTargetClass = true)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",matchIfMissing = true)//Cglib动态代理static class CglibAutoProxyConfiguration {}}
可以看到自动配置类AopAutoConfiguration
除了帮我们配置了jdk动态代理和cglib动态代理,还有一个注解@EnableAspectJAutoProxy
,这个注解内部通过@Import
导入了一个bean定义的注册器AspectJAutoProxyRegistrar
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class) //通过`@Import`导入了一个bean定义的注册器
public @interface EnableAspectJAutoProxy {
这个注册器帮我们注册了一个Aop中非常重要的类AnnotationAwareAspectJAutoProxyCreator
!该类实现了bean的后置处理器BeanPostProcessor
,可以在类创建前后做一些操作,具体如下:
postProcessBeforeInstantiation
方法中,解析切面类,把通知封装成Advisor,并放入缓存advisorsCache中!postProcessAfterInitialization
方法中,匹配切入点,创建动态代理 @Nullablepublic static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {// 注册了一个Aop中非常重要的bean的后置处理器`AnnotationAwareAspectJAutoProxyCreator`!return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);}
java ssm框架?看一下AnnotationAwareAspectJAutoProxyCreator
的继承关系:
①: 通过bean的后置处理器解析切面类,把通知封装成Advisor,并放入advisorsCache缓存中!
与spring事务一样,Aop也是通过bean的后置处理器解析带有@AspectJ的bean,这个bean的后置处理器在容器创建的时候就被注册,在解析时可以直接调用!
注意:下图中的AspectJAwareAdvisorAutoProxyCreator
正是AnnotationAwareAspectJAutoProxyCreator
的父类
Spring AOP发生在创建bean的时候,也就是finishBeanFactoryInitialization()
内部的creatBean()
方法中
try {Object scopedInstance = scope.get(beanName, () -> {beforePrototypeCreation(beanName);try {//创建bean的方法return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}});bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}
html5框架、 在creatBean()
方法内部,resolveBeforeInstantiation
方法会扫描@Aspect
注解,解析切面类,把通知封装成Advisor,并放入缓存advisorsCache
中!
try {/*** 第一次调用bean的后置处理器,事务在这里不会被调用,aop的才会被调用* 为啥aop在这里调用了?因为在此处需要解析出对应的切面保存到缓存中*/Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}}
进入resolveBeforeInstantiation
方法:
@Nullableprotected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {Object bean = null;if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// 如果有bean后置处理器: InstantiationAwareBeanPostProcessorsif (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {Class<?> targetType = determineTargetType(beanName, mbd);if (targetType != null) {//调用 postProcessBeforeInstantiation 方法bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);if (bean != null) {//调用 postProcessAfterInitialization 方法bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);}}}mbd.beforeInstantiationResolved = (bean != null);}return bean;}
在实例化bean之前,会第一次调用bean的后置处理器,解析到所有的@AspectJ
的类,保存到缓存中。那怎么解析的呢?进入上文resolveBeforeInstantiation
方法中的applyBeanPostProcessorsBeforeInstantiation
方法中!
@Nullableprotected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {/*** 获取容器中的所有后置处理器*/for (BeanPostProcessor bp : getBeanPostProcessors()) {//判断后置处理器是不是InstantiationAwareBeanPostProcessorif (bp instanceof InstantiationAwareBeanPostProcessor) {//把我们的BeanPostProcessor强制转为InstantiationAwareBeanPostProcessorInstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;/*** 【很重要】* 我们AOP @EnableAspectJAutoProxy 为我们容器中导入了 AnnotationAwareAspectJAutoProxyCreator* 我们事务注解@EnableTransactionManagement 为我们的容器导入了 InfrastructureAdvisorAutoProxyCreator* 都是实现了我们的 BeanPostProcessor接口,InstantiationAwareBeanPostProcessor,* 进行后置处理解析切面*/Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);if (result != null) {return result;}}}return null;}
@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {//构建我们的缓存keyObject cacheKey = getCacheKey(beanClass, beanName);if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {//已经被解析过 直接返回if (this.advisedBeans.containsKey(cacheKey)) {return null;}/*** 判断是不是基础的bean* 判断是不是应该跳过 (aop解析直接解析出我们的切面信息(并且把我们的切面信息进行保存),而事务在这里是不会解析的)*/if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return null;}}
由于AOP使用的是AnnotationAwareAspectJAutoProxyCreator
类,所以选择这个类中的shouldSkip方法,在所有的bean定义中选择是否跳过,如果带有@AspectJ
注解,就不跳过,把这个类中的带有@Before、@After、@Around
等注解的方法封装成一个个Advisor(顾问),它是Pointcut和Advice的一种结合! 并添加进集合中
@Overrideprotected List<Advisor> findCandidateAdvisors() {//找出事务相关的advisorList<Advisor> advisors = super.findCandidateAdvisors();//找出Aspect相关的信息之后封装为一个advisorif (this.aspectJAdvisorsBuilder != null) {advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());}//返回我们所有的通知return advisors;}
buildAspectJAdvisors
方法内部会把带有下面的注解的挨个解析成Advisor
//获取到切面类中的所有方法,但是该方法不会解析标注了@PointCut注解的方法for (Method method : getAdvisorMethods(aspectClass)) {//挨个去解析我们切面中的方法Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);if (advisor != null) {advisors.add(advisor);}}//看是否含有这些注解!private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
PHP源码?把解析到的Advisor放入advisorsCache缓存中
//加入到缓存中if (this.beanFactory.isSingleton(beanName)) {this.advisorsCache.put(beanName, classAdvisors);}
原理图:
注意:以上解析切面的操作,是在bean的第一个后置处理器postProcessBeforeInstantiation中完成的!
② 根据 Advisor 中的 PointCut 决定当前bean是否创建动态代理
我们都知道创建动态代理的时机是在初始化之后(如果存在循环依赖则在实例化之后!),所以在源码中创建动态代理在doCreateBean
方法中的initializeBean
方法中,这个方法内部调用了bean的后置处理器postProcessAfterInitialization
,在后置处理器中完成了判断和动态代理的创建
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {//1.回调各种 Aware 接口invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {//2.调用 BeanPostProcessorsBeforeInitialization 扩展wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {//3.调用实现InitializingBean的afterPropertiesSet方法// 调用xml方式的 bean标签里配置init-mothod属性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()) {//4.调用 BeanPostProcessorsAfterInitialization 扩展,动态代理在这里!wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}***********************************************************************************************
==================== applyBeanPostProcessorsAfterInitialization 内部创建动代理 ==================
***********************************************************************************************public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {/** 【很重要】* 我们AOP @EnableAspectJAutoProxy 为我们容器中导入了 AnnotationAwareAspectJAutoProxyCreator* 我们事务注解@EnableTransactionManagement 为我们的容器导入了 InfrastructureAdvisorAutoProxyCreator* 都是实现了我们的 BeanPostProcessor接口,InstantiationAwareBeanPostProcessor,* 在这里实现的是BeanPostProcessor接口的postProcessAfterInitialization来生成我们的代理对象 */Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;}
Java框架、AbstractAutoProxyCreator
抽象类扩展了这个后置处理器
/*** 在该后置方法中 我们的事务和aop的代理对象都是在这生成的* @param bean bean实例* @param beanName bean的名称* @return* @throws BeansException*/@Overridepublic Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {if (bean != null) {//获取缓存keyObject cacheKey = getCacheKey(bean.getClass(), beanName);//如果循环依赖时已经创建了代理,在这里把他移除掉!!if (this.earlyProxyReferences.remove(cacheKey) != bean) {//找到合适的就会被代理return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}
wrapIfNecessary
方法如下:主要内容就是拿到所有通知与当前类匹配,如果匹配成功则创建动态代理
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {//已经被处理过if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}//排除掉不需要增强的,比如Aop一些基础类if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}//是不是基础的bean 是不是需要跳过的if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}//***如果Advisor中的切点表达式命中了这个类,就返回适合本类的通知器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;}
其中getAdvicesAndAdvisorsForBean
方法中拿到了所有的Advisor与当前bean进行了匹配,返回合适本类的通知器advisor,如果合适的advisor
为空,则返回DO_NOT_PROXY
,不需要代理,表示不需要代理。
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {/*** 找到合适的增强器对象advisor*/List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);//若合适的通知器为空,则返回DO_NOT_PROXY,不需要代理if (advisors.isEmpty()) {return DO_NOT_PROXY;}return advisors.toArray();}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {//找到ioc容器中候选的通知 (找到Aop扫描到所有通知的Advisor,注意是所有的!!!)List<Advisor> candidateAdvisors = findCandidateAdvisors();//判断我们的通知Advisor能不能作用到当前的类上,返回合适本类的通知器advisorList<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);//加了一个内置的advisorextendAdvisors(eligibleAdvisors);//对我们的advisor进行排序,如果有多个切面类,则根据order排序//排序方式:异常--返回通知--后置通知--前置通知//这样排序的原因是,后边调用目标方法会讲!!if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;}
findAdvisorsThatCanApply
的调用链很深,这里就不再跟进了。
以上代码其实都是匹配阶段的代码,如果匹配成功,则进入上文wrapIfNecessary方法中的createProxy方法中,开始真正创建动态代理对象
web前端整站源码、创建动态代理是在createProxy方法中由ProxyFactory代理工厂来创建的
//创建一个代理对象工厂ProxyFactory proxyFactory = new ProxyFactory();。。。//真正的创建代理对象return proxyFactory.getProxy(getProxyClassLoader());
createAopProxy()
: 该方法用来创建我们的代理对象
代理形式由ProxyTargetClass和是否实现接口来决定!!
@Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {//判断我们是否前置指定使用cglib代理ProxyTargetClass =true fasle//判断是否实现了接口//判断是否是Optimize() 可手动设置,一般为false//三个判断只要有一个是true,就会使用cglib动态代理!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.");}//所targetClass是接口 使用的就是jdk代理if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}//cglib代理return new ObjenesisCglibAopProxy(config);}else {//动态代理return new JdkDynamicAopProxy(config);}}
至此,目标类的动态代理创建完成!
框架源码,③ 调用目标方法
如果使用的时jdk动态代理,在调用目标方法时会进入JdkDynamicAopProxy
中的 invoke
方法,把通知加入责任链,把Advisor转换成Inteceptor,通过责任链的方式递归调用proceed()方法完成对方法的增强调用处理
@Override@Nullablepublic 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 {//若执行代理对象的equals方法不需要代理if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {// The target does not implement the equals(Object) method itself.return equals(args[0]);}//若执行的是hashCode方法 不需要代理else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {// The target does not implement the hashCode() method itself.return hashCode();}//若执行的class对象是DecoratingProxy 也不要拦截器执行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;/*** 这个配置很重要很实用【暴露我们的代理对象到线程变量中】需要搭配@EnableAspectJAutoProxy(exposeProxy = true)* 一起使用.* 比如我们的aop中 multi和 mode方法都是被切入的方法,但是在切入的方法中通过* this来调用另外一个方法的时候,那么该方法就不会被代理执行,而是通过方法内部执行*还有的就是事务方法调用事务方法的时候 也需要这样*/if (this.advised.exposeProxy) {//把我们的代理对象暴露到线程变量中oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}//获取我们的目标对象target = targetSource.getTarget();//获取我们目标对象的classClass<?> targetClass = (target != null ? target.getClass() : null);//把我们的aop的advisor 转化为拦截器,相当于责任链的Handler顶级接口List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);//加入我们的拦截器链为空if (chain.isEmpty()) {//通过反射直接调用执行Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);}else {//创建一个方法调用对象MethodInvocation invocation =new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);//调用执行,注意proceed方法是递归调用,//会把需要的通知 通过责任链模式全部调用retVal = invocation.proceed();}Class<?> returnType = method.getReturnType();if (retVal != null && retVal == target &&returnType != Object.class && returnType.isInstance(proxy) &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {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()) {targetSource.releaseTarget(target);}if (setProxyContext) {AopContext.setCurrentProxy(oldProxy);}}}
注意:如果是jdk动态代理,在invoke方法中,会把代理对象暴露到本地线程变量ThreadLocal中,这样做的目的是:在A方法中调用另一个B方法时,保证两个方法都享受到动态代理的增强! 如果没有暴露出来,那么在调用B方法时,B方法是不会有增强逻辑的!而cglib就不存在这样的问题,因为他每次调用都会重新获取代理对象!
把advisor
转化为Inteceptor
拦截器,用于责任链调用,这个拦截器就相当于责任链中的顶级接口Handler。然后递归调用proceed方法
@Override@Nullablepublic Object proceed() throws Throwable {//执行到了最后一个拦截器的时候(从-1开始,结束条件执行目标方法是下标=拦截器的长度-1)if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {//如果责任链运行到了最后一个,表示增强代码结束,开始运行我们自己的代码逻辑return invokeJoinpoint();}/*** 获取第一个方法拦截器,按照之前排好序的advisor获取 * 顺序为:(新增的内置拦截器)-- 异常--返回通知--后置通知--前置通知*/Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {return dm.interceptor.invoke(this);}else {return proceed();}}else {//在这个地方需要注意,抵用第一个拦截器的invoke方法,传入的是this 当前的方法拦截器对象return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}
问题:那么为什么之前要按照 异常–返回通知–后置通知–前置通知 的方式来排序呢?
ssm框架原理, 答:是因为在递归调用时,递的过程最底层的通知(前置通知)首先被执行,然后才会有归的过程。 所以为了使通知顺序保持 前置通知 – 目标方法 – 异常通知(如果有异常) – 返回通知 – 后置通知 的顺序,就必须按照这样排序!!
6.1 目标方法无异常时
6.2 在目标方法抛出异常的情况下
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态