打开spring-boot-starter-aop的jar包:
里面一个类也没有,只是在pom中添加了几个依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.7.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.9.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
<scope>compile</scope>
</dependency>
说明配置类是在spring-boot-autoconfigure里面:
看下AopAutoConfiguration:
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}
代码很简单,首先看下@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class }),只有在EnableAspectJAutoProxy、Aspect、Advice和AnnotatedElement这些类存在的时候,配置才起作用,上一篇我们讲了只要加入aspectjweaver的jar,然后添加EnableAspectJAutoProxy就可以启用AOP,一样的判断逻辑。
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true):只有定义了spring.aop.auto并且值是true才启用,如果没定义那么默认就是true,一般我们都不会定义,因此只要加入了这个依赖默认AOP就是启用的。
继续看下面定义的2个bean:
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop",
name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
如果定义了spring.aop.proxy-target-class这个属性并且值是false的话,那么就启用EnableAspectJAutoProxy(proxyTargetClass = false),如果没定义默认值是false,
同理看下面一个bean的定义:
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop",
name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
如果定义了spring.aop.proxy-target-class这个属性并且值是true的话,那么就启用EnableAspectJAutoProxy(proxyTargetClass = true),如果没定义默认值是true
也就是说,如果我们没有明确的定义这个属性,那么SpringBoot的aop默认会启用@EnableAspectJAutoProxy(proxyTargetClass = true)。proxyTargetClass = true的意思是使用Cglib代理,因此,在SpringBoot中,默认是使用Cglib代理,而不是像Spring中那样,如果实现了接口就使用JDK的代理,没有实现接口就是用Cglib代理。
我们来证明下:
首先是使用Spring的方式:
//这是个接口
package com.github.xjs.aopdemo.service;
public interface IService {
void print(String msg);
}
//接口的一个实现
package com.github.xjs.aopdemo.service;
public class Service1 implements IService {
@Override
public void print(String msg){
log.info("Service1 print:{}", msg);
}
}
//它并没有实现IService接口
package com.github.xjs.aopdemo.service;
public class Service2 {
public void print(String msg){
log.info("Service2 print:{}", msg);
}
}
//这是切面
package com.github.xjs.aopdemo.springdemo;
@Aspect
public class DemoAdvice {
@Pointcut("execution(* com.github.xjs.aopdemo.service.*.*(..))")
public void pointCut(){
}
@Before("pointCut()")
public void before(){
log.info("---------before-------");
}
}
//配置类
@Configuration
@EnableAspectJAutoProxy
public class DemoApp {
@Bean
public DemoAdvice demoAdvice(){
return new DemoAdvice();
}
@Bean
public IService iService(){
return new Service1();
}
@Bean
public Service2 service2(){
return new Service2();
}
}
//测试一下
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(DemoApp.class);
IService s1 = ctx.getBean(IService.class);
Service2 s2 = ctx.getBean(Service2.class);
//class com.sun.proxy.$Proxy17
System.out.println(s1.getClass());
//class com.github.xjs.aopdemo.service.Service2$$EnhancerBySpringCGLIB$$de245da0
System.out.println(s2.getClass());
}
现在我们换成SpringBoot的方式:
@SpringBootTest
@RunWith(SpringRunner.class)
public class SpringBootDemoTest {
@Autowired
IService service;
@Test
public void testAop(){
System.out.println(service.getClass());
//class com.github.xjs.aopdemo.service.Service1$$EnhancerBySpringCGLIB$$f107fe5e
}
}
以上可以看的很清楚了,Spring方式的时候,service1是使用的JDK的动态代理,SpringBoot的时候,Service1是使用的Cglib代理。
继续看EnableAspectJAutoProxy的代码,其实这就跟SpringBoot没关系了:
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
//这个控制是否使用cglib,默认是false
boolean proxyTargetClass() default false;
//这个是说是否可以用AopContext来到当前的代理对象,具体的使用场景可以参考前一篇
boolean exposeProxy() default false;
}
看到我们非常熟悉的@Import,继续看AspectJAutoProxyRegistrar:
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//这一行注册了AOP注解处理的Bean
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
//这是获取EnableAspectJAutoProxy注解里面的值
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary:
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, (Object)null);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
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 {
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;
}
}
以上实际上就是注册了一个名字叫org.springframework.aop.config.internalAutoProxyCreator,类型是AnnotationAwareAspectJAutoProxyCreator的Bean。
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {}
public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {}
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator{}
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {}
AnnotationAwareAspectJAutoProxyCreator是一个BeanPostProcessor,里面就是具体的AOP的处理了,非常复杂!主要做的事情就是解析Advice,生成代理,下一篇我们通过一些具体的案例来看下AOP具体的应用场景,敬请关注。
源码下载:https://github.com/xjs1919/enumdemo 下面的 aop-demo
欢迎扫码加关注: