如何防止Spring在上下文刷新时实例化原型范围的bean?

Nic*_*las 4 spring

我在我的Spring XML描述符中使用原型范围的bean定义来配置默认属性(这些bean有许多属性)然后我用a getBean(beanName, ctorArgs[])来调用应用程序上下文来创建实例.

bean定义需要2-3个构造函数参数,这些参数提供逻辑上唯一的键,用于JMX的键属性ObjectName等.另外,构造函数参数写入的变量是final.

我所看到的是,当应用程序上下文刷新时,它会尝试实例化这些原型,这看起来与你想要原型的完全相反.它们是模板,而不是实际的实例.为了解决这个问题,我一直在使用伪造的ctor值配置原型,以便实例化这些伪造的bean实例,我只是在代码中过滤掉创建的MBean.

我的问题是,如何配置应用程序上下文来注册这些原型bean定义,但是在我打电话之前不实例化它们getBean

Tom*_*icz 7

更新:

问题比我最初想的要复杂一些.事实上,lazy是原型范围bean的默认行为.我挖了一点,我设法重现你的问题,找到解决方案.那么问题是什么?

您可能已<aop:scoped-proxy/>启用或(@ComponentScan(scopedProxy=...)等效).在上下文刷新期间,Spring用原型ClosedMetricSubscriberFeed代理包装你的原型bean().它使用类代理,因为(a)选择类代理或(b)类没有接口.

基于类的代理基本上是bean的CGLIB子类,必须调用(由于JVM规则)基类的构造函数.CGLIB生成的类总是调用no-arg构造函数.

我知道这听起来很复杂,这就是你能做的:

  1. 禁用<aop:scoped-proxy/>.就像那样.

  2. 提供一个虚拟的无参数构造函数并弃用它以防万一.不幸的是,你将不得不发现这样的虚假实例.请注意,在这种情况下,类的类型为:``.

  3. 从类中提取接口并使用接口作为范围代理:

.

@Scope(
  value = ConfigurableBeanFactory.SCOPE_PROTOTYPE,
  proxyMode = ScopedProxyMode.INTERFACES)
Run Code Online (Sandbox Code Playgroud)

老答案:

使用带@Lazy注释的延迟初始化或lazy-init="true"(参见参考文档中的4.4.4 Lazy-initialized beans)配置属性.

<bean id="proto" class="MyPrototype" scope="prototype" lazy-init="true"/>
Run Code Online (Sandbox Code Playgroud)

要么:

@Service
@Scope("prototype")
@Lazy
public class MyPrototype {/*...*/}
Run Code Online (Sandbox Code Playgroud)