Bean 必须有默认构造函数吗?

Must a Bean have a default constructor?

我正在阅读 JavaBean specification 但我找不到其中明确指出 bean 必须具有默认构造函数的句子。那么是不是?

你可以看看关于java bean的维基百科:

https://en.wikipedia.org/wiki/JavaBeans

bean 应该有一个 public 默认构造函数是它符合 JavaBean 资格的规则之一。然而,这并没有被标准明确定义,但却是许多框架采用的良好做法。

编辑: 如果我们要详细说明为什么需要非参数构造函数(但通常不强制执行)的原因,以下是原因之一:

CDI 框架通常有两种在 bean 中注入依赖项的方法:

构造函数注入: 您在其构造函数中明确定义了 bean 的依赖项。示例 (Spring):

@Component
public class SuchBean {
     private MuchDependency muchDependency;

     @Autowired
     public SuchBean(MuchDependency muchDependency){
         this.muchDependency = muchDependency;
     }

}

Setter/Reflection 注入:你不一定要通过构造函数注入任何依赖,但依赖是由 CDI 环境通过使用反射或二传手。示例:

@Component
public class SuchBean {
     // this dep doesn't have a setter, so the CDI will use reflection to set it
     @Autowired private MuchDependencyWithReflection muchDependencyWithReflection;
     // this dep has a setter so the CDI will use the setter to set it
     @Autowired private MuchDependencyWithSetter muchDependencyWithSetter;

     public void setMuchDependencyWithSetter(MuchDependencyWithSetter muchDependencyWithSetter){
         this.muchDependencyWithSetter = muchDependencyWithSetter;
     }
}

在上面的示例中,如果您没有显式定义无参数构造函数,当然,您知道,Java 会为您提供它(因为每个 class 都没有有任何显式定义的构造函数,只是有一个自动提供的无参数构造函数)。因此,在您决定使用 args:

定义自己的构造函数之前,一切都会很好而且花花公子
@Component
public class SuchBean {
     // this dep doesn't have a setter, so the CDI will use reflection to set it
     @Autowired private MuchDependencyWithReflection muchDependencyWithReflection;
     // this dep has a setter so the CDI will use the setter to set it
     @Autowired private MuchDependencyWithSetter muchDependencyWithSetter;

     public SuchBean(String nonDefaultConstuctorArg){
         System.out.println(nonDefaultConstuctorArg);
     }

     public void setMuchDependencyWithSetter(MuchDependencyWithSetter muchDependencyWithSetter){
         this.muchDependencyWithSetter = muchDependencyWithSetter;
     }
}

在上面的例子中它并不明显,但是任何依赖框架都会抱怨并且无法实例化它,因为实际上,当你使用 reflection/setter 注入时,框架会:

Constructor.newInstance();

在幕后然后注入依赖项。但是,由于您刚刚使 class 没有默认构造函数,因此没有 args 的 newInstance() 将不起作用。因此,在这种情况下,您需要一个默认的 args 构造函数。总结:

  • 如果使用构造函数注入,则不需要无参数构造函数。
  • 如果使用reflection/setter注入,需要使用无参 构造函数。
  • 既然好的代码应该有好的约定,JavaBeans 标准 "nudges" 你喜欢在任何地方都有一个默认的无参数构造函数,以拥有一个一致的、常规的代码,可以跨各种框架使用,并且由于它的标准化而成为 readable/understandable/maintainable。

不需要它(需要一些反射框架),但这是一个很好的做法

bean 不需要有默认构造函数。仅仅是因为规范没有定义该要求。

另外章节10.3 Instantiating a bean讲到获取bean实例:

A bean can be delivered as either a serialized template (which must be deserialized to create an instance of the bean) or as an implementation class (where a bean instance is created simply by creating an instance of the class).

此策略由 Beans.instantiate 实现:它查找序列化 bean(一种特殊命名的 Java 资源)。如果找不到,它会尝试通过 Class.newInstance 实例化 bean。但是这种机制清楚地表明规范编写者考虑提供一种通用方法来获取没有默认构造函数的 bean 实例。