Spring系列.AOP原理简析

Spring AOP使用简介

Spring的两大核心功能是IOC和AOP。当我们使用Spring的AOP功能时是很方便的。只需要进行下面的配置即可。

@Component @Aspect public class MyAspect { //PointCut匹配的方法必须是Spring中bean的方法 //Pointcut可以有下列方式来定义或者通过&& || 和!的方式进行组合. //下面定义的这些切入点就可以通过&& ||组合 private static Logger logger = LoggerFactory.getLogger(MyAspect.class); //*:代表方法的返回值可以是任何类型 //整个表达式匹配controller包下面任何的的echo方法,方法入参乐意是任意 @Pointcut("execution(* com.csx.demo.spring.boot.controller.*.echo(..))") public void pointCut1(){} @Before("pointCut1()") public void befor(){ logger.info("前置通知vvvv..."); logger.info("我要做些事情..."); } }

然后再开启注解

//自动选择合适的AOP代理 //传统xml这样配置:<aop:aspectj-autoproxy/> //exposeProxy = true属性设置成true,意思是将动态生成的代理类expose到AopContext的ThreadLocal线程 //可以通过AopContext.currentProxy();获取到生成的动态代理类。 //proxyTargetClass属性设置动态代理使用JDK动态代理还是使用CGlib代理,设置成true是使用CGlib代理,false的话是使用JDK动态代理 //注意:如果使用Spring Boot的话,下面的配置可以不需要。AopAutoConfiguration这个自动配置类中已经自动开启了AOP //默认使用CGLIB动态代理,Spring Boot配置的优先级高于下面的配置 @Configuration @EnableAspectJAutoProxy(exposeProxy = true,proxyTargetClass = false) public class AopConfig { }

通上面的配置,当我们调用controller包下面的任何类的echo方法时就会触发前置通知。其实这个说法不是很准确。因为我们调用的类已经不是我们自己写的类了。而是Spring框架通过动态代理生成的类。

稍微了解一点Spring AOP的同学都会知道Spring的AOP是通过动态代理实现的。那Spring是怎么生成动态代理类,并将Advice织入代理类的呢?整个流程是怎样的呢?下面就分析下Spring生成动态代理类的过程。

需要说明下的是,本博客旨在梳理整个AOP动态代理的过程,细节方面需要大家自己去看。

@EnableAspectJAutoProxy干了些啥

如果让你从头开始研究下AOP的原理,你是不是一头雾水,根本不知道从何入手。但其实看Spring的代码有个小技巧:如果你要研究一个功能,可以从开启这个功能的Enable注解开始看。Spring的很多功能都是通过Enable注解开启的,所以这些注解肯定和这些功能相关。

那么这边我们可以从@EnableAspectJAutoProxy这个注解开始着手,看下这个注解做了些什么操作。

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { //设置为true的话就一直使用cglib动态代理 //设置为false的话,对于接口使用jdk动态代理,对于类使用cglib代理 boolean proxyTargetClass() default false; boolean exposeProxy() default false; }

看到上面的@Impoer注解,我们很自然就会想到去看AspectJAutoProxyRegistrar这个类。

//AspectJAutoProxyRegistrar源代码 class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { /** * 主要作用也就是注册AnnotationAwareAspectJAutoProxyCreator */ @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //注册AnnotationAwareAspectJAutoProxyCreator的BeanDefinition AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy != null) { //给上面注册的BeanDefinition中添加两个属相proxyTargetClass和exposeProxy if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } }

我们可以看到上面的类中也没干什么特别的事情,就注册了一个BeanDefinition。如果我们点进去看下AnnotationAwareAspectJAutoProxyCreator这个类的源代码会发现这个类竟然实现了InstantiationAwareBeanPostProcessor这个接口。熟悉Spring尿性的朋友会敏锐的感觉到Spring可能是在postProcessBeforeInstantiation或者postProcessAfterInstantiation这些方法中对Bean进行动态代理的。

“大胆假设,小心求证”,让我们带着这个猜想去看看AnnotationAwareAspectJAutoProxyCreator到底干了些什么?

AnnotationAwareAspectJAutoProxyCreator生成动态代理类 @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) { Object cacheKey = getCacheKey(beanClass, beanName); if (!StringUtils.hasLength(beanName) || !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; } } // 一般不指定CustomTargetSource,所以不会进入这段代码,所以关键代码在 // postProcessAfterInitialization中 // 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. TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { if (StringUtils.hasLength(beanName)) { 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; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxxfd.html