在Bean类中使用ApplicationContextAware初始化原型作用域Bean成员

时间:2019-01-12 05:20:35

标签: java spring

我正在学习spring,而我只是在玩ApplicationContextAware和bean作用域。

我将附加代码,然后描述我想做什么。

到目前为止,我已经创建了一个

积分等级:

public class Point {
private int x;
private int y;

public int getX() {
    return x;
}
public void setX(int x) {
    this.x = x;
}
public int getY() {
    return y;
}
public void setY(int y) {
    this.y = y;
}

@Override
public String toString() {
    return "x: "+this.x+",y: "+this.y;
}

}

我创建了一个 Triangle 类,该类具有该 Point 类的3个实例:

public class Triangle implements ApplicationContextAware, BeanNameAware{

private Point pointA;
private Point pointB;
private Point pointC;
private String beanName;
private ApplicationContext context=null;

public Point getPointA() {
    return pointA;
}

public void setPointA(Point pointA) {
    this.pointA = (Point)this.context.getBean("point1");
}

public Point getPointB() {
    return pointB;
}

public void setPointB(Point pointB) {
    this.pointB = (Point)this.context.getBean("point2");
}

public Point getPointC() {
    return pointC;
}

public void setPointC(Point pointC) {
    this.pointC = (Point)this.context.getBean("point3");
}

public void draw() {
    System.out.println("BeanName is: "+this.beanName);
    System.out.println(pointA);
    System.out.println(pointB);
    System.out.println(pointC);
}

@Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
    this.context = arg0;
}

@Override
public void setBeanName(String arg0) {
    this.beanName = arg0;
}
}

下面是 spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 5.1.1//EN" "http://www.springframework.org/dtd/spring-beans-5.1.1.dtd">

<beans>
<bean id="triangle" class="org.java.learning.Triangle" >
    <property name="pointA" ref="point1" />
    <property name="pointB" ref="point2" />
    <property name="pointC" ref="point3" />
</bean>

<bean id="point1" class="org.java.learning.Point" scope="prototype">
    <property name="x" value="0" />
    <property name="y" value="0" />
</bean>

<bean id="point2" class="org.java.learning.Point" scope="prototype">
    <property name="x" value="20" />
    <property name="y" value="20" />
</bean>

<bean id="point3" class="org.java.learning.Point" scope="prototype">
    <property name="x" value="-20" />
    <property name="y" value="20" />
</bean>

这是主类:

public class DrawingApp {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        Triangle t = (Triangle) context.getBean("triangle");

        t.draw();
    }
}

因此,您会看到point1point2point3这三个bean的bean范围是prototype,但它们是bean triangle的成员,其范围默认为singleton

中的spring.xml

因此,我的假设是,除非我可以以某种方式在ApplicationContext类中获得Triangle并设置pointApointB,{{1} }就像我使用pointC

在他们的setter方法中所做的一样

不确定这种方法是否正确,或者不确定这在实时应用程序中是否有用。

因此,如果以上所有代码都能正常工作,我应该得到三行输出,例如:

ApplicationContext.

但是当我运行main方法时,出现以下错误:

  

警告:上下文初始化期间遇到异常-取消       刷新尝试:org.springframework.beans.factory.BeanCreationException:       创建类路径资源中定义的名称为“ triangle”的bean时出错       [spring.xml]:设置属性值时出错;嵌套异常为       org.springframework.beans.PropertyBatchUpdateException;嵌套的       PropertyAccessExceptions(3)是:       PropertyAccessException 1:       org.springframework.beans.MethodInvocationException:属性“ pointA”被抛出       例外;嵌套的异常是java.lang.NullPointerException       PropertyAccessException 2:       org.springframework.beans.MethodInvocationException:属性“ pointB”被抛出       例外;嵌套的异常是java.lang.NullPointerException       PropertyAccessException 3:       org.springframework.beans.MethodInvocationException:属性“ pointC”被抛出       例外;嵌套的异常是java.lang.NullPointerException       线程“主”中的异常       org.springframework.beans.factory.BeanCreationException:创建bean时出错       类路径资源[spring.xml]中定义的名称为“ triangle”的数据库:错误       设置属性值;嵌套异常为       org.springframework.beans.PropertyBatchUpdateException;嵌套的       PropertyAccessExceptions(3)是:       PropertyAccessException 1:       org.springframework.beans.MethodInvocationException:属性“ pointA”被抛出       例外;嵌套的异常是java.lang.NullPointerException       PropertyAccessException 2:       org.springframework.beans.MethodInvocationException:属性“ pointB”被抛出       例外;嵌套的异常是java.lang.NullPointerException       PropertyAccessException 3:       org.springframework.beans.MethodInvocationException:属性“ pointC”被抛出       例外;嵌套的异常是java.lang.NullPointerException       在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1685)       在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1400)       在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:575)       在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)处       在org.springframework.beans.factory.support.AbstractBeanFactory.lambda $ doGetBean $ 0(AbstractBeanFactory.java:320)       在org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)       在org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)       在org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)       在org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846)       在org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863)处       在org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)       在org.springframework.context.support.ClassPathXmlApplicationContext。(ClassPathXmlApplicationContext.java:144)       在org.springframework.context.support.ClassPathXmlApplicationContext。(ClassPathXmlApplicationContext.java:85)       在org.java.learning.DrawingApp.main(DrawingApp.java:9)       由以下原因引起:org.springframework.beans.PropertyBatchUpdateException;嵌套的       PropertyAccessExceptions(3)是:       PropertyAccessException 1:       org.springframework.beans.MethodInvocationException:属性“ pointA”被抛出       例外;嵌套的异常是java.lang.NullPointerException       PropertyAccessException 2:       org.springframework.beans.MethodInvocationException:属性“ pointB”被抛出       例外;嵌套的异常是java.lang.NullPointerException       PropertyAccessException 3:       org.springframework.beans.MethodInvocationException:属性“ pointC”被抛出       例外;嵌套的异常是java.lang.NullPointerException       在    org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:122)       在org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:77)       在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.app       lyPropertyValues(AbstractAutowireCapableBeanFactory.java:1681)       ...还有13个

我认为设置 pointA,pointB和pointC 成员变量的值时做错了事

请让我知道我是否需要任何详细信息,以消除此错误并实现我正在尝试做的事情。

3 个答案:

答案 0 :(得分:1)

与您面临的错误无关,让我们看看您的课程设置:

您希望您的观点成为原型。因此,每次您通过注入请求新的Bean时,Spring都会为您提供一个新的实例。

现在您将原型bean注入Triangle bean中,默认情况下它是单例的(这意味着它仅被请求并创建一次)。因此,还需要一次请求原型bean(点)将其注入单例Triangle bean中。

从现在开始,您的原型bean不再像原型bean那样工作,这意味着它们从您的Triangle bean继承了单例作用域。

但是在这种设置下,您很好,但是您应该牢记这一陷阱:仅当从容器/上下文请求Bean时,Spring才会创建原型Bean的新实例。

答案 1 :(得分:1)

您正在获取NPE,因为以下和类似方法中上下文对象为空

public void setPointC(Point pointC) {
    this.pointC = (Point)this.context.getBean("point3");
}

仅当所有bean都初始化并且上下文对象准备就绪时,才会在ApplicationContextAware Bean中设置上下文对象。

您的代码应如下所示

public void setPointC(Point pointC) {
        this.pointC = pointC;
    }

答案 2 :(得分:0)

导致代码抛出异常的两个原因:

  • new ClassPathXmlApplicationContext("spring.xml")方法无法意识到类上下文已准备就绪。
  • 循环依赖。创建ApplicationContext需要成功创建所有bean,但是Triangle需要上下文。

您可以使用IOC解决您的问题。