5

我有一个单例 Spring bean(它必须保持单例),每次执行某个方法时,它都需要另一个 bean 的新实例(我们称之为 X)。

到目前为止,我研究了以下方法:

  • 只需使用 new 创建 X。这工作了一段时间,但现在我们需要 X 的 Spring AOP 特性,所以这不再工作了,因为生成的实例不是 Spring 管理的。

  • 我将 FactoryBean 视为依赖项,但我只会从 FactoryBean 获得一个 X 实例,这不符合我的第一个实例。

  • 目前的计划是在 Spring 上下文中手动查找 X,并在那里使用原型依赖项声明它。这应该可行,但我认为它真的很难看。

=>我如何在我的bean中注入一个工厂,以便我可以在我认为合适的任何时候调用它的工厂方法并从中获取一个spring托管实例。

4

2 回答 2

12

此类场景的选择方法称为查找方法注入。简而言之,这使用了调用 bean 方法的方法,从而创建了一个新的 bean 实例。您将首先创建一个具有抽象方法的类,该方法最终将提供依赖项实例:

abstract class MyClient implements Client {

  void businessMethod(…) {

    Dependency dependency = getDependencyInstance();
    …
  }

  abstract Dependency getDependencyInstance();
}

您现在继续为依赖项配置原型 bean 定义:

<bean id="dependency" class="….DependencyImpl" scope="prototype" />

以及使用该lookup-method元素的客户端始终为每个方法调用获取依赖项的新实例:

<bean class="….MyClient">
  <lookup-method name="getDependencyInstance" bean="dependency" />
</bean>

这将导致创建一个 CGLib 代理,并由 a 支持MyClient的方法声明与要查找的 bean 的引用和名称。在每次方法调用时,都会触发 bean 查找并返回原型配置 bean 的新实例。getDependencyInstance(…)TargetSourceBeanFactory

于 2012-10-23T08:30:46.327 回答
2

我没有看到工厂 bean 的问题,我会这样做:

import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

@Component
public class X {
    public static class XFactory implements FactoryBean<X> {

        @Override
        public X getObject() throws Exception {
            return new X();
        }

        @Override
        public Class<?> getObjectType() {
            return X.class;
        }

        @Override
        public boolean isSingleton() {
            return false;
        }       
    }
}

并注入这个工厂bean。

否则,您可以使用

@Scope(proxyMode=ScopedProxyMode.TARGET_CLASS, value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)

您必须使用非默认代理模式,以便 spring 创建一个代理,该代理始终向您的单例返回一个新实例。

如果您使用的是 XML 配置,那么请这样做:

<bean id="x" class="X" scope="prototype">
<aop:scoped-proxy>
</bean>

玩得开心。

编辑:

当您通过 @Component 注释您的工厂时(我已在上面添加),在 #isSingleton 中返回 false 并确保您不返回您的 X 两次,您可以将带有 @Autowired 的工厂 bean 注入您的单例中。

否则我刚刚检查过

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

@Component
@Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class X {
}

它按预期工作。

编辑2:

如果您不想注入工厂 bean,而只想注入依赖项,则可以对工厂范围进行原型化 (@Scope(proxyMode=ScopedProxyMode.TARGET_CLASS, value="prototype")),但每次 X 都会创建一个新工厂涉及这可能不是你想要的。

如果您不想注入工厂本身,我会使用 Olivers 查找方法。

于 2012-10-23T07:02:15.127 回答