将原型bean注入单例bean

7 spring

我是Spring的新手,并试图理解" 将原型bean注入单个bean "的概念.根据我的理解在单例中,每个Spring IoC容器只有一个实例,无论你检索它多少次.validator.validate(requestId);,因为还private RequestValidator validator没有实例化.我开发了以下示例,在单例bean中,我给出了原型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" />
Run Code Online (Sandbox Code Playgroud)

RequestProcessor.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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在当我调用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");
    }
}
Run Code Online (Sandbox Code Playgroud)

输出是:

Constructor:: RequestProcessor instance created!
Constructor:: RequestValidator instance created!
Request ID : 1212
RequestValidator :1212
------------------------
Request ID : 1213
RequestValidator :1213
Run Code Online (Sandbox Code Playgroud)

现在查看输出,看起来第二个调用processor.handleRequest("1213");bean没有实例化,而是已经实例化的bean被使用,这就是为什么构造函数不会再被调用.所以Prototype validatorbean只作为单例bean使用.

对我来说:我希望当我从应用程序上下文中获取requestProcessor时,它将与new validator我们声明验证器bean是原型范围的连接.但这不会发生.

怎么解决?我的理解是否正确?

其他方式:

<!-- 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" />
Run Code Online (Sandbox Code Playgroud)

如果我调用我的main方法,我在下面看到输出+错误:这里代码validator.validate(requestId);执行,private RequestValidator validator;没有实例化,为什么空指针异常会到来.

我在下面的代码中显示:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我看到以下错误:

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)
Run Code Online (Sandbox Code Playgroud)

Ken*_*kov 6

当Spring上下文启动时,注入只发生一次.如果bean有prototype范围,Spring将为每次注入创建新的原型bean.但每次调用其方法时都不会创建原型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" />
Run Code Online (Sandbox Code Playgroud)

在这种情况下,两个RequestProcessorbean都有自己的RequestValidatorbean 实例.


Lookup方法是方法,每次需要原型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();
}
Run Code Online (Sandbox Code Playgroud)

注意,createValidator返回实例RequestValidator并且没有任何参数.您也不需要私有类变量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" />
Run Code Online (Sandbox Code Playgroud)

现在每次调用createValidator方法时,Spring都会创建validatorbean的新实例.

您可以在文档中找到更多详细信息.