Spring @CacheEvict不工作

时间:2016-12-04 06:26:06

标签: java spring spring-mvc caching

我在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方法。这是AuthenticationTokenFilterAuthenticationController

1 个答案:

答案 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)
}

最后,所有工作都很精细:)