23

我是 spring 框架的新手,从一些教程开始学习它。

我有以下文件,

# 主程序.java

package test.spring;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainProgram {
        public static void main(String[] args) {
              AbstractApplicationContext context = 
                              new ClassPathXmlApplicationContext("Bean.xml");     
              HelloSpring obj = (HelloSpring) context.getBean("helloSpring");
              obj.setMessage("My message");
              obj.getMessage();
              context.registerShutdownHook();

        }
 }

#HelloSpring.java

package test.spring;

public class HelloSpring   {
     private String message;

     public void setMessage(String message){
      this.message  = message;
      System.out.println("Inside setMessage");
   }

   public void getMessage(){
      System.out.println("Your Message : " + this.message);
   }

   public void xmlInit() {
    System.out.println("xml configured  initialize");
   } 

    public void xmlDestroy() {
    System.out.println("xml configured destroy");
    }

  }

# 豆.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

     <bean id="helloSpring" class="test.spring.HelloSpring" 
          scope="prototype" init-method="xmlInit" destroy-method="xmlDestroy">

     </bean>
     </beans>

当我采取scope="singleton" 我的输出是:

 xml configured  initialize
 Inside setMessage
 Your Message : My message
 xml configured destroy

当我采取scope="prototype" 我的输出是:

 xml configured  initialize
 Inside setMessage
 Your Message : My message

xmlDestroy()方法是使用singleton范围 bean 调用的,但prototype 请不要帮我以下,

它是否正确?如果是这样,可能的原因是什么?

我也有一些疑问,例如,

之间有什么区别或关系 ApplicationContext , AbstractApplicationContext and ClassPathXmlApplicationContext

4

6 回答 6

45

xmlDestroy()方法是用单例范围 bean 调用的,但不是用原型调用的,因为

Spring 不管理原型 bean 的完整生命周期:容器实例化、配置、装饰和以其他方式组装原型对象,将其交给客户端,然后不再了解该原型实例。为了释放资源,请尝试实现自定义 bean 后处理器。

与 spring 容器管理完整生命周期的单例 bean 不同

您可以查看此基本教程,了解不同上下文之间的差异

参考文档

于 2013-02-23T12:37:34.223 回答
2

这是预期的行为。Spring 无法知道您何时完成了原型范围 bean 的使用,因此 Spring 不会为原型范围 bean 管理 bean 销毁。从文档中:

尽管初始化生命周期回调方法在所有对象上都被调用,无论范围如何,但在原型的情况下,不会调用配置的销毁生命周期回调。

有关更多信息,请参阅Spring 文档

关于ApplicationContexts,您可以选择最适合您的应用的一种。例如,这取决于您是要使用 XML 还是注释 bean 配置,以及您是否在 servlet 容器中运行。 ApplicationContext它本身就是类型层次结构根部的接口。

于 2013-02-23T12:34:19.590 回答
2

单例 bean 意味着在应用程序上下文中只有一个该 bean 的实例。这意味着如果您执行以下操作:

HelloSpring obj = (HelloSpring) context.getBean("helloSpring");
    obj.setMessage("My message");
    System.out.printIn(obj.getMessage());
    HelloSpring anotherObj = (HelloSpring) context.getBean("helloSpring");
    System.out.printIn(anotherObj.getMessage());

您将在控制台输出中看到两次“我的消息”。

对于原型 bean,每次您尝试从应用程序上下文中获取其中一个时,您将获得一个新实例,因此如果您再次运行上述代码,第二个控制台输出将为“null”。

由于容器不需要为原型 bean 调用 destroy 方法,因此不需要,并且行为是正确的。

上述类之间的区别在于它们分别是接口、抽象类和具体类,为了更好地理解这些概念,我建议阅读Oracle Java 教程中的 Java 官方 oracle 文档。

于 2013-02-23T12:38:30.560 回答
2

您的应用程序可以每 10 毫秒请求一次原型 bean 的新实例,对 bean 做一些事情,然后让它超出范围。如果 Spring 必须在应用程序关闭时销毁()它们,它必须保留对每个创建的原型 bean 的引用,防止它们被垃圾收集,从而导致内存泄漏。

于 2017-12-01T08:45:46.660 回答
0

我还尝试获取 bean 的销毁事件,其范围是“原型”。所以我阅读了上面的所有答案并尝试他们的答案。结果,我发现即使原型 bean 也无法检测到破坏。

尽管初始化生命周期回调方法在所有对象上都被调用,无论范围如何,但在原型的情况下,不会调用配置的销毁生命周期回调。

见这里(https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-factory-scopes-prototype

于 2017-10-25T16:11:14.260 回答
-3

请在您的 spring 配置文件中检查您的范围类型。如果 scope="prototype" 则将其更改为 scope="singleton"

<bean id="helloWorld" class="com.example.test.HelloWorld"
init-method="init" destroy-method="destroy">
<property name="message" value="Hello World!" />

于 2015-10-25T11:20:25.223 回答