文章结构
阅读本篇文章之前建议您首先查看上方两篇文章,因为本篇主要是描述了基于注解的方式和基于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
@Configuration
public class AnnotationConfig {
@Bean
public IOCService iocService(){
return new IOCServiceImpl();
}
}
创建切点
@Aspect
@Component
public 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 : AnnotationAwareAspectJAutoProxyCreator
AopConfigUtils.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"); //如果已存在这个bean
if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
//判断优先级,如果优先级较高则替换原先的bean
if (!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;
}
}