not eligible for getting processed by all BeanPostProcessors

描述

这个BUG大的起源是我上线以后,在后台看日志的时候发现一行奇怪的INFO日志:

2022-06-09 23:34:24 [restartedMain] [org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker:376] INFO  - Bean 'userServiceImpl' of type [com.markerhub.service.impl.UserServiceImpl] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

什么?userServiceImpl代理失效了?我于是尝试了一下,果然,这个方法直接不回滚了:

@Override
    @Transactional
    public void addUser(UserVo user) {
        User userExist = getBaseMapper().selectOne(new QueryWrapper<User>().eq("id", user.getId()));

        if (userExist == null) {//添加
            user.setPassword(SecureUtil.md5(user.getPassword()));
            user.setCreated(LocalDateTime.now());
            user.setLastLogin(LocalDateTime.now());
            boolean update = saveOrUpdate(user);
            log.info("添加{}号账号结果:{}", user.getId(), update);
            int i = 1 / 0;
            Assert.isTrue(update, "添加失败");
        } else {//修改

            BeanUtil.copyProperties(user, userExist, "created", "password", "lastLogin", "username", "id");

            boolean update = saveOrUpdate(userExist);

            log.info("修改{}号账号结果:{}", userExist.getId(), update);

            Assert.isTrue(update, "修改失败");
        }

    }

第12行我强行模拟了故障,但是数据库里还是保存成功了。这个是生产上的严重事故。Spring事务默认的传播级别,是当前若存在事务,就加入这个事务。saveOrUpdate是mybatis-plus的方法,已经加上了事务注解,也就是说这里事务本来必须是其作用的。

原理探究

我从网上的一篇文章发现了答案https://blog.csdn.net/feiying0canglang/article/details/119704109,问题的罪魁祸首是Shiro框架。

在使用shiro框架的时候,一般都要新建一个ShiroFilterFactoryBean配置一些配置,例如:

@Bean("shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager,
                                                         ShiroFilterChainDefinition shiroFilterChainDefinition) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        Map<String, Filter> filters = new HashMap<>();
        filters.put("jwt", jwtFilter);
        shiroFilter.setFilters(filters);
        Map<String, String> filterMap = shiroFilterChainDefinition.getFilterChainMap();
        shiroFilter.setFilterChainDefinitionMap(filterMap);
        return shiroFilter;
    }

这些本身是一些固定的写法,没有太多可以改的,抄过来就行了。但是问题在于ShiroFilterFactoryBean实现了BeanPostProcessor这个接口:

public class ShiroFilterFactoryBean implements FactoryBean<AbstractShiroFilter>, BeanPostProcessor;

这个接口的实现类会在某种情况下被提前初始化,导致他不会被Sping AOP的动态代理所处理,最后的结果就是事务失效。

从打印日志看到,Realm是没有被代理的,因为Realm依赖了UserService,最后UserService页没有被代理。UserService也可能依赖了其他Service,最后就全都事务失效了。

解决

在UserService上加入@Lazy懒加载模式:

UserService userService;

    @Autowired
    @Lazy
    private void setUserServiceImpl(UserService userService) {
        this.userService = userService;
    }

分析依赖,将提前加载的Service全部懒加载。

posted @ 2022-06-10 00:18  imissinstagram  Views(1837)  Comments(0Edit  收藏  举报