I have a @Controller
with @Autowired
fields and handler methods that I want to annotate with custom annotations.
For example,
@Controller
public class MyController{
@Autowired
public MyDao myDao;
@RequestMapping("/home")
@OnlyIfXYZ
public String onlyForXYZ() {
// do something
return "xyz";
}
}
Where @OnlyIfXYZ
is an example of a custom annotation. I was thinking I would intercept the Controller bean creation, pass my own CGLIB proxy on which Spring can then set properties, like the autowired field.
I tried using a InstantiationAwareBeanPostProcessor
but that solution doesn't work great because postProcessBeforeInstantiation()
short-circuits the rest of the process. I tried with postProcessAfterInitialization()
, like below
public class MyProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// Here the bean autowired fields are already set
return bean;
}
@Override
public Object postProcessAfterInitialization(Object aBean, String aBeanName) throws BeansException {
Class<?> clazz = aBean.getClass();
// only for Controllers, possibly only those with my custom annotation on them
if (!clazz.isAnnotationPresent(Controller.class))
return aBean;
Object proxy = Enhancer.create(clazz, new MyMethodInterceptor());
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
try {
// get the field and copy it over to the proxy
Object objectToCopy = field.get(aBean);
field.set(proxy, objectToCopy);
} catch (IllegalArgumentException | IllegalAccessException e) {
return aBean;
}
}
return proxy;
}
}
This solution uses reflection to copy over all the fields of the target bean to the proxy bean (kind of hacky for my taste). But I don't have access to the HttpServletRequest
and HttpServletResponse
objects if those aren't arguments in the method I'm intercepting.
Is there another callback I can inject into Spring bean creation logic to inject my own Proxy Controller before Spring populates its properties? I need to be able to access the HttpServletRequest
and HttpServletResponse
objects regardless of if the Controller handler method has it in its definition, ie. as arguments.
N.B The @Autowired
field is also a proxy, it is annotated with @Transactional
so Spring proxies it up.
EDIT: The AOP solution works nicely for intercepting the method invocation, but I can't find a way to access the HttpServletRequest
and HttpServletResponse
objects, if they aren't already method arguments.
I'm probably going to end up using HandlerInterceptorAdapter, but I was hoping I can do it with OOP so as to not add the overhead to methods that don't need it.