遇到的问题 what
新公司的项目使用Kotlin+SpringBoot作为后台架构,开发中出现了AOP日志切面不生效的问题
为什么会这样 why
- @Aspect注解的切面类没有初始化到IOC容器中,即没有声明为组件
- SpringBoot2.0的AOP代理有三种策略,启动时的AutoConfig配置类是使用CGLIB进行代理,即matchIfMissing=true,spring.aop.proxy-target-class配置项缺失时
- Kotlin生成的类和方法如果前缀没有open关键字,编译成字节码文件时会带上final关键字即类不可继承、方法不可重写
- CGLIB使用ASM字节码技术进行字节码植入,运行时生成目标类的子类来实现代理,所有如果目标类不可继承、方法不可重写、就无法被cglib代理
有3种,前提均开启spring.aop.auto=true;
1. jdk动态代理:当spring.aop.proxy-target-class=false, 引入了aspectjweaver依赖时生效
2. cglib代理:当spring.aop.proxy-target-class=true, 引入了aspectjweaver依赖时生效
3. 基础代理:当spring.aop.proxy-target-class=true, 若没有aspectjweaver依赖时生效,只作用于框架内部的advisors
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
static class JdkDynamicAutoProxyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class CglibAutoProxyConfiguration {
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class ClassProxyingConfiguration {
ClassProxyingConfiguration(BeanFactory beanFactory) {
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
}
}
}
解决办法 how
- 切面类声明为组件,启动时被扫描进IOC容器。或者在Configuration配置类中使用@Bean生成切面类实例
- 在默认使用cglib代理的情况下,被AOP横切的类及方法需要加上open关键字
来源:oschina
链接:https://my.oschina.net/u/3744350/blog/4794813