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全部懒加载。
本文来自博客园,作者:imissinstagram,转载请注明原文链接:https://www.cnblogs.com/LostSecretGarden/p/16361708.html