内容简介:在上一篇自动织入方式需要AnnotationAwareAspectJAutoProxyCreator类的支持,通过将AnnotationAwareAspectJAutoProxyCreator和需要的Aspect切面、以及目标对象声明在IOC容器中,在容器启动期间,AnnotationAwareAspectJAutoProxyCreator将自动为目标对象生成织入切面逻辑的代理对象Spring AOP支持以下的Pointcut表达式
在上一篇 spring-AOP(一)实现原理 我们了解了如何使用ProxyFactory来创建AOP代理对象,但其过程需要实现一些接口,并且需要一些比较复杂的配置。因此,在spring2.0之后,提供了一种较为便利的方式。 使用@Aspect注解声明一个切面类,之后通过@EnableAspectJAutoProxy注解来注册代理生成类AnnotationAwareAspectJAutoProxyCreator。下面我们来看一下其原理
spring中如何使用@AspectJ
织入方式
手动织入
- 首先需要定义一个Aspect
package com.luhc.springaop.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; /** * @author luhuancheng * @date 2018/11/20 */ @Aspect public class PerformanceTraceAspect { @Pointcut("execution(* *..*method1()) || execution(* *..*method2())") public void pointcutName(){} @Pointcut("@annotation(AnyJoinpointAnnotation)") public void matchPointcut(){} @Before("matchPointcut()") public void before() { System.out.println("+++++++++@annotation++++++++++"); } @Around("pointcutName()") public Object performanceTrace(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); try { return joinPoint.proceed(); } finally { System.out.println(String.format("cost time %s", System.currentTimeMillis() - start)); } } } 复制代码
- 通过AspectJProxyFactory手动织入
private static void manualWeaver() { // 手动织入 AspectJProxyFactory weaver = new AspectJProxyFactory(); weaver.setProxyTargetClass(true); // 声明目标对象 weaver.setTarget(new Foo()); // 声明切面 weaver.addAspect(PerformanceTraceAspect.class); // 获取代理 Object proxy = weaver.getProxy(); // 执行已经织入切面逻辑的方法 ((Foo) proxy).method1(new FlyImpl()); ((Foo) proxy).method2(); } 复制代码
自动织入
自动织入方式需要AnnotationAwareAspectJAutoProxyCreator类的支持,通过将AnnotationAwareAspectJAutoProxyCreator和需要的Aspect切面、以及目标对象声明在IOC容器中,在容器启动期间,AnnotationAwareAspectJAutoProxyCreator将自动为目标对象生成织入切面逻辑的代理对象
- 声明配置
package com.luhc.springaop.aspect; import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author luhuancheng * @date 2018/11/21 */ @Configuration public class AspectConfigure { /** * 自动织入器 * @return */ @Bean public AnnotationAwareAspectJAutoProxyCreator proxyCreator() { AnnotationAwareAspectJAutoProxyCreator proxyCreator = new AnnotationAwareAspectJAutoProxyCreator(); // 默认为false,如果目标对象未实现接口的话,其代理对象也是通过cglib生成 proxyCreator.setProxyTargetClass(false); return proxyCreator; } /** * 未实现接口的目标对象 * @return */ @Bean public Foo foo() { return new Foo(); } /** * 切面 * @return */ @Bean public PerformanceTraceAspect performanceTraceAspect() { return new PerformanceTraceAspect(); } } 复制代码
- 从IOC容器中取出织入切面后的代理对象
private static void autoWeaver() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AspectConfigure.class); Foo foo = context.getBean(Foo.class); // 此时的foo对象,是以及经过AnnotationAwareAspectJAutoProxyCreator处理后的代理对象 foo.method1(new FlyImpl()); foo.method2(); } 复制代码
@AspectJ形式的Pointcut声明方式
Spring AOP支持以下的Pointcut表达式
// 任意包下的具有任意参数、任意返回值的任意方法 // @Pointcut("execution(* *..*(..))") // com.luhc.springaop的任意子包下的任意类,springAOP只支持方法级别的JoinPoint,因此这个表达式将匹配指定类所声明的所有方法执行 // @Pointcut("within(com.luhc.springaop..*)") // 匹配代理对象类型为Foo的所有方法级的JoinPoint // @Pointcut("this(Foo)") // 匹配目标对象类型为Fly的所有方法级的JoinPoint // @Pointcut("target(Fly)") // 匹配传入参数类型为Fly和Foo的所有方法执行的JoinPoint,不关心方法在哪个类中定义 // @Pointcut("args(Fly,Foo)") // @within @target的区别在于@within是静态匹配、@target是在运行时动态匹配 // 匹配所有被注解AnyJoinpointAnnotation标注了的类的所有方法级的JoinPoint // @Pointcut("@within(AnyJoinpointAnnotation)") // 匹配所有目标对象呗注解AnyJoinpointAnnotation标注了的类的所有方法级的JoinPoint // @Pointcut("@target(AnyJoinpointAnnotation)") // 匹配方法参数类型被注解AnyJoinpointAnnotation标注了的所有方法级的JoinPoint // @Pointcut("@args(AnyJoinpointAnnotation)") // 匹配方法被注解AnyJoinpointAnnotation标注了的所有方法级的JoinPoint // @Pointcut("@annotation(AnyJoinpointAnnotation)") // 可以使用 || 和 && 来表达pointcut之间的逻辑运算 // @Pointcut("execution(* *..*method1()) || execution(* *..*method2())") 复制代码
剖开@AspectJ在SpringAOP中的真相
@AspectJ形式的Pointcut
AnnotationAwareAspectJAutoProxyCreator通过反射获取到@Pointcut注解的信息,在内部实例化为AspectJExpressionPointcut对象。 AspectJExpressionPointcut实现了ClassFilter、MethodMatcher,其内部实现逻辑代理给了PointcutParser,最终生成为PointcutExpression(PointcutExpressionImpl实现类)实例
@AspectJ形式的Advice
在Advice定义中访问Joinpoint处的方法参数
使用org.aspectj.lang.JoinPoint
将Advice方法的第一个参数声明为org.aspectj.lang.JoinPoint类型,我们可以通过调用org.aspectj.lang.JoinPoint相关方法获取需要的数据
@Before("matchPointcut()") public void before(org.aspectj.lang.JoinPoint joinPoint) { // 获取方法名 System.out.println(joinPoint.getSignature().getName()); System.out.println("+++++++++@annotation++++++++++"); } 复制代码
使用args标志符绑定
// 可以同时使用标识符和JoinPoint,但是JoinPoint必须放在第一个参数位置上 @Before("matchPointcut() && args(name)") public void before(JoinPoint joinPoint, String name) { System.out.println("获取到Joinpoint上的入参:" + name); System.out.println("获取到Joinpoint的方法名: " + joinPoint.getSignature().getName()); } 复制代码
捕获异常@AfterThrowing
@AfterThrowing(pointcut = "matchPointcut()", throwing = "e") public void afterThrowing(JoinPoint joinPoint, RuntimeException e) { System.out.println("方法:" + joinPoint.getSignature().getName() + "发生异常:" + e.getMessage()); } 复制代码
捕获返回值@AfterReturning
@AfterReturning(pointcut = "pointcutName()", returning = "result") public void afterReturning(JoinPoint joinPoint, String result) { System.out.println("方法:" + joinPoint.getSignature().getName() + "获得返回值:" + result); } 复制代码
方法正常执行完成后(未抛出异常)@After
@After("pointcutName()") public void after(JoinPoint joinPoint) { System.out.println("方法:" + joinPoint.getSignature().getName() + ": 执行完毕"); } 复制代码
@Around环绕方法
@Around与其他几个Advice注解不同,在@Around方法中,第一个参数必须为org.aspectj.lang.ProceedingJoinPoint
@Around("pointcutName()") public Object performanceTrace(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); try { return joinPoint.proceed(); } finally { System.out.println(String.format("cost time %s", System.currentTimeMillis() - start)); } } 复制代码
公开当前调用的代理对象
// 在目标对象方法中,通过此方法可以获取当前目标对象的代理对象 AopContext.currentProxy() 复制代码
@AspectJ形式的Spring AOP代理自动生成原理
一个例子
我们使用注解配置的一个spring aop的demo(新版本的spring中推荐使用注解来配置容器)
// 假设这是一个业务接口 public interface Fly { void fly(); } // 业务接口实现 public class FlyImpl implements Fly { @Override public void fly() { System.out.println("++++++++++++++++ Fly ++++++++++++++++"); } } // 声明一个切面 @Aspect public class PerformanceTraceAspect { // 匹配任意返回值、任意包下的、任意参数的fly方法。在这个demo中,将匹配到com.luhc.springaop.aspect.FlyImpl#fly这个方法 @Pointcut("execution(* *..*fly(..))") public void pointcutName(){} // 声明切入的前置逻辑 @Before("pointcutName()") public void before(JoinPoint joinPoint) { // 可以通过JoinPoint获取到pointcut方法的详细信息 System.out.println("Before --> 获取到Joinpoint的方法名: " + joinPoint.getSignature().getName()); } // 声明切入的后置逻辑 @After("pointcutName()") public void after(JoinPoint joinPoint) { // 可以通过JoinPoint获取到pointcut方法的详细信息 System.out.println("After --> 获取到Joinpoint的方法名: " + joinPoint.getSignature().getName()); } // 声明切入的环绕逻辑(即在方法执行前后切入逻辑) @Around("pointcutName()") public Object performanceTrace(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); try { // 调用执行链 return joinPoint.proceed(); } finally { System.out.println(String.format("cost time %s", System.currentTimeMillis() - start)); } } } // 配置类 @Configuration // 启用AOP @EnableAspectJAutoProxy public class AspectConfigure { /** * 实现接口的目标对象 * @return */ @Bean public Fly fly() { return new FlyImpl(); } /** * 切面 * @return */ @Bean public PerformanceTraceAspect performanceTraceAspect() { return new PerformanceTraceAspect(); } } // 运行应用 public class AspectJDemo { // 使用配置类,初始化容器 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AspectConfigure.class); // 从容器中获取业务接口(此时已经是被处理过的代理对象,即已经切入了切面逻辑) Fly fly = context.getBean(Fly.class); fly.fly(); } 复制代码
剖析demo运行机制
从@EnableAspectJAutoProxy注解开始解开神秘面纱
注解EnableAspectJAutoProxy的定义
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { // 是否使用cglib来生成代理 boolean proxyTargetClass() default false; // 是否将代理绑定到ThreadLocal,后续在目标类中可以使用AopContext.currentProxy()来获取代理对象 boolean exposeProxy() default false; } 复制代码
AspectJAutoProxyRegistrar配置类
重点在其元注解@Import上(有机会再分析一下关于spring的@Import注解导入机制),其导入了配置类AspectJAutoProxyRegistrar
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { /** * Register, escalate, and configure the AspectJ auto proxy creator based on the value * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing * {@code @Configuration} class. */ @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 重点!!此处向容器注入了AnnotationAwareAspectJAutoProxyCreator类 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } 复制代码
注册过程
public abstract class AopConfigUtils { /** * Stores the auto proxy creator classes in escalation order. */ private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<Class<?>>(); /** * Setup the escalation list. * 在spring中,默认存在三个代理生成类。优先级别从上到下排序,越往后优先级越高 */ static { APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class); // 最高优先级 } private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { // 如果容器当前已经注册了代理生成器类,则比较其与AnnotationAwareAspectJAutoProxyCreator的优先级。取优先级最高的那个作为代理生成器注册在容器中。 // 显然AnnotationAwareAspectJAutoProxyCreator被注册到容器中 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; } } 复制代码
注册流程总结
- @EnableAspectJAutoProxy注解导入了配置类AspectJAutoProxyRegistrar
- 配置类AspectJAutoProxyRegistrar调用了AopConfigUtils来注册代理生成器AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator如何做到自动生成代理
类结构
主流程
源码分析
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { Object cacheKey = getCacheKey(beanClass, beanName); if (beanName == null || !this.targetSourcedBeans.contains(beanName)) { if (this.advisedBeans.containsKey(cacheKey)) { return null; } if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } } // Create proxy here if we have a custom TargetSource. // Suppresses unnecessary default instantiation of the target bean: // The TargetSource will handle target instances in a custom fashion. if (beanName != null) { TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { this.targetSourcedBeans.add(beanName); Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } } return null; } // 生成代理对象 @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; } 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. // 获取切面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, 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 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()); } } 复制代码
总结
- 描述了@AspectJ形式的Spring AOP如何使用
- spring AOP可以使用的@AspectJ标识符,如execution、within、this、target、@annotation等
- 描述了spring内部是如何使用@EnableAspectJAutoProxy注解来启用Spring AOP功能的,以及代理生成器AnnotationAwareAspectJAutoProxyCreator的内部流程时如何根据@Aspect类,来自动生成代理的
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- java反射原理, 注解原理
- 注解的原理又是怎么一回事
- Spring 中 Transactional 注解原理
- Spring源码分析:@Autowired注解原理分析
- 【Spring】Autowired原理及与Resource注解区别
- Spring 中异步注解 @Async 的使用、原理及使用时可能导致的问题
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
宇宙涟漪中的孩子
谢云宁 / 四川科学技术出版社 / 2017-11 / 28.00元
近未来。日冕科技公司通过建造围绕太阳的光幕搜集了近乎无穷的能源,这些能源主要用于地球上的网络空间建设。随着全球网络时间频率的不断提升,越来越多的人选择接驳进虚拟空间,体验现实中难以经历的丰富人生。 网络互动小说作者宁天穹一直自认为是这些人中普通的一员,有一天却被一名读者带进反抗组织,了解到日冕公司的各种秘密,并被告知自己的小说将在抵抗运动中起到重要作用。 起初他拒绝参与,但看到地球被笼......一起来看看 《宇宙涟漪中的孩子》 这本书的介绍吧!