Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you inject a proxy into a service?

There is some information in the tomcat engine that we want to access run time, so we have the following in our app context (got this from this blog post):

<bean id="tomcatEngineProxy" class="org.springframework.jmx.access.MBeanProxyFactoryBean">
    <property name="objectName" value="Catalina:type=Engine" />
    <property name="proxyInterface" value="org.apache.catalina.Engine" />
    <property name="useStrictCasing" value="false" />
</bean>

In a controller, we then autowired it in like this:

@Autowired
private MBeanProxyFactoryBean tomcatEngineProxy = null;

We cannot wire in org.apache.catalina.Engine like in the blog post, because that class is not available to us at build time. It's only available at run time with all the different tomcat versions running on the different machines.

We were able to get the information we needed from this @Autowire using reflection. Now, we want to move this functionality into a service. I added this to our app context:

<bean id="myService" class="com.foo.bar.MyServiceImpl">
    <constructor-arg ref="tomcatEngineProxy" />
</bean>

And the class looks like this:

public class MyServiceImpl implements MyService
{
    public MyServiceImpl(MBeanProxyFactoryBean tomcatEngineProxy) throws Exception
    {
         //stuff with the proxy
    }
    .....
}

When I do this, I get the following error:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myService' defined in ServletContext resource [/WEB-INF/spring/root-context.xml]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.springframework.jmx.access.MBeanProxyFactoryBean]: Could not convert constructor argument value of type [$Proxy44] to required type [org.springframework.jmx.access.MBeanProxyFactoryBean]: Failed to convert value of type '$Proxy44 implementing org.apache.catalina.Engine,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'org.springframework.jmx.access.MBeanProxyFactoryBean'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [$Proxy44 implementing org.apache.catalina.Engine,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.jmx.access.MBeanProxyFactoryBean]: no matching editors or conversion strategy found

Knowing basically nothing about how proxies work and how to use them, I'm not sure how to go about making this work. Is there some declaration I can use for my constructor arg that will match up? What is different between the @Autowire in the controller that does work and the constructor arg that doesn't work?

like image 835
dnc253 Avatar asked Oct 07 '22 14:10

dnc253


1 Answers

It's because your factory bean is exposing the result as the engine interface:

<property name="proxyInterface" value="org.apache.catalina.Engine" />

So if you try to wire in the "tomcatEngineProxy" bean itself, it's only compatible assignment is to "org.apache.catalina.Engine", since the created proxy implements only that interface.

try referencing the factory bean directly instead (notice the ampersand which is the syntax for finding the actual factory bean which created the object instead of the object itself):

<constructor-arg ref="&tomcatEngineProxy" />

How to inject FactoryBean instead of object it produces?

like image 96
Matt Avatar answered Oct 10 '22 03:10

Matt