|
|
How to get proxied bean from Context
I have a bean that is of type quot;MyTypequot;. When I call context.getNamesForType(Class.forName(quot;MyTypequot;)) it only returns the matching bean names for beans that have NOT been proxied.
How can you get a proxied bean from the context by the class name of its proxied target?Obligatory quot;why don't you just dependency injectquot; explanation:
The system I'm working with is a rules engine which can execute arbitrary java classes as defined in the DB by their fully qualified class name. There is a section of code that takes the FQCN from the DB and loads the bean from the Spring context. Works great until one or more of the beans are proxied.
I can refactor the whole design to require that everything is dependency injected. However, these rules engine classes (and their corresponding bean configs) are coming from various different jars. Refactoring would be a major undertaking involving coordination between multiple teams.
I'd really much rather figure out how to just call context.getBean* (or similar) to load proxied beans (which will require the least amount of refactoring). Trying to avoid a major refactor for something that seems so quot;simplequot;.
I don't think you can. From what I know, you don't have any control over how CGLIB names its proxies. JDK interface proxies are also not an option in your case, so with just Spring aop I don't see any solution. However, if you can refactor your aop to use AspectJ, then you don't have proxies anymore so your problem is solved.
Here's what I ended up doing.
All of these classes that I'm loading from different JARs implement a common interface, so I can load them by the interface and then loop through to find matching proxy objects like so:Code:
String className = quot;my.package.structure.MyClassWhichImplementsMyInterfacequot;;
Class targetClass = Class.forName(className);
String[] beanNames = context.getBeanNamesForType(MyInterface.class);
for (String beanName : beanNames) { MyInterface bean = (MyInterface) context.getBean(beanName);
if (AopUtils.isJdkDynamicProxy(bean)) { Class aopTargetClass = ((Advised)bean).getTargetSource().getTarget().getClass(); if (targetClass.equals(aopTargetClass)) {return bean; } } else if (targetClass.equals(bean.getClass())) { return bean; }
}
return null;
This is simplified a bit. I ended up wrapping this in a generic method to make it more flexible (which takes two generic types--the target class and the parent class or interface). I also cache the className =gt; resolved bean so the looping only ever occurs once per classname string.
This might not be bullet-proof (what happens if different AOP libraries are used?), but I hope this helps people. |
|