tags:

views:

1112

answers:

4

I'm attempting to implement a delegate Service provider by overriding the bean definition for the original service with my delegate Service. However, as the name would imply, the delegate Service needs a reference to the original service to delegate calls to.

I'm having trouble figuring out how to override the bean definition while using the original bean def without running into a circular reference issue.

For example:

<!-- Original service def in spring-context.xml -->
<bean id="service" class="com.mycompany.Service"/>

<!-- Overridden definition in spring-plugin-context.xml -->
<bean id="service" class="com.mycompany.DelegatedService"/>
    <constructor-arg ref="service"/>
</bean>

Is this possible?

+1  A: 

You can create proxies and interceptors. So now the bean named service will become a proxy to the original service which needs to be renamed to something else. So the changes will be limited to the Spring XML only and not be propagated to your java code.

<bean id="personTarget" class="com.mycompany.PersonImpl">
    <property name="name"><value>Tony</value></property>
    <property name="age"><value>51</value></property>
</bean>

<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
    <property name="someProperty"><value>Custom string property value</value></property>
</bean>

<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor">
</bean>

<bean id="person" 
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces"><value>com.mycompany.Person</value></property>

    <property name="target"><ref local="personTarget"/></property>
    <property name="interceptorNames">
        <list>
            <value>myAdvisor</value>
            <value>debugInterceptor</value>
        </list>
    </property>
</bean>
saugata
I can't rename the original "service" bean to anything else because it is defined in a spring context that is out of my control
Kevin
AFAIK, that is impossible in spring. Plus even if it were possible it would be bad practice, if someone wrote the bean with a particular functionality in mind and closed it to modification you might end up breaking the original functionality. One (bad) work-around will be that you define your own class with the same signature and use a custom class loader to load the original class and delegate to it. It would be better if you could post your end requirement.
saugata
A: 

It sounds like you're trying to reinvent spring-AOP. Please consider using spring-AOP for this.

It's possible to programatically change the name of the existing service and create a new bean with the old name. The autoproxying-code inside spring framework does this and you could have a look at that. A quick code search for *Auto*Proxy* in the spring framework should get you there.

Alternately if you control the client sites (the consumers), you could add a qualifier to your wrapper, and use qualifiers to coerce the proper implementations to the consumers. The the wrapper could use the unqualified implemementation to get access to the original. (It might also be possible to retro-mount a qualifier to the original implementation by adding another bean definition for service with a qualifier in xml code that you control, haven't tried this but it should work)

krosenvold
+1  A: 

The short answer to your question is that you cannot have two bean definitions with the same name. If you try, one will hide the other, and only one definition will be usable.

Your question's example seems to suggest that you're trying to wrap the original service bean in a proxy object, with the wrapper performing some before-and-after work around calls to the service. One way to achieve this, without defining two service beans, and without modifying the original service bean, is to use a Spring AutoProxyCreator, probably a BeanNameAutoProxyCreator.

This allows you to list a bean (or beans) that are to be automatically proxied. You specify the interceptors you want to be applied to invocations on the target bean. You would implement these interceptors to do the work you need to do.

Spring would automatically create a delegating proxy for you, which would have the bean id service as before, but with your additional functionality.

skaffman
This answer was the most useful though my problem turned out to be unsolvable. In order to proxy the class, it must be woven by an aspect. Since the class I was attempting to proxy was already compiled and run in a different classloader, I was not able to proxy it.
Kevin
@Kevin: An `AutoProxyCreator` doesn't proxy classes, it proxies bean. It shouldn't matter which classloader loads the target class, it's the target object that is proxied, and Spring instantiates that target object.
skaffman
A: 

Use the "parent" attribute of the "ref" element with a parent container.
You can find a detailed example in Spring documentation: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-ref-element

Oded Peer