组件的定义被分割的情况下,为了不让复数个组件的定义名称发生冲突,可以用components标签的namespace属性指定命名空间。
foo.dicon
<components namespace="foo">
<component name="aaa" .../>
<component name="bbb" ...>
<arg>aaa</arg>
</component>
</components>
bar.dicon
<components namespace="bar">
<include path="foo.dicon"/>
<component name="aaa" .../>
<component name="bbb" ...>
<arg>aaa</arg>
</component>
<component name="ccc" ...>
<arg>foo.aaa</arg>
</component>
</components>
app.dicon
<components>
<include path="bar.dicon"/>
</components>
在同一个组件定义文件中可以不需要指定命名空间而调用组件。调用其它S2Container文件中定义的组件时,要在组件名前加上命名空间。foo.aaa 和 bar.aaa 虽然有相同名称的组件,但是因为命名空间的不同,就被认为是不同的组件。
实例(instance)管理
在S2Container中,怎么样对实例进行管理,这个设定是用component标签的instance属性。
instance属性 说明
singleton(default) 不论S2Container.getComponent()被调用多少次都返回同一个实例。
prototype S2Container.getComponent()每次被调用的时候都返回一个新的实例。
request 对应每一个请求(request)做成一个实例。用name属性中指定的名称,组件被容纳在请求中。使用request的场合下需要设定S2ContainerFilter。
session 对应每一个session做成一个实例。用name属性中指定的名称,组件被容纳在session中。使用session的场合下需要设定S2ContainerFilter。
application 使用Servlet的场合下,对应每一个ServletContext做成一个实例。用name属性中指定的名称,组件被容纳在ServletContext中。使用application的场合下需要设定S2ContainerFilter。
outer 组件的实例在S2Container之外作成,从而仅仅行使Dependency Injection的功能。Aspect、构造函数注入不能适用。
生存周期
使用initMethod 和 destroyMethod组件的生存周期也可以用容器来管理。在S2Container的开始时用(S2Container.init())调用 initMethod标签中指定的方法,S2Container结束时用(S2Container.destroy())调用destroyMethod 标签中指定的方法。initMethod将按照容器中注册的组件的顺序来执行组件,destroyMethod则按照相反的顺序去执行。instance 属性是singleton之外的情况下,指定了destroyMethod也会被忽视。java.util.HashMap#put()方法中初始化(给 aaa赋值为111)?结束处理(给aaa赋值为null)的设定,向下面那样。
<components namespace="bar">
<component name="map" class="java.util.HashMap">
<initMethod name="put">
<arg>"aaa"</arg>
<arg>111</arg>
</initMethod>
<destroyMethod name="put">
<arg>"aaa"</arg>
<arg>null</arg>
</destroyMethod>
</component>
</components>
自动绑定
组件间的依存关系,类型是interface的场合时,将由容器来自动解决。这是在S2Container被默认的,指定component标签的autoBinding属性可以进行更加细致的控制。
autoBinding 说明
auto(default) 适用于构造函数和属性变量的自动绑定。
constructor 适用于构造函数的自动绑定。
property 适用于属性变量的自动绑定。
none 只能对构造函数、属性变量进行手动绑定。
构造函数的自动绑定规则如下所示。
明确指定了构造函数的参数的情况下,自动绑定将不再适用。
不属于上述情况,如果是定义了没有参数的默认的构造函数的话,对于这个构造函数,自动绑定也不适用。
不属于上述情况,参数的类型全是interface并且参数数目最多的构造函数将被使用。 这样,对于从容器中取得参数类型的实装组件,自动绑定是适用的。
如果不是以上情况,自动绑定将不适用。
属性变量的自动绑定规则如下。
明确指定了属性变量的情况下,自动绑定将不适用。
不属于上述情况,如果在容器的注册组件中存在着可以代入属性变量中的同名组件,自动绑定将适用于该组件。
不属于上述情况,属性变量的类型是interface并且该属性类型的实装组件在容器中注册了的话,自动绑定是适用的。
如果不是以上情况,自动绑定将不适用。
用property标签的bindingType属性,可以更加细致的控制属性变量。
bindingType 说明
must 自动绑定不适用的情况下?将会发生例外。
should(default) 自动绑定不适用的情况下,将发出警告通知。
may 自动绑定不适用的情况下,什么都不发生。
none autoBinding的属性虽然是auto、property情况下,自动绑定也不适用。
在组件中利用S2Container
不想让组件依存于S2Container的情况下,根据组件的具体情况,在组件中需要调用S2Container的方法,这样的场合也许会存在。 S2Container自身也以container的名称,自我注册了。所以可以在arg,property标签的正文中指定container,从而取 得容器的实例。还有,S2Container类型的setter方法定义好了后也可以做自动绑定的设定。用arg,property标签指定 container的情况下,向下面这样进行。
<components>
<component class="examples.dicon.BarImpl">
<arg>container</arg>
</component>
<component class="examples.dicon.FooImpl">
<property name="foo">container</property>
</component>
</components>
S2ContainerServlet
到此为止,在Java application中,是用明确表示的方法做成S2Container的,Web application的情况下,由谁来作成S2Container呢?为了达到这个目的,准备了以下的类。
org.seasar.framework.container.servlet#S2ContainerServlet
为了使用S2ContainerServlet,在web.xml中记述如下项目。
<servlet>
<servlet-name>s2servlet</servlet-name>
<servlet-class>org.seasar.framework.container.servlet.S2ContainerServlet</servlet-class>
<init-param>
<param-name>configPath</param-name>
<param-value>app.dicon</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>s2servlet</servlet-name>
<url-pattern>/s2servlet</url-pattern>
</servlet-mapping>
用configPath来指定作为根的S2Container的定义路径。定义文件将放在WEB-INF/classes中。对于 S2ContainerServlet,为了比其它的servlet更早的起动,请做load-on-startup标签的调整。 S2ContainerServlet起动之后,可以用如下的方法函数取得S2Container的实例。
org.seasar.framework.container.factory.SingletonS2ContainerFactory#getContainer()
另外,S2Container的生命周期和S2ContainerServlet是连动的。debug变量被设为true的话,按照以下的方法,可以将运行中的S2Container再次起动。xxx是Web application的context名。
http://localhost:8080/xxx/s2servlet?command=restart
在使用了S2ContainerServlet的情况下,ServletContext将会作为一个组件可以用servletContext的名字来访问。
app.dicon的角色
根的S2Container的定义文件,按照惯例用app.dicon的名称。通常放在WEB-INF/classes中就好了。
AOP的适用
在组件中AOP的适用情况也可以被设定。比如,想要在ArrayList中设定TraceInterceptor使用的情况下需要象下面这样做。
<components>
<component name="traceInterceptor"
class="org.seasar.framework.aop.interceptors.TraceInterceptor"/>
<component class="java.util.ArrayList">
<aspect>traceInterceptor</aspect>
</component>
<component class="java.util.Date">
<arg>0</arg>
<aspect pointcut="getTime, hashCode">traceInterceptor</aspect>
</component>
</components>
aspect标签的正文中指定Interceptor的名字。pointcut的属性中可以用逗号做分隔符指定AOP对象的方法的名字。 pointcut的属性没有被指定的情况下,组件将把实装的interface的所有方法函数作为AOP的对象。方法函数的名称指定也可以用正则表达式 (JDK1.4のregex)。这样的定义例子如下。
private static final String PATH =
"examples/dicon/Aop.dicon";
S2Container container = S2ContainerFactory.create(PATH);
List list = (List) container.getComponent(List.class);
list.size();
Date date = (Date) container.getComponent(Date.class);
date.getTime();
date.hashCode();
date.toString();
执行结果。
BEGIN java.util.ArrayList#size()
END java.util.ArrayList#size() : 0
BEGIN java.util.Date#getTime()
END java.util.Date#getTime() : 0
BEGIN java.util.Date#hashCode()
BEGIN java.util.Date#getTime()
END java.util.Date#getTime() : 0
END java.util.Date#hashCode() : 0
BEGIN java.util.Date#getTime()
END java.util.Date#getTime() : 0
组件中也可以设定InterType的适用情况。比如,在Hoge中设定PropertyInterType的适用情况如下进行。
<components>
<include path="aop.dicon"/>
<component class="examples.Hoge">
<interType>aop.propertyInterType</aspect>
</component>
</components>
在interType标签的正文中指定InterType的名称。
Meta数据
在components、component、arg、property标签中也可以指定Meta数据。meta标签将作为需要指定Meta数据的标签的字标签来指定Meta数据。例如,想要在components标签中指定Meta数据的情况时,象下面一样设定。
<components>
<meta name="aaa">111</meta>
</components>
request的自动绑定
对于组件来说,也可以进行HttpServletRequest的自动绑定。为了实现这个目的,在组件中,定义了 setRequest(HttpServletRequest request)方法。这样的话,S2Container就自动得设定了request。还有,需要象下面这样在web.xml中进行Filter的定 义。
<web-app>
<filter>
<filter-name>s2filter</filter-name>
<filter-class>org.seasar.framework.container.filter.S2ContainerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>s2filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
同样地对HttpServletResponse、HttpSession、ServletContext也是只要定义了setter方法,就可以 自动绑定了。而且,使用了S2ContainerFilter的话,HttpServletRequest、HttpServletResponse、 HttpSession、ServletContext就可以各自用request、response、session、application的名字来 做为组件被自由访问了。
组件的自动注册
根据自动绑定的原理,DI的设定几乎可以做近乎全部的自动化。 使用备注码就有可能进行更加细致的设定。 更进一步、对组件的注册也进行自动化的话,就可以称为组件的自动注册机能了。
org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister
是从文件系统中将类检索出来对组件进行自动注册的组件。
属性 说明
instanceDef 在自动注册的组件中指定适用的InstanceDef。用XML指定的场合下,
@org.seasar.framework.container.deployer.InstanceDefFactory@REQUEST
这样来指定。
autoBindingDef 在自动注册的组件中指定适用的AutoBindingDef。用XML指定的场合下,
@org.seasar.framework.container.assembler.AutoBindingDefFactory@NONE
这样来指定。
autoNaming 可以根据类名来自动决定组件名的组件。需要实装 org.seasar.framework.container.autoregister.AutoNaming interface。默认状态下,使用 org.seasar.framework.container.autoregister.DefaultAutoNaming类的实例。
方法 说明
addClassPattern 将想要自动注册的类模式注册。最开始的一个参数是组件所在包的名字。子包也能被以回归的方式进行检索。第二个参数是类的名字。可以使用正则表达式。也可以用“,”分隔做复数个设定。
addIgnoreClassPattern 将不想自动注册的类模式注册。最开始的一个参数是组件所在包的名字。子包也能被以回归的方式进行检索。第二个参数是类的名字。可以使用正则表达式。也可以用“,”分隔做复数个设定。
org.seasar.framework.container.autoregister.JarComponentAutoRegister
从Jar文件中检索类自动注册组件的组件。
属性 说明
jarFileNames 指定设定对象的jar文件名。可以使用正则表达式。但是能包含后缀。指定复数个对象的场合下,用“,”做分割符。例如,myapp.*, yourapp.*这样。
referenceClass 用这个属性指定的类所属的jar文件的父路径为基础路径(例如,WEB-INF/lib)。默认的是org.aopalliance.intercept.MethodInterceptor.class。
instanceDef 适用于自动注册的组件的InstanceDef的指定。在XML中如下,
@org.seasar.framework.container.deployer.InstanceDefFactory@REQUEST
这样指定。
autoBindingDef 适用于自动注册的组件的AutoBindingDef的指定。在XML中如下,
@org.seasar.framework.container.assembler.AutoBindingDefFactory@NONE
这样指定。
autoNaming 根据类名自动决定组件的名称的组件。需要对 org.seasar.framework.container.autoregister.AutoNaming interface 进行实装。默认的情况下是 org.seasar.framework.container.autoregister.DefaultAutoNaming类的实例。
方法 说明
addClassPattern 将想要自动注册的类模式注册。最开始的一个参数是组件所在包的名字。子包也能被以回归的方式进行检索。第二个参数是类的名字。可以使用正则表达式。也可以用“,”分隔做复数个设定。
addIgnoreClassPattern 将不想自动注册的类模式注册。最开始的一个参数是组件所在包的名字。子包也能被以回归的方式进行检索。第二个参数是类的名字。可以使用正则表达式。也可以用“,”分隔做复数个设定。
org.seasar.framework.container.autoregister.ComponentAutoRegister
将类从文件系统或者Jar文件中检索出来并将组件自动注册的组件。
属性 说明
instanceDef 适用于自动注册的组件的InstanceDef的指定。在XML中如下,@org.seasar.framework.container.deployer.InstanceDefFactory@REQUEST这样指定。
autoBindingDef 适用于自动注册的组件的AutoBindingDef的指定。在XML中如下,
@org.seasar.framework.container.assembler.AutoBindingDefFactory@NONE
这样指定。
autoNaming 从类的名称来自动决定组件的名称的组件。需要对 org.seasar.framework.container.autoregister.AutoNaming instance进行实装。默认的是 org.seasar.framework.container.autoregister.DefaultAutoNaming类的实例。
方法 说明
addReferenceClass 以这个方法所指定的类所存在的路径或者Jar文件为基点对类进行检索。
addClassPattern 将想要自动注册的类模式注册。最开始的一个参数是组件所在包的名字。子包也能被以回归的方式进行检索。第二个参数是类的名字。可以使用正则表达式。也可以用“,”分隔做复数个设定。
addIgnoreClassPattern 将不想 自动注册的类模式注册。最开始的一个参数是组件所在包的名字。子包也能被以回归的方式进行检索。第二个参数是类的名字。可以使用正则表达式。也可以用“,”分隔做复数个设定。
AutoNaming
根据AutoNaming来控制组件名称。
org.seasar.framework.container.autoregister.DefaultAutoNaming
从类的完整合法名称中将类的包的那部分名称去掉,如果结尾是Impl或者Bean也要去掉,之后将开头的字母变成小写做为组件名称来设定。 例如,aaa.HogeImpl类的情况下,组件的名称就成了hoge。
属性 说明
decapitalize 组件名的开头字母为小写的情况下指定为true。默认值是true。
方法 说明
setCustomizedName 不依从于默认的规则对类进行注册。第一个参数是类的完整合法名。第二个参数是组件的名称。
addIgnoreClassSuffix 指定从类名的尾端消除的部分。注册默认值为Impl以及Bean。
addReplaceRule 根据正则表达式追加替换规则。第一个参数为正则表达式。第二个参数为向要替换的字符串。
clearReplaceRule 用setCustomizedName、addIgnoreClassSuffix、addReplaceRule将注册的变换规则清零。作为默认值被注册的Impl和Bean也被清零。
org.seasar.framework.container.autoregister.QualifiedAutoNaming
将包的名字或者是一部分类的合法名做为组件名称的设定。从类的完整合法名的最后把Impl或者Bean去掉,开头字母小写,分隔点后紧接着的字母变成大写并取掉分隔点,将这个新的单词设定为组件的名称。
可以将包的开头的不要的部分做消除指定。
例如,aaa.bbb.ccc.ddd.HogeImpl类的情况下,将开头的aaa.bbb做消除指定的情况下组件的名称为,cccDddHogeになります。
属性 说明
decapitalize 组件名的开头字母为小写的情况下指定为true。默认值是true。
方法 说明
setCustomizedName 遵从默认的规则来注册类。第一个参数是类的完整合法名。 第二个参数是组件的名称。
addIgnorePackagePrefix 从包名称的开头开始指定消除的部分。
addIgnoreClassSuffix 类名称的最末尾开始指定消除的部分。默认地将Impl和Bean注册。
addReplaceRule 根据正则表达式追加替换规则。第一个参数为正则表达式。第二个参数是替换的新字符串。
clearReplaceRule 将setCustomizedName、 addIgnorePackagePrefix、 addIgnoreClassSuffix、 addReplaceRule注册的替换规则清除。默认注册的Impl以及Bean也将被清除。
例
<component
class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
<property name="autoNaming">
<component class="org.seasar.framework.container.autoregister.DefaultAutoNaming">
<initMethod name="setCustomizedName">
<arg>"examples.di.impl.HogeImpl"</arg>
<arg>"hoge2"</arg>
</initMethod>
</component>
</property>
<initMethod name="addClassPattern">
<arg>"examples.di.impl"</arg>
<arg>".*Impl"</arg>
</initMethod>
</component>
<component class="org.seasar.framework.container.autoregister.JarComponentAutoRegister">
<property name="referenceClass">
@junit.framework.TestSuite@class
</property>
<property name="jarFileNames">"junit.*"</property>
<initMethod name="addClassPattern">
<arg>"junit.framework"</arg>
<arg>"TestSuite"</arg>
</initMethod>
</component>
<component class="org.seasar.framework.container.autoregister.ComponentAutoRegister">
<initMethod name="addReferenceClass">
<arg>@aaa.bbb.ccc.ddd.HogeImpl@class</arg>
</initMethod>
<initMethod name="addClassPattern">
<arg>"aaa.bbb"</arg>
<arg>".*Impl"</arg>
</initMethod>
</component>
AOP的自动注册
根据组件的自动注册规则,组件的注册可以做到自动化。进一步,AOP的注册也可以做到自动化,这就是AOP的自动注册机能。
和组件的自动注册功能组和使用的场合下,必须在组件的自动注册设定之后,作AOP的自动注册的设定。对于适用于使用AOP的组件的记述,必须在AOP的自动注册设定之后进行。
<components>
<!-- 1.组件的自动注册 -->
<component class="org.seasar.framework.container.autoregister.ComponentAutoRegister">
...
</component>
<!-- 2.AOP的自动注册 -->
<component class="org.seasar.framework.container.autoregister.AspectAutoRegister">
...
</component>
<!-- 3.其它的组件 -->
<component class="...">
...
</component>
...
<components>
org.seasar.framework.container.autoregister.AspectAutoRegister
通过指定类名的模式来进行AOP的自动注册的组件。
属性 说明
interceptor 指定interceptor。想要指定复数个interceptor的场合下,请使用InterceptorChain。
pointcut 适于使用interceptor的方法用逗号分隔开进行指定。不指定pointcut的情况下,实装组件的interface的所有方法都做为interceptor的对象。对于方法名称也可以使用正则表达式(JDK1.4のregex)来指定。
方法 说明
addClassPattern 将想要自动注册的类的模式注册。第一个参数是组件的包的名。子包也可以用回归的方法检索。第二个参数是类名。可以使用正则表达式。用“,”分隔可以做复数个记述。
addIgnoreClassPattern 将不想自动注册的类模式注册。第一个参数是组件的包的名。子包也可以用回归的方法检索。第二个参数是类名。可以使用正则表达式。用“,”分隔可以做复数个记述。
例
<include path="aop.dicon"/>
...
<component
class="org.seasar.framework.container.autoregister.AspectAutoRegister">
<property name="interceptor">aop.traceInterceptor</property>
<initMethod name="addClassPattern">
<arg>"examples.di.impl"</arg>
<arg>".*Impl"</arg>
</initMethod>
</component>
org.seasar.framework.container.autoregister.InterfaceAspectAutoRegister
针对某个interface的实装类进行AOP的自动注册的组件。
属性 说明
interceptor 指定interceptor。想要指定复数个interceptor的场合下,请使用InterceptorChain。
targetInterface 针对某一指定的interface的实装组件,使用AOP。
例
<include path="aop.dicon"/>
...
<component
class="org.seasar.framework.container.autoregister.InterfaceAspectAutoRegister">
<property name="interceptor">aop.traceInterceptor</property>
<property name="targetInterface">@examples.Greeing@class</property>
</component>
META的自动注册
META信息也可以自动注册。
同组件的自动注册相组合使用的场合下,必须在组件的自动注册设定之后,做META的自动注册的设定记述。 调用META信息的组件必须在META自动注册的设定之后记述。
<components>
<!-- 1.组件的自动注册 -->
<component class="org.seasar.framework.container.autoregister.ComponentAutoRegister">
...
</component>
<!-- 2.META的自动注册 -->
<component class="org.seasar.framework.container.autoregister.MetaAutoRegister">
...
</component>
<!-- 3.其它的组件 -->
<component class="...">
...
</component>
...
<components>
org.seasar.framework.container.autoregister.MetaAutoRegister
通过指定类名的模式来做META自动注册的组件。
被自动注册的META数据,将做为在这个组件自身的定义中一个叫做autoRegister的META数据的子数据来记述。
方法 说明
addClassPattern 将想要自动注册的类模式注册。第一个参数是组件所在包的名字。子包也将被用回归的方式所检索。第二个参数是类名。可以使用正则表达式。用“,”做分隔符号,可以做复数个记述。
addIgnoreClassPattern 将不想自动注册的类模式注册。第一个参数是组件所在包的名字。子包也将被用回归的方式所检索。第二个参数是类名。可以使用正则表达式。用“,”做分隔符号,可以做复数个记述。
例
<component
class="org.seasar.framework.container.autoregister.MetaAutoRegister">
<meta name="autoRegister">
<meta name="hoge"</meta>
</meta>
<initMethod name="addClassPattern">
<arg>"examples.di.impl"</arg>
<arg>".*Impl"</arg>
</initMethod>
</component>
本例中、叫做hoge的META数据自动地注册到其它的组件定义中。
Hotswap
一直以来,更改了源代码并重新编译之后的场合,想要测试编译后的机能,必须让应用程序(确切地说是ClassLoader)再起动。在应用程序服务器上,进行程序再起动将非常花时间。 “真烦人”这样想的人很多不是吗。
在Seasar2中,应用程序在运行中,即使类文件替换了,也可以即刻测试的Hotswap机能得以实现。这样就让我们从那种“心情烦躁”中解放出来了。无须花费多余的时间使得出产率得以提高。这样的好东西,不想试一试吗?
Greeting.java
package examples.hotswap;
public interface Greeting {
String greet();
}
GreetingImpl.java
package examples.hotswap.impl;
import examples.hotswap.Greeting;
public class GreetingImpl implements Greeting {
public String greet() {
return "Hello";
}
}
hotswap.dicon
<components>
<component class="examples.hotswap.impl.GreetingImpl"/>
</components>
到此为止,并没有什么特别的变化。关键点从此开始。 使用s2container.dicon,切换成hotswap模式。
s2container.dicon
<components>
<component
class="org.seasar.framework.container.factory.S2ContainerFactory$DefaultProvider">
<property name="hotswapMode">true</property>
</component>
</components>
把s2container.dicon根据class path放到根路径下的话,就能被自动识别到。也可以使用S2ContainerFactory#configure()明确地指定。
GreetingMain.dicon
package examples.hotswap.main;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
import examples.hotswap.Greeting;
public class GreetingMain {
private static final String CONFIGURE_PATH =
"examples/hotswap/dicon/s2container.dicon";
private static final String PATH =
"examples/hotswap/dicon/hotswap.dicon";
public static void main(String[] args) throws Exception {
S2ContainerFactory.configure(CONFIGURE_PATH);
S2Container container = S2ContainerFactory.create(PATH);
System.out.println("hotswapMode:" + container.isHotswapMode());
container.init();
try {
Greeting greeting = (Greeting) container
.getComponent(Greeting.class);
System.out.println(greeting.greet());
System.out.println("Let's modify GreetingImpl, then press ENTER.");
System.in.read();
System.out.println("after modify");
System.out.println(greeting.greet());
} finally {
container.destroy();
}
}
}
为了使用hotswap,有必要调用S2Container#init()。 执行了的话"Hello"表示出来后,程序就停止了,所以将GreetingImpl#greet()修改并编译使之表示"Hello2"。这之后,请将 文字终端显示窗口调成聚焦状态并按下ENTER键。虽然是用同一个instance也没有关系,class文件被替换了的事实可以很容易的被测知。这个是 实例模式为singleton的场合下的例子,实例模式为prototype的场合下,类将在调用S2Container#getComponent() 的时刻被置换。
执行结果
hotswapMode:true
Hello
Let's modify GreetingImpl, then press ENTER.
after modify
Hello2
为了使用hotswap,组件提供了interface,组件的利用者方面,必须通过interface来利用组件。 实例模式为request、session的情况下,对于一个组件不能被其它的组件调用的场合来说,没有interface也可以利用hotswap。
S2Container标签参考
DOCTYPE
DOCTYPE要在XML声明之后指定。请象下面那样指定。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
"http://www.seasar.org/dtd/components23.dtd">
<components>
<component name="hello" class="examples.dicon.HelloConstructorInjection">
<arg>"Hello World!"</arg>
</component>
</components>
components标签(必须)
成为了根标签。
namespace属性(任意)
可以指定命名空间。做为Java的标识语来使用
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN"
"http://www.seasar.org/dtd/components23.dtd">
<components namespace="hoge">
...
</components>
include标签(任意)