Spring Aop 失效的一种可能原因
一、问题描述
1.@Transactional(propagation = Propagation.REQUIRES_NEW)失效并没有开启新的事务
2.自定义注解 @DataSource(SLAVE1) 动态数据源切换失效
二、分析和定位原因
一、示例代码
@Service
public class TestAopInvalid {
@DataSource
public void a() {
b();
TestAopInvalid bean = SpringContextHolder.getBean(TestAopInvalid.class);
bean.c();
}
@DataSource
public void b() {
}
@DataSource
public void c() {
}
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataSource {
String value() default "";
}
@Component
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextHolder.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> requiredType) {
assertApplicationContext();
return applicationContext.getBean(requiredType);
}
}
@Aspect
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DataSourceAspect {
@Pointcut("@annotation(com.xxx.DataSource)")
public void dataSourcePointCut() {}
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
return point.proceed();
}
}
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
TestAopInvalid call = context.getBean(TestAopInvalid.class);
call.a();
System.exit(0);
}
二、在DataSourceAspect的around方法打断点debug结果如下
方法TestAopInvalid.a()经过了AOP增强,进入了AOP切面类的断点
方法TestAopInvalid.b()没有经过AOP增强
方法TestAopInvalid.c()经过了AOP增强,进入了AOP切面类的断点
三、总结和规避
通过注解@Autowired、@Resource、@Qualifier、@Import、@Bean和ApplicationContext.getBean()、xml
配置拿到的对象如果有被AOP增强,返回的一定是代理类的对象,方法会被增强。
另一种比如直接new的对象、或者用this关键字调用,比如同一类的a方法调用该类下的另一个方法b就是this关键字隐式调用,方法不会被增强。
重点看方法b和c被调用的方式的区别
public void a() {
b();
TestAopInvalid bean = SpringContextHolder.getBean(TestAopInvalid.class);
bean.c();
}
一句话想要被AOP增强就要拿到代理类的对象去调用。
你可以写一个这样的抽象类,然后继承他:
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public abstract class ProxyHolder<T extends ProxyHolder<T>>{
protected T proxy;
public ProxyHolder() {
this.proxy=proxy();
}
@SuppressWarnings({ "unchecked", "hiding" })
private <T> T proxy(){
Type[] types = this.getClass().getGenericInterfaces();
ParameterizedType type = (ParameterizedType)types[0];
Class<T> tClass = (Class<T>)type.getActualTypeArguments()[0];
return (T) SpringContextHolder.getBean(tClass);
}
}
@Service
@Lazy
public class TestAopInvalid extends ProxyHolder<TestAopInvalid>{
@DataSource
public void a() {
proxy.b();
TestAopInvalid bean = SpringContextHolder.getBean(TestAopInvalid.class);
bean.c();
}
@DataSource
public void b() {
}
@DataSource
public void c() {
}
}
本文探讨了Spring AOP在@Transactional和@DataSource注解失效的情况,详细分析了问题出现的原因,包括新事务未启动和动态数据源切换失败。通过示例代码和调试结果,指出只有通过代理类调用的方法才能被AOP增强,避免直接使用new或this关键字调用。建议使用注解或抽象类来确保获取到代理对象。
168万+

被折叠的 条评论
为什么被折叠?



