Reputation: 49639
Is it possible to wire a Spring MVC Interceptor using annotations and if so could someone provide me with an example of how to do so?
By wire via annotation I am referring to doing as little in the XML configuration as possible. For example in this configuration file I found at http://www.vaannila.com/spring/spring-interceptors.html;
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" p:interceptors-ref="loggerInterceptor" />
<bean id="loggerInterceptor" class="com.vaannila.interceptor.LoggerInterceptor" />
How little configuration could you get away with there? I imagine an @Autowired
would remove the need to explicitly declare the bean in line 2, but would it be possible to get rid of line 1 with an annotation as well?
Upvotes: 31
Views: 40345
Reputation: 10650
I implemented a working solution using a custom @Interceptor
annotation in the spirit of Spring's @Controller
annotation:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Component
public @interface Interceptor {
String[] pathPatterns() default {};
String[] excludePathPatterns() default {};
}
This annotation should be applied to HandlerInterceptor
types like so:
@Interceptor
public class BuildTimestampInterceptor extends HandlerInterceptorAdapter {
private final String buildTimestamp;
public BuildTimestampInterceptor(@Value("${build.timestamp}") String buildTimestamp) {
this.buildTimestamp = buildTimestamp;
}
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
req.setAttribute("buildTimestamp", buildTimestamp);
return true;
}
}
Finally, the processor class, InterceptorProcessor
, is a Spring bean that extends WebMvcConfigurerAdapter
and implements BeanPostProcessor
in order to scan for the custom @Interceptor
annotations and register beans having that anntation as HandlerInterceptor
s inside the overridden addInterceptors
method:
@Component
public class InterceptorProcessor extends WebMvcConfigurerAdapter implements BeanPostProcessor {
private final Map<HandlerInterceptor,Interceptor> interceptors = new HashMap<>();
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
scanForInterceptorAnnotation(bean, beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String string) throws BeansException {
return bean;
}
protected void scanForInterceptorAnnotation(Object bean, String beanName) {
Optional<Interceptor> optionalInterceptor = getInterceptorAnnotation(bean.getClass());
if (optionalInterceptor.isPresent() && bean instanceof HandlerInterceptor) {
interceptors.put((HandlerInterceptor) bean, optionalInterceptor.get());
}
}
private Optional<Interceptor> getInterceptorAnnotation(Class cls) {
Annotation[] annotations = cls.getAnnotationsByType(Interceptor.class);
if (hasValue(annotations)) {
return Optional.of((Interceptor) annotations[0]);
}
return Optional.empty();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
interceptors.forEach((HandlerInterceptor key, Interceptor val) -> {
InterceptorRegistration registration = registry.addInterceptor(key);
if (hasValue(val.pathPatterns())) {
registration.addPathPatterns(val.pathPatterns());
}
if (hasValue(val.excludePathPatterns())) {
registration.excludePathPatterns(val.excludePathPatterns());
}
});
}
private static <T> boolean hasValue(T[] array) {
return array != null && array.length > 0;
}
}
Just remember to have your spring application scan for this processor bean in order to have it actually register your @Interceptor
s. Something like:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"org.my.controller", "org.my.utils.processor"})
public class WebConfig extends WebMvcConfigurerAdapter {...
Upvotes: 8
Reputation: 29
like Markus Kreusch'answers,It also could work like this
@Configuration
@EnableWebMvc
@ComponentScan(basePackages="webapp.base.package")
public class WebApplicationConfig extends WebMvcConfigurerAdapter {
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping RequestMappingHandlerMapping= super.requestMappingHandlerMapping();
Object[] interceptors = new Object[1];
interceptors[0] = new RoleInterceptor();
RequestMappingHandlerMapping.setInterceptors(interceptors);
return RequestMappingHandlerMapping;
}
}
Upvotes: -2
Reputation: 2121
Stumbled upon this question while searching exactly this. Finally I found out that it works in Spring 3.1 using @EnableWebMVC in conjunction with WebMvcConfigurerAdapter.
Simple Example:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages="webapp.base.package")
public class WebApplicationConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoggerInterceptor());
}
}
Upvotes: 80
Reputation: 242696
As far as I know, there are no ways to configure Spring MVC interceptors without XML at all.
However, there are some simplifications with mvc
namespace in the latest versions of Spring 3.0.x (not Spring 3.0.0!):
<mvc:interceptors>
<bean class="com.vaannila.interceptor.LoggerInterceptor" />
</mvc:interceptors>
See also:
Upvotes: 20
Reputation: 17761
I dont know about spring-AOP but if you're using AspectJ via Spring you can use @Aspect, @Pointcut, @Advise and more...
there's also a nice article on howto use these annotation with Spring AOP here: http://java-x.blogspot.com/2009/07/spring-aop-with-aspecj-annotations.html
Upvotes: 0