SpringBoot中在使用了@Component、@Configuration等类中注入Service对象导致Service对象无法正常使用事务功能

SpringBoot中在使用了@Component、@Configuration等类中注入Service对象导致Service对象无法正常使用事务功能

原因

这是因为在@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 版权协议,转载请附上原文出处链接和本声明。
原文链接

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值