2016-12-04 4 views
3

Ich habe Erfahrung in Spring MVC, aber das erste Mal mit Cache. Das sind Schritte, die ich bisher gemacht habe.Spring @CacheEvict funktioniert nicht

Schritt: 1

// In Feder Konfig

@Bean 
public CacheManager cacheManager() { 
    return new ConcurrentMapCacheManager("user"); 
} 

// zwischengespeicherte Objekt

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 
    } 
} 

// My Filter

public class AuthenticationTokenFilter extends UsernamePasswordAuthenticationFilter { 
    AuthService authService = WebApplicationContextUtils 
      .getRequiredWebApplicationContext(this.getServletContext()) 
      .getBean(AuthService.class); 
    CachedUser user = this.authService.loadUserDetailsFromDb(username, authToken); 
} 

// Controller-

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

Wenn loadUserDetailsFromDb von AuthenticationTokenFilter nannte es im Cache gespeicherte Objekt zurückgibt (außer im ersten Aufruf offensichtlich). Das bedeutet @Cacheable(value="user", key="#token") funktioniert gut.

Aber selbst nachdem ich mich abgemeldet und authService.removeUser() aufgerufen habe, ruft Aufruf loadUserDetailsFromDb() das zwischengespeicherte Objekt ab. Das bedeutet @CacheEvict(value="user", key="#token") funktioniert nicht.

Schritt: 2

this Geworben und bewegt removeUser() an einen anderen Dienst (sagen wir CacheServiceImp implements CacheService), noch gleiche Problem.

Schritt: 3

reffered this und durch mein Verständnis, bewegt @Cache* Anmerkung AuthService, bekam folgende Fehler zu verbinden.

java.lang.IllegalArgumentException: Null Schlüssel zurückgegeben für Cache Operation (vielleicht Sie verwenden Namen params auf Klassen ohne info zu debuggen?)

Hinweis: Ist das Problem der nicht evicting , weil ich @Cacheable und @CacheEvict Methoden aus verschiedenen Klassen aufrufen. Das ist von AuthenticationTokenFilter und AuthenticationController

+0

Ich denke, Ihre Implementierung korrekt aussieht. Vielleicht haben Sie @EnableCaching Annotation in Ihrer Konfigurationsklasse vergessen? – pDer666

+0

'@ EnableCaching' ist dort in meiner Konfigurationsklasse. Und '@ Cacheable' funktioniert gut. –

+0

Weitere Suche brachte mir diese "** JDK ConcurrentMap, die für einfache Anwendungsfälle ausreicht, aber nicht die Persistenz oder Räumungsrichtlinie **" von diesem Beitrag [link] (http://websystique.com/spring/spring-4 -cache-tutorial-mit-ehcache /). Hat das etwas mit meinem Problem zu tun? –

Antwort

1

Nach dem Spielen mit meinem Code, Kopf und Internet, endlich, habe ich das gelöst. Es ist ein Fehler in meiner Spring (Security) -Konfiguration, die ich nicht mit der Frage gepostet habe.

Fehler 1:

In SecurityInitializer Klasse

public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {  
    public SecurityInitializer() { 
     super(WebSecurityConfiguration.class); 
    } 

} 

Als Projekt umfasst Spring MVC-Konfiguration, der Konstruktor nicht umgesetzt werden müssen.Also den Konstruktor entfernt. Diese Klasse registriert dann einfach den springSecurityFilterChain-Filter für jede URL.

Fehler 2: (die eigentliche Ursache der oben beschriebene Problem)

Ich habe meine AuthenticationTokenFilter auf zwei Arten hinzugefügt:

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { 
    // other overrides 
    @Override 
    protected Filter[] getServletFilters() { 
     return new Filter[]{ new AuthenticationTokenFilter() }; 
    } 
} 

und

@Configuration 
@EnableWebSecurity 
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 
    // Other config 
    @Override 
    protected void configure(HttpSecurity httpSecurity) throws Exception { 
     //Other config 
     httpSecurity.addFilterBefore(authTokenFilter, 
        UsernamePasswordAuthenticationFilter.class); 
    } 
} 

Dies machte den Filter angerufen zu werden zweimal, ein innerhalb des Frühlingskontextes und die andere als üblichen Servlets Filter

So entfernte Konfiguration innerhalb WebAppInitializer

Weiterer Wechsel

@ComponentScan aus WebSecurityConfiguration entfernt, da es bereits in SpringMvcConfig ist. Dazu müssen beide Konfigurationen im selben Kontext geladen werden. Fertig mit folgendem Code.

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

Endlich funktioniert alles gut :)