這個問題困擾了我好多天
問題
- 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正确初始化。