我是 Spring 新手并试图理解“ 将原型(prototype) bean 注入(inject)单例 bean ”的概念。据我了解在单例中,每个 Spring IoC 容器只有一个实例,无论您检索多少次 . validator.validate(requestId);
, 因为还是 private RequestValidator validator
未实例化。
我开发了下面的示例,其中在单例 bean 中我给出了原型(prototype) bean 的引用,如下所示:
<bean id="requestProcessor" class="com.injection.testing.RequestProcessor">
<property name="validator" ref="validator" />
</bean>
<bean id="validator" class="com.injection.testing.RequestValidator" scope="prototype" />
请求处理器.java
public class RequestProcessor {
private RequestValidator validator;
public RequestProcessor(){
System.out.println("Constructor:: RequestProcessor instance created!");
}
public void handleRequest(String requestId){
System.out.println("Request ID : "+ requestId);
validator.validate(requestId);
}
public RequestValidator getValidator() {
return validator;
}
public void setValidator(RequestValidator validator) {
this.validator= validator;
}
}
RequestValidator.java
public class RequestValidator {
private List<String> errorMessages = new ArrayList<String>();
public RequestValidator() {
System.out.println("Constructor:: RequestValidator instance created!");
}
// Validates the request and populates error messages
public void validate(String requestId){
System.out.println("RequestValidator :"+requestId);
}
public List<String> getErrorMessages() {
return errorMessages;
}
}
现在,当我调用 main 方法时,我看到以下输出:
MainDemo.java
public class MainDemo {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
RequestProcessor processor = (RequestProcessor) context.getBean("requestProcessor");
processor.handleRequest("1212");
System.out.println("------------------------");
processor.handleRequest("1213");
}
}
输出是:
Constructor:: RequestProcessor instance created!
Constructor:: RequestValidator instance created!
Request ID : 1212
RequestValidator :1212
------------------------
Request ID : 1213
RequestValidator :1213
现在查看输出,看起来像是第二次调用
processor.handleRequest("1213");
bean 没有被实例化,而是已经实例化的 bean 被使用,这就是为什么构造函数不会被再次调用。所以原型(prototype) bean
validator
仅充当单例 bean。
对我来说:预计当我从应用程序上下文中获取 requestProcessor 时,它将与
new validator
连接。正如我们声明的验证器 bean 是原型(prototype)范围的。但这不会发生。
如何解决?我的理解正确吗?
其他方式:
<!-- Lookup way -->
<bean id="requestProcessor" class="com.injection.testing.RequestProcessor" >
<lookup-method name="getValidator" bean="validator" />
</bean>
<bean id="validator" class="com.injection.testing.RequestValidator" scope="prototype" />
如果我调用我的主要方法,我会在下面看到 输出+错误 : 这里代码
validator.validate(requestId);
执行,
private RequestValidator validator;
不是 instatiated 以及为什么会出现空指针异常。
我在下面的代码中显示:
public class MainDemo {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
RequestValidator requestValidator = (RequestValidator) context.getBean("validator");
RequestProcessor processor = (RequestProcessor) context.getBean("requestProcessor");
processor.handleRequest("1212");
System.out.println("------------------------");
processor.handleRequest("1213");
}
}
现在我看到以下错误:
Constructor:: RequestProcessor instance created!
Constructor:: RequestValidator instance created!
Request ID : 1212
Exception in thread "main" java.lang.NullPointerException
at com.injection.testing.RequestProcessor.handleRequest(RequestProcessor.java:12)
at com.injection.testing.MainDemo.main(MainDemo.java:14)
请您参考如下方法:
当 Spring 上下文启动时,注入(inject)只发生一次。如果 bean 有 prototype
范围内,Spring 将为每次注入(inject)创建新的原型(prototype) bean。但是每次调用它的方法时都不会创建原型(prototype)bean。让我们考虑下一个例子:
<bean id="firstRequestProcessor" class="com.injection.testing.RequestProcessor">
<property name="validator" ref="validator" />
</bean>
<bean id="secondRequestProcessor" class="com.injection.testing.RequestProcessor">
<property name="validator" ref="validator" />
</bean>
<bean id="validator" class="com.injection.testing.RequestValidator" scope="prototype" />
在这种情况下,
RequestProcessor
bean 将拥有自己的
RequestValidator
实例 bean 。
Lookup方法是方法,每次需要原型(prototype)bean的新实例时都应该调用。最好做这个方法
abstract
, 因为无论如何 Spring 都会自动覆盖这个方法。例如:
public class abstract RequestProcessor {
public void handleRequest(String requestId){
System.out.println("Request ID : "+ requestId);
RequestValidator validator = createValidator(); //here Spring will create new instance of prototype bean
validator.validate(requestId);
}
protected abstract RequestValidator createValidator();
}
请注意,
createValidator
返回
RequestValidator
的实例并且没有任何参数。你也不需要私有(private)类变量
validator
.在这种情况下,bean 的配置将如下所示:
<bean id="requestProcessor" class="com.injection.testing.RequestProcessor" >
<lookup-method name="createValidator" bean="validator" />
</bean>
<bean id="validator" class="com.injection.testing.RequestValidator" scope="prototype" />
现在每次调用
createValidator
方法,Spring 将创建
validator
的新实例 bean 。
您可以在 documentation 中找到更多详细信息.