文章结构
阅读本篇文章之前建议您首先查看上方两篇文章,因为本篇主要是描述了基于注解的方式和基于xml配置文件方式的异同点
- 源码阅读环境的搭建
- 首先简单描述了
bean容器AnnotationConfigApplicationContext - 然后源码执行的第一步就是关于包扫描一块的东西,也就是我们比较熟悉的注解
@ComponentScan - 扫描到了各个带有注解的类之后就是读取类呀、反射呀什么的来加载类
- 当
bean已经加载完后就是bean的注册逻辑了
相比较与之前两篇文章的长篇大论,这篇文章的篇幅要少很多,这主要得益于Spring的设计精妙和代码之优雅准备工作
本文会分析Spring的AOP模块的整体流程,分析过程需要使用一个简单的demo工程来启动Spring,demo工程我以备好,需要的童鞋自行在下方链接下载:
https://github.com/shiyujun/spring-framework
Demo工程示例代码
本文源码分析基于Spring5.0.0,所以pom文件中引入5.0的依赖
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.0.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.0.0.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.11</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.11</version></dependency></dependencies>
然后写一个简单的接口和实现类,跟IOC源码解析那几篇文章用的同一个工程,所以没有改名字
public interface IOCService {public String hollo();}public class IOCServiceImpl implements IOCService {public String hollo() {return "Hello,IOC";}}
增加bean的配置类,以及启动AOP
@EnableAspectJAutoProxy@Configurationpublic class AnnotationConfig {@Beanpublic IOCService iocService(){return new IOCServiceImpl();}}
创建切点
@Aspect@Componentpublic class AspectJTest {@Pointcut("execution(public * cn.shiyujun.service.IOCService.hollo(..))")public void testAOP(){}@Before("testAOP()")public void before(){System.out.println("before testAOP...");}@After("testAOP()")public void after(){System.out.println("after testAOP...");}@Around("testAOP()")public Object around(ProceedingJoinPoint p){System.out.println("around before testAOP...");Object o = null;try {o = p.proceed();} catch (Throwable e) {e.printStackTrace();}System.out.println("around after testAOP...");return o;}}
启动Spring
public class AnnotationIOCDemo {public static void main (String args[]){ApplicationContext context = new AnnotationConfigApplicationContext("cn.shiyujun.config");IOCService iocService=context.getBean(IOCService.class);System.out.println(iocService.hollo());}}
至此,demo工程准备完毕。我就不详细的说明了,直接开始看源码吧
@EnableAspectJAutoProxy注解
可以看到,在最开始的demo工程中,为了开启AOP功能,我使用了一个@EnableAspectJAutoProxy注
进入这个注解可以查看到这个注解的2个属性,相信大家都已经很熟悉了,就不相信的说明了。除此之外可以看到这个注解使用@Import注解引入了一个配置类
@Import注解:可以引入一个类,将这个类注入到Spring IOC容器中被当前Spring管理
@Import(AspectJAutoProxyRegistrar.class)public @interface EnableAspectJAutoProxy {//proxyTargetClass属性,默认false,尝试采用JDK动态代理织入增强(如果当前类没有实现接口则还是会使用CGLIB);如果设为true,则强制采用CGLIB动态代理织入增强boolean proxyTargetClass() default false;//通过aop框架暴露该代理对象,aopContext能够访问。为了解决类内部方法之间调用时无法增强的问题boolean exposeProxy() default false;}
看一下这个配置类的操作
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {AspectJAutoProxyRegistrar() {}public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//注册APC bean : AnnotationAwareAspectJAutoProxyCreatorAopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);//从导入者类上获取注解@EnableAspectJAutoProxy的属性,根据其中的 proxyTargetClass/exposeProxy, 对所创建的 APC 做设置AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);if (enableAspectJAutoProxy != null) {if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}}}
registerAspectJAnnotationAutoProxyCreatorIfNecessary() 方法的主要功能是注册或者升级AnnotationAwareAspectJAutoProxyCreator类 (这个类有多个优先级的实现)
这个类在AOP中非常的重要,它的主要功能就是根据@Point注解定义的切点来自动代理与表达式匹配的类。
下面看一个这个实现的逻辑
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); //如果已存在这个beanif (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");//判断优先级,如果优先级较高则替换原先的beanif (!cls.getName().equals(apcDefinition.getBeanClassName())) {int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());int requiredPriority = findPriorityForClass(cls);if (currentPriority < requiredPriority) {apcDefinition.setBeanClassName(cls.getName());}}return null;} else {//注册AnnotationAwareAspectJAutoProxyCreator到容器中,此类负责基于注解的AOP动态代理实现RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);beanDefinition.setSource(source);beanDefinition.getPropertyValues().add("order", -2147483648);beanDefinition.setRole(2);registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);return beanDefinition;}}
