原因
这是因为在@Component、@Configuration等类中注入实例会导致实例被过早实例化,没有被AOP增强,导致事务失效。
解决
package com.qiwen.base.util;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public final class SpringHelper {
private static ApplicationContext applicationContext;
public static void setApplicationContext(ApplicationContext context) {
if (applicationContext == null) {
applicationContext = context;
}
}
public static ApplicationContext getApplicationContext() {
if(applicationContext == null) {
throw new UnsupportedOperationException("ApplicationContext 未初始化");
}
return applicationContext;
}
public static ApplicationContext getApplicationContext(ApplicationContext applicationContext) {
if(getApplicationContext() == null) {
setApplicationContext(applicationContext);
}
return getApplicationContext();
}
private static class LazyLoadProxyBean<T> implements MethodInterceptor {
// 禁止 JVM 重排
private volatile T targetObject;
private final Class<T> clazz;
private final String beanName;
public LazyLoadProxyBean(Class<T> clazz, String beanName) {
this.clazz = clazz;
this.beanName = beanName;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 第一次初始化使用的时候初始化
if (Objects.isNull(targetObject)) {
// 代理对象懒加载部分一次只允许一个线程访问
synchronized(this) {
if(Objects.isNull(targetObject)) {
// 首先尝试使用 name, name 没有则使用 class
if(StringUtils.isEmpty(beanName)) {
targetObject = (T) SpringHelper.getRealBean(clazz);
} else {
targetObject = (T) SpringHelper.getRealBean(beanName);
}
}
}
}
Object result = method.invoke(targetObject, args);
return result;
}
}
private SpringHelper() { }
public static <T> T getLazyBean(final Class<T> clazz) {
return getLazyBean(clazz, null);
}
// 创建代理传入类型的代理类
public static <T> T getLazyBean(final Class<T> clazz, final String beanName) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(new LazyLoadProxyBean<T>(clazz, beanName));
T proxy = (T) enhancer.create();
return proxy;
}
public static <T> T getRealBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
public static <T> T getRealBean(String name) {
return (T) getApplicationContext().getBean(name);
}
public static <T> List<T> getRealBeansByType(Class<T> clazz) {
String[] beanNames = getApplicationContext().getBeanNamesForType(clazz);
List<T> beans = Arrays.stream(beanNames)
.map(name -> (T)getRealBean(name))
.collect(Collectors.toList());
return beans;
}
}
@Configuration
// 启动优先级配置到最高
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ApplicationContextHolderConfig implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringHelper.setApplicationContext(applicationContext);
}
}
@Component
public class AuthInterceptor extends HandlerInterceptorAdapter {
private final IRoleService roleService;
public AuthInterceptor () {
// 创建 LazyBean, 既创建一个 IRoleService 的代理对象,实际 IRoleService Bean
// 会在第一次被使用的使用初始化。
this.roleService = SpringHelper.getLazyBean(IRoleService.class);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
// ...
}
}
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.9</version>
</dependency>
版权声明:本文为Dreamcatcher_yxc原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接