4

我来自 .NET 背景,使用过 Unity、Ninject、Castle Windsor 等依赖注入容器。最近开始学习使用 Spring 的 Java 依赖注入功能。

在学习 Spring 时,我发现可以在 bean XML 配置中指定“init-method”和“destroy-method”的概念。

指定“init-method”的目的似乎是在创建 bean 时进行您可能想要做的任何设置。这就是我感到困惑的地方。为什么你需要一个单独的方法来执行设置,而不是仅仅使用构造函数来执行对象所需的任何设置,就像正常/良好的面向对象设计所要求的那样?

换句话说,如果一个类需要一个依赖项,它不应该被注入到构造函数中,你知道它已经被调用了,而对象可以在没有调用它的状态下存在'init-method'?

4

3 回答 3

9

在少数情况下init()需要单独的方法:

  • 您别无选择的遗留 API

  • 初始化有一些副作用,例如启动 a Thread,连接到 som 外部资源

    这实际上具有更深层次的含义:当使用基于类的代理(通过)时,基类的构造函数被调用两次(第二次为从您的类继承的代理) -init()方法仅在最终对象上调用一次。

  • 你不应该在构造函数中执行虚拟调用(这实际上应该被编译器禁止......)

  • 有时您必须使用 setter/field 注入(尽管我喜欢构造函数注入),例如,当使用上述基于类的代理时

使用构造函数执行对象所需的任何设置,例如正常/良好的面向对象设计会指示?

这实际上不是将所有初始化代码放在构造函数中的最佳实践。构造函数中的副作用使测试和模拟变得更加困难。而是专注于创建稳定已知状态的对象。通过这种方式,您可以例如解耦创建一个管理连接池的对象并物理连接到该池。

BTWdestroy()是一种没有析构函数的语言的福音,因为它允许您感激地关闭外部资源、中断线程等。经常使用它。

于 2012-07-08T08:42:10.627 回答
5

你为什么需要它?

在设置了 bean 的所有属性后调用 init 方法。如果 bean 需要对属性进行一些初始化或验证,而这些属性只能在设置完所有属性后完成,则通常需要这样做。(如果您尝试在没有“init”回调的情况下执行此操作,您会发现每个属性设置器都必须检查其他设置器是否已被调用,依此类推。如果只能在所有属性之后进行初始化,那么即使该策略也会失败在一个循环的 bean 中已设置。)

如果 bean 持有需要显式释放的资源,则需要使用 destroy 方法;例如文件句柄、网络套接字、数据库连接。

...像正常/良好的面向对象设计会决定吗?

任何规定 init 和 destroy 事件/方法是“错误”或“禁止”的设计方法都是不现实的,应该被忽略。事实上,面向对象的设计方法通常不会规定这一点。他们最多会说这种东西通常不需要。

此外,DI 实际上在一定程度上改变了设计方法的规则……至少在初始化方面。特别是,通过将实例的“连接”外部化,它以经典 OO 设计方法没有预料到的方式从代码中提取出很多逻辑。如果有的话,这就是说需要根据依赖注入重新审视经典的 OO 方法。

于 2012-07-08T04:16:04.870 回答
0

如果您使用的是 setter 注入,那么肯定需要 init 方法/InitializingBean/@PostConstruct 以便在所有属性都已设置/自动装配后进行初始化。否则你有一个构造但不是依赖注入的对象。如果您使用构造函数注入,则很少需要它,在 Tomasz 和 Stephen 指出的情况下。

于 2012-07-09T02:50:45.510 回答