Spring MVC - Interceptor never called - java

I am trying to configure an interceptor in my application and I am not being able to make it work.
In my application configuration class, I have configured in the following way:
#Configuration
#EnableWebMvc
public class AppContextConfiguration extends WebMvcConfigurerAdapter {
...
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
...
}
And the interceptor:
public class MyInterceptor extends HandlerInterceptorAdapter{
private static final Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
logger.debug("MyInterceptor - PREHANDLE");
}
}
Does anybody know why is not being invoked?

I'm using Spring Boot and was having the same problem where addInterceptors() was being called to register the interceptor, but the interceptor never fired during a request. Yet XML configuration worked no problem.
Basically, you don't need the WebMvcConfigurerAdapter class. You just need to declare an #Bean of type MappedInterceptor:
#Bean
public MappedInterceptor myInterceptor()
{
return new MappedInterceptor(null, new MyInterceptor());
}

Interceptor classes must be declared in spring context xml configuration file within the tag <mvc:interceptors>. Did you do that?
From the Documentation
An example of registering an interceptor applied to all URL paths:
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
</mvc:interceptors>
An example of registering an interceptor limited to a specific URL path:
<mvc:interceptors>
<mvc:interceptor>
<mapping path="/secure/*"/>
<bean class="org.example.SecurityInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
So, you would need to configure MyInterceptor class in the spring context xml file

Can someone please mark Theos answer as the correct one? I had the situation of a perfectly working Spring Boot app using i18n and Thymeleaf (with a layout interceptor) as long as the app was running localhost with the following config:
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
registry.addInterceptor(thymeleafLayoutInterceptor());
}
As soon as I deployed the app to an Elasticbeanstalk instance, both interceptors were not fired anymore. Although added once. When I changed the setting to
#Bean
public MappedInterceptor localeInterceptor() {
return new MappedInterceptor(null, localeChangeInterceptor());
}
#Bean
public MappedInterceptor thymeleafInterceptor() {
return new MappedInterceptor(null, thymeleafLayoutInterceptor());
}
everything was working fine on all environments. There must be an issue with firing interceptors added with addInterceptor, it might depend on the URL that is used to invoke the request - I don't know.
Thanks for your answer, Theo, I just wanted to add this here if some else stumbles upon this nice feature.

If it´s possible. Use this approach:
public class Application extends WebMvcConfigurerAdapter{
...
#Bean
public MyInterceptor myInterceptor() {
return new MyInterceptor();
}
public #Override void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor());
}
}
instead of:
#Bean
public MappedInterceptor myInterceptor()
{
return new MappedInterceptor(null, new MyInterceptor());
}
because with the first you can use injection features (like #Autowired, etc...)

Maybe you should add componentscan annotation in the file where the main class is present.
#ComponentScan("package where the interceptor is placed.")
Worked for me.

This approach worked with me
#Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
}

Using XML configuration, ensure you defined the interceptors in the correct context.
Moving config from servlet context(*-servlet) to main context (web.xml) made it work.
Even if the URL was a call to the servlet.

Related

How to let Interceptor work in springboot

I migrate the code to springboot and our API works well. Only interceptor can't be triggerred.
I googled related solutions and modify the code to right format which still failed to trigger the interceptor.
In our project, we also have the filter which extends OncePerRequestFilter and works.
It makes me confused.
They should be no big difference.
Btw, AOP is used in the project.
It's my code.
JerseyConfig.class
#Configuration
public class JerseyConfig extends ResourceConfig {
public JerseyConfig(){
packages("com.xxx");
}
}
VaultAuthorizationInterceptor.class
#Component
public class VaultAuthorizationInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(VaultAuthorizationInterceptor.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.info("test");
return true;
}
}
VaultAuthConfig.class
#Configuration
public class VaultAuthConfig implements WebMvcConfigurer {
#Bean
public VaultAuthorizationInterceptor getVaultInterceptor() {
return new VaultAuthorizationInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getVaultInterceptor()).addPathPatterns("/**");
}
}
When you are using the spring-boot-starter-jersey, you use jersey as your web stack. That means any requests will processed by jersey. So you have to register a jersey filter or interceptor. Take a look at the jersey documantation. There is described how to use filters and interceptors. I think you want to use a filter because interceptors in the jersey stack used to manipulate the input or output stream.

Spring-MVC + Spring-websocket + #Cacheable don't work

I have got a project on Spring-MVC and Spring-websockets and I try to plug cache on my service layer. These are my configuration:
#Configuration
#ComponentScan(basePackages = {
"com.example"
})
#PropertySource("classpath:/configuration.properties")
#EnableWebMvc
#EnableAspectJAutoProxy(proxyTargetClass = true)
#EnableCaching
public class WebAppConfig extends WebMvcConfigurerAdapter {
#Bean
public EhCacheManagerFactoryBean ehcache() {
EhCacheManagerFactoryBean ehCache = new EhCacheManagerFactoryBean();
ehCache.setConfigLocation(new ClassPathResource("ehcache.xml"));
ehCache.setShared(true);
return ehCache;
}
#Bean
public CacheManager cacheManager() {
return new EhCacheCacheManager(ehcache().getObject());
}
//...different settings by mvc
}
and my websocket configuration:
#Configuration
#EnableAsync
#EnableWebSocket
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue/", "/topic/");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/locations").withSockJS();
}
#Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.taskExecutor().corePoolSize(4).maxPoolSize(10);
}
}
I want to use #Cacheable annotation on my service layer:
#Service
public class StoreServiceImpl implements StoreService {
private static final Log logger = LogFactory.getLog(StoreServiceImpl.class);
#Autowired
private StoreRepository storeRepository;
#Override
#Cacheable("stores")
public Store findById(String storeId) {
return storeRepository.findById(storeId);
}
//... others methods
}
but if I have included annotation #EnableWebSocketMessageBroker then the cache doesn't work, because aop interceptors do not use it, so
if I haven't included #EnableWebSocketMessageBroker then cache and AOP interceptors work well.
The documentation on the websocket I found this information:
In some cases a controller may need to be decorated with an AOP proxy
at runtime. One example is if you choose to have #Transactional
annotations directly on the controller. When this is the case, for
controllers specifically, we recommend using class-based proxying.
This is typically the default choice with controllers. However if a
controller must implement an interface that is not a Spring Context
callback (e.g. InitializingBean, *Aware, etc), you may need to
explicitly configure class-based proxying. For example with
<tx:annotation-driven />, change to <tx:annotation-driven proxy-target-class="true" />
I tried use #EnableCaching(proxyTargetClass = true), but it didn't help.
Has anyone encountered this problem?
I decided this problem:
I changed mode in #EnableAsync(mode = AdviceMode.ASPECTJ) and it works.
I think it depends of the order initialization BeanPostProcessors

Unable to add an instance of HandleInterceptorAdapter

I am trying to intercept every HTTP request that comes into my Spring Boot application.
For this I have a LoggingInterceptor as follows:
#Component
public class LoggingInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);
public LoggingInterceptor() {
super();
logger.debug("LoggingInteceptor constructor");
}
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
logger.debug("LoggingInteceptor: Intercepted " + request.getRequestURI());
return true;
}
}
Then, I have an #Configuration class for adding the interceptor to the registry as follows:
#EnableWebMvc
#Configuration
public class LoggingConfig extends WebMvcConfigurerAdapter {
#Autowired
LoggingInterceptor loggingInterceptor;
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(loggingInterceptor);
}
}
However, I just cannot see any of the logger statements. Is there something more I need to do to get this going?
Your configuration looks fine. Also registry.addInterceptor(loggingInterceptor); call would fail if interceptor would be null, therefore it seems to be correctly wired.
Therefore I would verify:
if DEBUG level us enabled in logging framework
If both classes are included into your Spring context at all (put breakpoint addInterceptors method and start app)
EDIT:
OK, so comment confirmed that you your problem is my first point.
You need to find out logging configuration file (e.g. log4j.properties, log4j,xml or logback.xml) and change log level from INFO to DEBUG there.

Java config for spring interceptor where interceptor is using autowired spring beans

I want to add spring mvc interceptor as part of Java config. I already have a xml based config for this but I am trying to move to a Java config. For interceptors, I know that it can be done like this from the spring documentation-
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor());
}
}
But my interceptor is using a spring bean autowired into it like follows-
public class LocaleInterceptor extends HandlerInterceptorAdaptor {
#Autowired
ISomeService someService;
...
}
The SomeService class looks like follows-
#Service
public class SomeService implements ISomeService {
...
}
I am using annotations like #Service for scanning the beans and have not specified them in the configuration class as #Bean
As my understanding, since java config uses new for creating the object, spring will not automatically inject the dependencies into it.
How can I add the interceptors like this as part of the java config?
Just do the following:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
LocaleInterceptor localInterceptor() {
return new LocalInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeInterceptor());
}
}
Of course LocaleInterceptor needs to be configured as a Spring bean somewhere (XML, Java Config or using annotations) in order for the relevant field of WebConfig to get injected.
The documentation for general customization of Spring's MVC configuration can be found here, and specifically for Interceptors see this section
When you handle the object creation for yourself like in:
registry.addInterceptor(new LocaleInterceptor());
there is no way the Spring container can manage that object for you and therefore make the necessary injection into your LocaleInterceptor.
Another way that could be more convenient for your situation, is to declare the managed #Bean in the #Configuration and use the method directly, like so:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public LocaleInterceptor localeInterceptor() {
return new LocaleInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor( localeInterceptor() );
}
}
Try to inject your service as a constructor parameter. It is simple.
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
ISomeService someService;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor(someService));
}
}
Then reconfigure your interceptor,
public class LocaleInterceptor extends HandlerInterceptorAdaptor {
private final ISomeService someService;
public LocaleInterceptor(ISomeService someService) {
this.someService = someService;
}
}
Cheers !

How can I customize the AuditingHandler injected by Spring-Data when using Auditing?

I'm using Spring Data 1.5 and Auditing. Part of the AuditingEntityListener has a setAuditingHandler method.
How can I customize the AuditingHandler and instruct Spring-Data to inject my custom handler instead of the default org.springframework.data.auditing.AuditingHandler?
I've tried instantiating my own AuditingEntityListener in which I inject my own Handler, but that is not doing the job. The default handler is still being injected. I've tried both via XML configuration and JavaConfig to see if one worked better than the other, but neither way works.
JavaConfig:
#Configuration
#EnableJpaAuditing(auditorAwareRef="auditorProvider")
public class AppConfig {
#Bean
public AuditorAware<User> auditorProvider(){
return new SpringSecurityAuditorAware();
}
#Bean
public AuditingEntityListener auditingEntityListener(){
AuditingEntityListener listener = new AuditingEntityListener();
listener.setAuditingHandler(new com.ia.persistence.AuditingHandler());
return listener;
}
}
My custom handler:
#Component
public class AuditingHandler extends org.springframework.data.auditing.AuditingHandler {
// SLF4J logger
private static final Logger logger = LoggerFactory.getLogger(AuditingHandler.class);
/* (non-Javadoc)
* #see org.springframework.data.auditing.AuditingHandler#markCreated(java.lang.Object)
*/
#Override
public void markCreated(Object source) {
logger.info("Custom handler");
super.markCreated(source);
}
/* (non-Javadoc)
* #see org.springframework.data.auditing.AuditingHandler#markModified(java.lang.Object)
*/
#Override
public void markModified(Object source) {
logger.info("Custom handler");
super.markModified(source);
}
}
What am I doing wrong? With my JavaConfig, I do not even see Spring instantiating the listener using my configuration. Alternatively, I've tried using XML configuration to configure the listener, but the default listener is still the one that is used.
<!-- enable Spring data-JPA repositories -->
<jpa:repositories base-package="com.ia" />
<bean id="auditingEntityListener" class="org.springframework.data.jpa.domain.support.AuditingEntityListener">
<property name="auditingHandler" ref="auditingHandler"/>
</bean>
Any suggestions would be helpful.
I met the same question.
The short version
You have to register jpaAuditingHandler bean definition using BeanDefinitionRegistry.
The long version
the org.springframework.data.jpa.domain.support.AuditingEntityListener is a special class which mixed in with aspectj when compiling. see here
It need a bean definition to work. see the spring framework document.
the org.springframework.data.jpa.repository.config.EnableJpaAuditing you are using will register the bean definition with auditingHandler bind to a jpaAuditingHandler bean. It also will register the jpaAuditingHandler bean definition.
If you add a jpaAuditingHandler using #Component, it won't work because Spring prefer another one. see org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass
So you have to register your bean definition using BeanDefinitionRegistry.
public class jpaAuditingHandlerRegistrar implements ImportBeanDefinitionRegistrar {
#Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("jpaAuditingHandler", BeanDefinitionBuilder
.rootBeanDefinition(JpaAuditingHandler.class)
.addConstructorArgReference("jpaMappingContext")
.getBeanDefinition());
}
}
and add #Import(JpaAuditingHandlerRegistrar.class) to your Configuration class
#SpringBootApplication
#EnableJpaAuditing
#Import(JpaAuditingHandlerRegistrar.class)
public class Application {
I put sample code https://github.com/macdao/customize-auditing-handler

Categories