我在Spring MVC中有过经验,但是第一次使用Cache。这些是我已经完成的步骤。
步骤:1
//在spring config中
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("user");
}
//缓存对象
public class CachedUser {
private String username;
private String token;
// Public getter-setter
}
// AuthServiceImp
@Service
public class AuthServiceImp implements AuthService {
@Override
@Cacheable(value="user", key="#token")
@Transactional
public CachedUser loadUserDetailsFromDb(String username, String token) {
// codes here
}
@Override
@CacheEvict(value="user", key="#token")
@Transactional
public void removeUser(String username, String token) {
// codes here
}
}
//我的过滤器
public class AuthenticationTokenFilter extends UsernamePasswordAuthenticationFilter {
AuthService authService = WebApplicationContextUtils
.getRequiredWebApplicationContext(this.getServletContext())
.getBean(AuthService.class);
CachedUser user = this.authService.loadUserDetailsFromDb(username, authToken);
}
//控制器
@RestController
public class AuthenticationController {
@Autowired
private AuthService authService;
@GetMapping("logout2")
public ResponseModel logout(@RequestAttribute("username") String username,
HttpServletRequest request) {
String token = request.getHeader(tokenHeader);
authService.removeUser(username, token);
return new ResponseModel(200,"Success",null);
}
}
每当从loadUserDetailsFromDb
调用AuthenticationTokenFilter
时,它都会返回缓存对象(显然除了第一次调用外)。这意味着@Cacheable(value="user", key="#token")
工作正常。
但即使我退出并调用authService.removeUser()
,调用loadUserDetailsFromDb()
也会获取缓存的对象。这意味着@CacheEvict(value="user", key="#token")
无效。
步骤:2
推荐this并将removeUser()
移至其他服务(例如CacheServiceImp implements CacheService
),但同样的问题。
步骤:3
已暂停this,据我了解,已将@Cache*
注释移至界面AuthService
,出现以下错误。
java.lang.IllegalArgumentException:为缓存返回Null键 操作(也许你在没有调试的情况下在类上使用命名参数 信息?)
注意:是不是要驱逐的问题,因为我正在调用来自不同类的@Cacheable
和@CacheEvict
方法。这是AuthenticationTokenFilter
和AuthenticationController
答案 0 :(得分:1)
在玩了我的代码,头和互联网之后,我终于解决了这个问题。这是我的Spring(安全)配置中的一个错误,我没有发布这个问题。
错误1 :
在SecurityInitializer
班级
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
public SecurityInitializer() {
super(WebSecurityConfiguration.class);
}
}
由于项目包含Spring MVC配置,不得实现构造函数。所以删除了构造函数。然后,该类只为每个URL注册springSecurityFilterChain过滤器。
错误2:(上述问题的真正原因)
我已经通过两种方式添加了AuthenticationTokenFilter
:
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
// other overrides
@Override
protected Filter[] getServletFilters() {
return new Filter[]{ new AuthenticationTokenFilter() };
}
}
和
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
// Other config
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
//Other config
httpSecurity.addFilterBefore(authTokenFilter,
UsernamePasswordAuthenticationFilter.class);
}
}
这使得过滤器被称为两次,一个称为Spring上下文,另一个称为通常的Servlet过滤器
删除了WebAppInitializer
其他更改
已从@ComponentScan
移除WebSecurityConfiguration
,因为它已在SpringMvcConfig
中。 这需要在相同的上下文中加载两个配置。通过以下代码完成。
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { SpringMvcConfig.class, WebSecurityConfiguration.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
// Removed filter registering from here (Mistake 2)
}
最后,所有工作都很精细:)