我在Spring XML描述符中使用原型范围的bean定义来配置默认属性(这些bean有许多属性),然后用getBean(beanName, ctorArgs[])
调用应用程序上下文来创建实例。
bean定义需要2-3个构造函数参数,这些参数提供逻辑上唯一的键,用于JMX ObjectName
的键属性等。另外,构造函数参数写入的变量是final。
我所看到的是,当应用程序上下文刷新时,它会尝试实例化这些原型,这看起来与原型要做的完全相反。它们是模板,而不是实际的实例。为了解决这个问题,我一直在使用伪造的ctor值配置原型,以便实例化这些伪造的bean实例,我只是在代码中过滤掉创建的MBean。
我的问题是,在我进行getBean
调用之前,如何将应用程序上下文配置为注册这些原型bean定义,而不是实例化它们?
答案 0 :(得分:7)
问题比我最初想的要复杂一点。事实上,lazy是原型范围bean的默认行为。我挖了一点,我设法重现你的问题,找到解决方案。那么问题是什么?
您可能已启用<aop:scoped-proxy/>
或(@ComponentScan(scopedProxy=...)
等效)。在上下文刷新期间,Spring使用作用域代理包装原型bean(ClosedMetricSubscriberFeed
)。它使用类代理,因为(a)选择类代理或(b)类没有接口。
基于类的代理基本上是bean的CGLIB子类,必须调用(由于JVM规则)基类的构造函数。 CGLIB生成的类总是调用no-arg构造函数。
我知道这听起来很复杂,这就是你能做的事情:
禁用<aop:scoped-proxy/>
。就像那样。
提供一个虚拟的无参数构造函数并弃用它以防万一。不幸的是,你将不得不发现这样的虚假实例。请注意,在这种情况下,类的类型为:``。
从类中提取接口并使用接口作为作用域代理:
@Scope(
value = ConfigurableBeanFactory.SCOPE_PROTOTYPE,
proxyMode = ScopedProxyMode.INTERFACES)
使用@Lazy
注释或lazy-init="true"
(参见参考文档中的4.4.4 Lazy-initialized beans)配置属性进行延迟初始化。
<bean id="proto" class="MyPrototype" scope="prototype" lazy-init="true"/>
或:
@Service
@Scope("prototype")
@Lazy
public class MyPrototype {/*...*/}
答案 1 :(得分:0)
我使用抛出IllegalStateException的私有的,不推荐的,无参数的构造函数。上下文加载正常,getBean()与构造函数args工作正常,而没有args的getBean()抛出异常。
package a;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component("myCommand")
@Scope("prototype")
public class Command {
final protected String name;
@Deprecated
private Command() {throw new IllegalStateException("Only for Spring"); }
public Command(String name) {
super();
this.name = name;
}
@Override
public String toString() {
return "Command [name=" + name + "]";
}
}