这个问题困扰了我好多天
问题
- ServiceImpl类里的方法上有缓存注解,用于将返回的实体类存入redis,下次调用时就不需要通过数据库获取实体类信息。
- Shiro框架内由于自定义了Ream,需要注入Service来获取用户实体类信息。
- 而后运行时,发现缓存注解并没有起作用,两次调用Service方法,都进入了方法,而不是读取缓存。
- 自定义Ream
/**
* 用来给shiro注入认证信息和授权信息
*/
@Component("userRealm")
public class UserRealm extends AuthorizingRealm{
/**
* shiro内注入bean时,需要加入lazy注解,否则bean可能不能正常运行(比如缓存注解)
* 参考:https://blog.csdn.net/elonpage/article/details/78965176
*/
@Autowired
@Lazy
private UserService userService;
/**
* 授权处理
* 登录时不检查用户权限
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
/**
* 身份认证
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 获取用户 - 这里调用了Service方法
String account = (String) authenticationToken.getPrincipal();
User user = userService.getUserByAccount(account,
DatabaseConst.STATUS_ENABLE,
DatabaseConst.IS_DETETED_NO);
if (user == null) {
return null;
}
return new SimpleAuthenticationInfo(
user,
user.getPassword().toCharArray(),
ByteSource.Util.bytes("salt-sdwbhx23i"),//盐,可自定义
getName()
);
}
}
- Service方法
@Service
public class UserServiceImpl implements UserService{
// 使用了缓存注解的方法,第二次执行时,应该直接从缓存中读取User实体信息
@Cacheable(value = RedisConst.USER_INFO ,key = "#account")
public User getUserByAccount(String account,int isEnable,int isDeleted) {
//这里模拟从数据库中读取数据
User user = new User();
user.setAccount(account);
user.setIsDeleted(isDeleted);
user.setStatus(isEnable);
return userMapper.selectOne(user);
}
}
解决办法
在Shiro框架内注入bean时,除了 @Autowired 注解外,再加入 @Lazy 注解。
这样会使得注入到Shiro框架的Bean延时加载(即在第一次使用的时候加载)
原因
spring boot整合shiro后,部分注解(Cache缓存、Transaction事务等)失效的问题
简单来说,就是Shiro框架初始化比Spring框架的某些部件早,导致使用@Autowire注入Shiro框架的某些类不能被Spring正确初始化。