2016-12-04 222 views
3

我在Spring MVC中有经验,但第一次使用Cache。这些是我已经完成的步骤。Spring @CacheEvict不工作

步骤:1

//在弹簧配置

@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); 
    } 
} 

每当调用loadUserDetailsFromDbAuthenticationTokenFilter它(显然除了在第一次调用)返回缓存的对象。这意味着@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异常:空键返回缓存 操作(也许你正在使用的类名为PARAMS没有调试 信息?)

注:是不是驱逐的问题,因为我打电话来自不同类别的@Cacheable@CacheEvict方法。这是从AuthenticationTokenFilterAuthenticationController

+0

我觉得你的实现看起来正确。也许你忘记了你的配置类中的@EnableCaching注释? – pDer666

+0

'@ EnableCaching'在我的配置类中。 '@ Cacheable'工作正常。 –

+0

进一步的搜索为我带来了这个“** JDK ConcurrentMap,它对于简单的用例已经足够了,但不支持持久性或驱逐策略**”[link](http://websystique.com/spring/spring-4 -cache教程与 - ehcache的/)。这与我的问题有关吗? –

回答

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

其他变化

WebSecurityConfiguration删除@ComponentScan因为它已经在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) 
} 

最后,一切工作正常:)