michael nesterenko
michael nesterenko

Reputation: 14439

wrap spring bean with another bean

I have some service bean which is accessible by identifier someSpecificService which I need to modify. Beans are defined in different xml files and are collected together in runtime. So one big xml file is created where all these xmls are imported:

context.xml
....
<import path="spring1.xml" />
<import path="spring2.xml" />
...

So there is following configuration:

<-- definitions from spring1.xml -->
<alias name="defaultSomeSpecificService" alias="someSpecificService" />
<bean id="defaultSomeSpecificService" class="..."/>
....
<!-- definitions from spring2.xml -->
<alias name="myOwnSomeSpecificService" alias="someSpecificService" />
<bean id="myOwnSomeSpecificService" class="..." /> <!-- how to inject previously defined someSpecificService into this new bean? -->

I would like to override someSpecificService from spring1.xml in spring2.xml, however I do need to inject previously defined bean defaultSomeSpecificService and all I know is its alias name someSpecificService which I need to redefine to new bean myOwnSomeSpecificService.

Is it possible to implement?

Upvotes: 1

Views: 2479

Answers (1)

Morfic
Morfic

Reputation: 15508

One solution would be to avoid trying to override the definition, by creating a proxy for the service implementation to intercept all calls towards it.

1) For the sake of the example, suppose the service would be something like:

public interface Service {
    public String run();
}

public class ExistingServiceImpl implements Service {

    @Override
    public String run() {
        throw new IllegalStateException("Muahahahaha!");
    }
}

2) Implement an interceptor instead of myOwnSomeSpecificService:

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class SomeSpecificServiceInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        String status;
        try {
            // allow the original invocation to actually execute
            status = String.valueOf(invocation.proceed());
        } catch (IllegalStateException e) {
            System.out.println("Existing service threw the following exception [" + e.getMessage() + "]");
            status = "FAIL";
        }
        return status;
    }
}

3) In spring2.xml define the proxy creator and the interceptor:

<bean id="serviceInterceptor" class="com.nsn.SomeSpecificServiceInterceptor" />

<bean id="proxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames" value="someSpecificService"/>
    <property name="interceptorNames">
        <list>
            <value>serviceInterceptor</value>
        </list>
    </property>
</bean>

4) Running a small example such as:

public class Main {
    public static void main(String[] args) {
        Service service = new ClassPathXmlApplicationContext("context.xml").getBean("someSpecificService", Service.class);
        System.out.println("Service execution status [" + service.run() + "]");
    }
}

... instead of the IllegalStateException stacktrace you'd normally expect, it will print:

Existing service threw the following exception [Muahahahaha!]
Service execution status [FAIL]

Please note that in this example the service instance is not injected in the interceptor as you asked because I had no user for it. However should you really need it, you can easily inject it via constructor/property/etc because the interceptor is a spring bean itself.

Upvotes: 2

Related Questions