0
votes

In my spring controllers, annotated with aspects, I am attempting to remove CGLib proxies and replace them with JDK dynamic proxies. I know that Spring AOP uses CGLib when the class does not implement an interface, since JDK dynamic proxies work only on interfaces. I also realize that annotations need to be present on both the interface and the implementing class. However, the problem I am running into is that the controller no longer shows up as a bean with a JDK proxy.

My controller bean is scanned for like such:

<context:annotation-config/>
<context:component-scan base-package="com.package.name"/>

This works, but controller shows up as CGLibController$$EnhancerByCGLIB$$5f0b2287:

package com.package.name;
@Controller
public class CGLibController {
  @AOP_Aspect
  @RequestMapping("some_url")
  public void foo();
}

//in a bean post processor
//in postProcessAfterInitialization(Object bean, String beanName)
  Controller controller = AnnotationUtils
      .findAnnotation(bean.getClass(), Controller.class);
//controller will exist
//bean name is CGLibController$$EnhancerByCGLIB$$5f0b2287

This doesn't work, it never gets to the bean post processor:

package com.package.name;
@Controller
public interface ITest{
  @AOP_Aspect
  @RequestMapping("some_url")
  public void foo();
}

package com.package.name;
@Controller
public class DynamicController implements ITest{
  @AOP_Aspect
  @RequestMapping("some_url")
  public void foo();
}

However, if I explicitly create this DynamicController bean as in

<bean class="com.package.name.DynamicController"/>

then when I start up my server the ServletContext complains that

Initialization of bean failed; nested exception is java.lang.IllegalStateException: Cannot map handler 'dynamicController' to URL path [some_url]: There is already handler of type [class $Proxy61] mapped.

So something is happening here, DynamicController is a dynamic proxy. But I don't know what else is happening and I know it's not a bean/controller any longer. I don't want "controller, aspect, dynamic proxy: pick any two" I want all three. Is this possible somehow?

2
your component-scan seems to be for com.name.package but your controller is in com.package.name..is it just a typo?Biju Kunjummen
yes, it's a demo, I'll fix itDanielKWinsor
Curious - how are you sure that the bean is not getting created at all. Not sure if I completely understood the question either - Is the issue that the bean is not getting created or that the beanpostprocessor not intercepting the dynamic proxyBiju Kunjummen
I am on the run and give you a detailed analysis. Seems to me, that you are confusing me and perhaps even spring when you duplicate all annotations (Controller, AOP_Aspect, Requestmapping) in the interface and class. Double check the examples?Stefan
Irrelevant side note: I think <context:component-scan base-package="com.package.name"/> implies <context:annotation-config/> so you have some unnecessary duplication.Dave Syer

2 Answers

0
votes

I'm not 100% sure what your BeanPostProcessor is trying to do, or if you control the code in it, but it seems safe to assume that it is not Ordered and it is therefore being processed after the proxies are created (which would have default lowest precedence, but before unordered). Maybe you can implement Ordered and give it a low order (like 0)?

0
votes

In order to pick up this bean I had to handle it in postProcessBeforeInitialization NOT postProcessAfterInitialization like I was doing before. I surmise that it is proxied when initialized and that messes up something.

As I hinted at, DynamicController is in fact a JDK dynamic proxy, but the real object behind the proxy is the bean. However! when using proxies and programming to interfaces, the annotations must be on the interface, according to some source which I have lost. Without them on the interface, spring wouldn't know. AND the annotations must be on the concrete class in order for the bean post processor to work, on the interface alone is not enough.