2016-12-04 63 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) 
} 

最後,一切工作正常:)