如何覆盖Spring bean定义但仍然引用被覆盖的bean?

11

我试图通过覆盖原始服务的bean定义来实现代理服务提供程序,然后使用我的代理服务。然而,正如名称所示,代理服务需要引用原始服务以委托调用。

我发现很难在使用原始bean定义的情况下覆盖bean定义,而不会遇到循环引用的问题。

例如:

<!-- 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>

这个有可能吗?

5个回答

11
您的问题的简短回答是:您不能有两个名称相同的Bean定义。如果尝试这样做,一个会覆盖另一个,只有一个定义可以使用。
您的问题示例似乎表明您正在尝试在代理对象中包装原始的service bean,并使包装器执行一些调用服务前后的工作。一种实现此目的的方法,而不定义两个service beans,也不修改原始的service bean,是使用Spring的AutoProxyCreator,可能是一个BeanNameAutoProxyCreator
这允许您列出要自动代理的bean(或beans)。您指定要应用于目标bean上调用的拦截器。您将实现这些拦截器来执行所需的工作。
Spring会自动为您创建委托代理,其bean id仍为service,但具有额外的功能。

尽管我的问题最终无法解决,但这个答案是最有用的。为了代理该类,必须通过一个方面进行编织。由于我试图代理的类已经在不同的类加载器中编译和运行,所以我无法代理它。 - Kevin
@Kevin:AutoProxyCreator 不会代理类,而是代理 bean。无论哪个类加载器加载目标类都不应该有影响,被代理的是目标对象,Spring 实例化该目标对象。 - skaffman
回答原问题,一种模式是简单地声明一个“裸”底层bean。在一个配置中将其别名为目标bean名称,在另一个配置中定义您的包装器,该包装器注入了底层bean。不过,这需要事先进行规划。 - aaron

2
您可以创建代理和拦截器。因此,名为service的bean将成为原始service的代理,需要将其重命名为其他名称。因此,更改将仅限于Spring XML,并且不会传播到Java代码中。
<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>

我无法将原始的“service” bean 重命名为其他任何内容,因为它是在我无法控制的 Spring 上下文中定义的。 - Kevin
据我所知,在Spring中这是不可能的。即使可能,这也是不好的做法。如果有人编写了一个特定功能的bean并将其关闭以进行修改,您可能会破坏原始功能。一个(不好的)解决方法是定义一个具有相同签名的自定义类,并使用自定义类加载器来加载原始类并委托给它。如果您能发布您的最终需求,那就更好了。 - saugata

1

听起来你正在尝试重新发明Spring-AOP。请考虑使用Spring-AOP。

可以通过编程方式更改现有服务的名称并创建一个新的bean,Spring框架内部的自动代理代码就是这样做的,你可以查看一下。在Spring框架中快速搜索AutoProxy*应该能找到它。

或者,如果你控制客户端站点(消费者),你可以向你的包装器添加一个限定符,并使用限定符来强制将正确的实现提供给消费者。然后包装器可以使用未经限定的实现来访问原始实现。 (也可能通过在你控制的xml代码中添加另一个带有限定符的服务bean定义来对原始实现进行后期挂载限定符,我没有尝试过,但应该可以工作)


1

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接