组件系列、组件类型和渲染器类型之间的关系是什么?

当我在 JSF 中学习自定义组件开发时,我对组件系列、组件类型和渲染器类型之间的关系感到困惑。例如,我注册了一个渲染器和一个自定义组件,如下所示。

faces-config.xml:

<component>
    <component-type>study.faces.Div</component-type>
    <component-class>javax.faces.component.UIPanel</component-class>
</component>

<render-kit>
    <render-kit-id>HTML_BASIC</render-kit-id>
    <renderer>
        <component-family>javax.faces.Panel</component-family>
        <renderer-type>study.faces.DivRenderer</renderer-type>
        <renderer-class>com.study.ui.DivRenderer</renderer-class>
    </renderer>
</render-kit>

我还在文件中注册了一个新标签,如下所示:my.taglib.xml

<tag>
    <tag-name>div</tag-name>
    <component>
        <component-type>study.faces.Div</component-type>
        <renderer-type>study.faces.DivRenderer</renderer-type>
    </component>
</tag>

此配置非常有效。但是,我不明白为什么渲染器注册时需要该行。在 中,组件和渲染器是连接的,恕我直言,为组件选择合适的渲染器应该就足够了。附加参数有什么用?<component-family>javax.faces.Panel</component-family>my.taglib.xml<component-family>

我做了谷歌研究,我得到的所有答案都说:“一个渲染器可以用来渲染多个组件。这些组件属于一个系列”。但这些说法并没有消除我的困惑。有人可以解释组件类型,组件系列和渲染器选择策略之间的关系吗?(希望有一个很好的例子。


答案 1

渲染器是由组件系列选择的,而不是像您期望的那样由组件类型选择。

让我们引用 JSF 2.0 规范

3.1.2 组件类型

虽然不是 UIComponent 的属性,但组件类型是与每个子类相关的重要数据,它允许实例使用该类型创建子类的新实例。有关组件类型的更多信息,请参见第 7.1.11 节 “对象工厂”。UIComponentApplicationUIComponent

3.1.3 组件系列

每个标准用户界面组件类都有一个组件系列的标准值,该值用于查找与此组件关联的呈现器。泛型类的子类通常将从其超类继承此属性,因此只期望超类的呈现器仍然能够处理专用的子类。UIComponent

基本上,组件类型对于 JSF 是必需的,以便通过 Application#createComponent() 方法创建组件。

UIComponent component = context.getApplication().createComponent("study.faces.Div");

这样做的好处是,该组件不是编译时依赖项,因此提供了运行时多态性和可插拔性的可能性(如果您熟悉 JDBC 的 Class#forName() 机制及其工厂,那么您将更好地理解该部分)。study.faces.Div

每个元件类型都属于一个族,该族可以由一个或多个元件组成。渲染器是根据组件系列和渲染器类型由 RenderKit#getRenderer() 选择的

Renderer renderer = context.getRenderKit().getRenderer(component.getFamily(), component.getRendererType());

不会根据组件类型和渲染器类型选择渲染器。这允许对属于一个组件族的多个组件类型重用渲染器。否则,您需要为每个组件注册一个渲染器,即使这些组件可以共享同一个渲染器。

以下条目faces-config.xml

<component>
    <component-type>study.faces.Div</component-type>
    <component-class>javax.faces.component.UIPanel</component-class>
</component>

告诉 JSF,每当要创建给定组件类型的组件时,都应该创建给定组件类的实例。其中未指定组件系列,因为 中已经隐式知道。Applicationcomponent.getFamily()

以及以下条目faces-config.xml

<render-kit>
    <renderer>
        <component-family>javax.faces.Panel</component-family>
        <renderer-type>study.faces.DivRenderer</renderer-type>
        <renderer-class>com.study.ui.DivRenderer</renderer-class>
    </renderer>
</render-kit>

告诉 JSF,每当请求给定组件系列和渲染器类型的渲染器时,应返回给定渲染器类的实例。RenderKit

以下条目.taglib.xml

<tag>
    <tag-name>div</tag-name>
    <component>
        <component-type>study.faces.Div</component-type>
        <renderer-type>study.faces.DivRenderer</renderer-type>
    </component>
</tag>

告诉 JSF(好吧,Facelets),给定的标记应该在视图根目录中创建给定组件类型的组件(其类已在 中定义),并且其渲染器类型应设置为给定的渲染器类型。请注意,组件类型用于选择渲染器,而是用于在视图根目录中创建组件。另请注意,呈现器类型条目是可选的。否则,将使用组件自己的预定义渲染器类型。这允许使用不同的呈现器类型重用现有组件类型。faces-config.xml


答案 2

javadoc说:getFamily()

返回此元件所属元件族的标识符。此标识符与 rendererType 属性的值结合使用,可用于为此组件实例选择适当的 Renderer

维护者的基本原理在 JSF 规范中有所介绍:

组件系列

每个标准用户界面组件类都有一个组件系列的标准值,该值用于查找与此组件关联的呈现器。泛型 UIComponent 类的子类通常将从其超类继承此属性,因此只期望超类的呈现器仍能够处理专用子类。

我将其解释为为Java类类型之外的其他类型检查提供了一些功能(因为子类将始终是子类。我不确定这到底有多大用处。


推荐