- 浏览: 8067 次
最新评论
公司的系统采用Seasar框架。Seasar是一套日本人开发的类似Spring的开源web框架。关于Seasar的中文教程比较少,只有日文和英文的(http://www.seasar.org/en/)。这几天研究了一下seasar的代码,做点记录怕以后忘记了。也希望能对路人朋友有点帮助。
(注:建议在阅读本文前先去阅读下官方提供的文档http://s2container.seasar.org/2.4/en/DIContainer.html)
察看Seasar web项目下的web.xml。默认的servlet是TeedaServlet。 TeedaServelet实际上是继承S2containerServlet。在初始化servlet的过程中,调用了S2containerServlet的init函数,其中采用策略模式,调用了策略类SingletonS2ContainerInitializer的initialize()函数。该函数内实现了对 app.dicon文件中所有包含的component的初始化和注入工作。
(注:如果不理解component和dicon的概念,请先浏览官方文档再继续阅读)
SingletonS2ContainerInitializer:initialize函数如下:
configPath的值就是"app.dicon",是在web.xml中定义的。代码的第一句话就是设定ConfigPath。关于第二句,需要先理解以下概念:
S2Container类:就是Seasar容器类,用来管理dicon文件生成的对象。在官方文档中的示例代码中关于普通JAVA项目如何使用seasar,有:
可以看到调用S2container类getComponent函数即可获得容器中生成的GreetingClient类对象。
值得注意的是,每一个dicon文件都会有自己的container实例来管理。如果dicon文件中include其他dicon, 则可以通过调用getChild()来获得子dicon的container实例。
S2containerFactory类:工厂模式,负责生成s2container。
S2ComponentDef类,封装了dicon中的<Component>标签声明的component,S2Container.getComponent函数实际上就是调用S2ComponentDef的getComponent函数来返回真正的对象(如上例中的GreetingClient对象)。
S2ContainerBehavior类:工厂模式用来生成S2ComponentDef类实例。
ComponentDeployer类:每一个ComponentDef实例中都有一个ComponentDeployer,它的作用是真正的去生成指定的类对象(如上例中的GreetingClient类型,该实例是通过Deployer通过反射生成的)。
ComponentDeployerFactory类:工厂模式用来生成ComponentDeployer对象。
Assember类:主要包括ConstructorAssember, PropertyAssembler和MethodAssembler。每个componentDeployer都包括如下assembler
在componentDeployer生成类对象过程中,通过策略模式委托assembler完成相应的生成工作。AssemblerFactory类:工厂模式用来生成assembler实例。
Provider类:seasar代码中每一个XXXFactory类都包含一个provider对象,Provider是策略类,用来执行真正的XXX类对象的生成。注意不同的factory之间的provider虽然都叫做"provider",但彼此间并没有联系,都是因为策略模式而分离出来专门用于“生成对象”的。
HotdeployBehavior类:这个命名很容易根S2ContainerBehavior类混淆,其实它是一个用于S2ContainerBehavior的Provider的子类,执行的也是Provider的功能。
回到initialize()函数上来。第二句要给ComponentDeployerFactory中的provider赋值为ExternalComponentDeployerProvider,是因为seasar的web项目和seasar的普通Java项目不同,普通Java项目中component只需要支持PROTOTYPE,SINGLETON两种实例类型,而web还需要支持APPLICATION,SESSION,REQUEST等实例类型,所以要使用ExternalComponentDeployerProvider。
接下来最核心的代码是最后一句SingletonS2ContainerFactory.init()。
container = S2ContainerFactory.create(configPath)用来生成app.dicon的s2container容器并把dicon文件中的component注册到容器中,然后container.init()执行dicon文件中component的生成。
首先是create函数中:
调用了configure()函数(其实在S2containerFactory类载入时运行的static代码段就调用了 ):
这里的configFile是"s2container.dicon"。这个dicon文件及其子dicon文件里声明的组件都是用来为app.dicon中的组件服务的,主要是提供一些AOP的设定。(关于Seasar的AOP,请查阅官方文档http://s2container.seasar.org/2.4/en/aop.html)
在进行下一步之前,先来查看一下s2container.dicon的结构。s2container.dicon是Seasar web项目默认提供的。其内容如下:
在实际运行中,是调用hotdeploy.dicon文件,这个dicon隐藏在s2-framework-XX.jar中。内容如下:
这四行存在依次依赖关系。熟悉seasar注入机制的就知道,这意味着每一个component的生成都会注入之前所依赖的component。在hotdeploy.dicon声明的组件是对以后用户自定义的app.dicon中的component作一些设定,主要是AOP的设定。比如以后用户自己定义的Page类,就会对Page类中的do*, initialize, prerender函数添加j2ee.requireTx的transaction AOP。(关于j2ee.requireTx及更多的Seasar transaction机制,请查阅官方文档http://s2container.seasar.org/2.4/en/tx.html)
回到configure(configureFile)函数:
这个函数就是负责s2container.dicon文件的container的生成和初始化。builder.build(configFile)用来解析dicon文件(本质上是xml),将其中的<include>标签封装为子container,将其中<component>标签之间的内容封装为ComponentDef实例,并注册进该container中(在这里就是 configurationContainer)。然后comfigurationContainer.init()函数的作用实际上和之前的container.init()函数是差不多的。只不过这个是s2container.dicon的容器初始化,而后者是app.dicon容器的初始化。该init()函数核心代码片断如下:
首先是递归地调用子container的init函数(每个container对应一个include的子dicon) ,其次是对本dicon中注册的component进行实例生成。在第二步 getComponentDef(i).init()的代码如下:
其中getConreteClass函数是把AOP的行为封装在要生成的实际类对象(例如GreetingClient对象)的相关函数上(在dicon中AOP绑定的函数)。而getComponentDeployer().init()则是采用策略模式(前文已经介绍)由componentDef中的componentDeployer来实现实际类对象的生成,其中依次调用它的构造函数、属性(如果属性是私有则调用setter)注入和@initMethod函数的调用。
多说一句,在对dicon文件解析的build过程中,根据每个component定义的 "instance"来定义相应componentDef的componentDeployer(如instance=singleton则componentDeployer=new SingletonComponentDeployer() )。
重新回到S2ContainerFactory的init函数。configurationContainer.init()之后,又设定了一个DefaultConfigurator,并运行configurator.configure(configurationFactory)。代码如下:
这里是为下一步app.dicon的container容器初始化作准备工作。将S2ContainerBehavior(这个类的功能类似于ComponentDefFactory)、ComponentDeployerFactory和AssemblerFactory的provider设定好。事实上在实际过程中,只有S2ContainerBehavior的provider设定为org.seasar.framework.container.hotdeploy.HotdeployBehavior。这个HotdeployBehavior实例是在s2container.dicon下的子dicon文件hotdeploy.dicon中定义的(此时s2container.dicon相关的组件已经初始化完成)。其余两个provider仍是默认提供的provider。
configurationContainer容器初始化完成以后,跳回S2ContainerFactory的create函数,执行最后一句 return getProvider().create(path)。这个是初始化app.dicon的container,相关代码如下:
初始化过程和configurationContainer的初始化过程是一样的。都是先解析文件(build函数)然后初始化(init函数),不过在实际运行中,init并不在这一步进行。
回到SingletonS2Factory的init函数。app.dicon的container的init函数是在这里调用。这样就完成了应用程序容器的初始化。
而在之后的web交互中,每一个request都会被过滤器HotdeployFilter和S2containerFilter拦截(感觉也没有做什么实际性的过滤工作,读者可自行研究)。
对组件的调用也是通过container.getComponent函数完成的。相关代码如下:
进入S2ContainerBehavior.acquireFromGetComponent(this,
componentKey),代码如下:
注意此时的provider是HotdeployBehavior类型。这里的aquireFromGetComponent函数会调用HotdeployBehavior的getComponentDef函数,完成获取ComponentDef的工作,。在HotdeployBehavior的acquireFromGetComponent函数中,就会把在前文中介绍的hotdeploy.dicon中声明的AOP设定添加进componentDef中。
多说一句,所谓HotDeploy,实际上他的本意是类的实例不是以<component>在app.dicon声明,而是预先设置好相应的AOP(这一部分是在customer.dicon中定义)和Creator(这一部分是在creator.dicon定义)。然后通过将一个HotdeployBehavior实例赋值到S2ContainerBehavior的一个静态成员变量,通过这个静态变量的穿针引线,在需要调用container.getComponent (XXClass)函数的时候利用这个HotdeployBehavior察看是否XXClass是否符合一定的命名规则(主要是看类的路径是否有相应的creator处理以及类的名字后缀是否合法,比如jp.co.worksap.cim.service这个路径下的类就归ServiceCreator生成,而该目录下RunSericeImpl是合法命名,RunServiceImpl1就不是合法命名,具体规则可察看ServiceCreator的定义),如果一切符合则生成实例。这样实际上在app.dicon中并没有定义该类的<component>却可以最终生成该类的实例,这就是HotDeploy。
这里可能有人会有疑问,如果我在app.dicon或者其子dicon下定义了某个component,而又符合Creator可以自动构造的命名规则的话,究竟是这个component的ComponentDef是谁来生成呢?查看HotdeployBehavior类的getCompoonentDef类,如下:
重点看第一行,进入这个函数,有
再进入S2ContainerImpl的internalGetComponentDef函数, 有
这里有个Map叫做componentDefMap, 在解析app.dicon及其子dicon的xml的时候就会将新生成的componentDef添加到这个Map。所以说如果你在app.dicon中自己定义了component,那么seasar会优先取你自己的定义的这个component,而不再用creator来生成。
返回到container.getComponent函数中。在真实的Seasar项目运行过程中,一般首先会调用getComponent(XXPage.class)获得某个相关html的后台Page类。由之前的代码可以知道,我们首先获得XXPage的相关的ComponentDef,然后调用cd.getComponent()获得XXPage的实例。在cd.getComponent()中调用deploy()函数完成Page实例的生成。而deploy()中又分别调用ConstructorAssembler, PropertyAssembler,InitMethodAssmebler等(根据不同的instance决定,比如Prototype和Singleton在生成时就有差异)完成对构造函数的调用,对类的内部属性的自动注入以及initMethod的调用。在对类的内部属性的自动注入中,就把后台的什么Service,Logic,Dao等等也会一层一层迭代地调用container.getComponent(XXClass)。所以说实际上,只需要container.getComponent(XXPageClass),根据自动注入,就可以把所有的类都实例化了。
(注:建议在阅读本文前先去阅读下官方提供的文档http://s2container.seasar.org/2.4/en/DIContainer.html)
察看Seasar web项目下的web.xml。默认的servlet是TeedaServlet。 TeedaServelet实际上是继承S2containerServlet。在初始化servlet的过程中,调用了S2containerServlet的init函数,其中采用策略模式,调用了策略类SingletonS2ContainerInitializer的initialize()函数。该函数内实现了对 app.dicon文件中所有包含的component的初始化和注入工作。
(注:如果不理解component和dicon的概念,请先浏览官方文档再继续阅读)
SingletonS2ContainerInitializer:initialize函数如下:
if (!StringUtil.isEmpty(configPath)) { SingletonS2ContainerFactory.setConfigPath(configPath); } if (ComponentDeployerFactory.getProvider() instanceof ComponentDeployerFactory.DefaultProvider) { ComponentDeployerFactory .setProvider(new ExternalComponentDeployerProvider()); } HttpServletExternalContext extCtx = new HttpServletExternalContext(); extCtx.setApplication(application); SingletonS2ContainerFactory.setExternalContext(extCtx); SingletonS2ContainerFactory .setExternalContextComponentDefRegister(new HttpServletExternalContextComponentDefRegister()); SingletonS2ContainerFactory.init();
configPath的值就是"app.dicon",是在web.xml中定义的。代码的第一句话就是设定ConfigPath。关于第二句,需要先理解以下概念:
引用
public class GreetingMain2 {
private static final String PATH =
"examples/di/dicon/GreetingMain2.dicon";
public static void main(String[] args) {
S2Container container =
S2ContainerFactory.create(PATH);
GreetingClient greetingClient = (GreetingClient)
container.getComponent("greetingClient");
greetingClient.execute();
}
}
private static final String PATH =
"examples/di/dicon/GreetingMain2.dicon";
public static void main(String[] args) {
S2Container container =
S2ContainerFactory.create(PATH);
GreetingClient greetingClient = (GreetingClient)
container.getComponent("greetingClient");
greetingClient.execute();
}
}
可以看到调用S2container类getComponent函数即可获得容器中生成的GreetingClient类对象。
值得注意的是,每一个dicon文件都会有自己的container实例来管理。如果dicon文件中include其他dicon, 则可以通过调用getChild()来获得子dicon的container实例。
... private ConstructorAssembler constructorAssembler; private PropertyAssembler propertyAssembler; private MethodAssembler initMethodAssembler; private MethodAssembler destroyMethodAssembler; ...
在componentDeployer生成类对象过程中,通过策略模式委托assembler完成相应的生成工作。
回到initialize()函数上来。第二句要给ComponentDeployerFactory中的provider赋值为ExternalComponentDeployerProvider,是因为seasar的web项目和seasar的普通Java项目不同,普通Java项目中component只需要支持PROTOTYPE,SINGLETON两种实例类型,而web还需要支持APPLICATION,SESSION,REQUEST等实例类型,所以要使用ExternalComponentDeployerProvider。
接下来最核心的代码是最后一句SingletonS2ContainerFactory.init()。
container = S2ContainerFactory.create(configPath); if (container.getExternalContext() == null) { if (externalContext != null) { container.setExternalContext(externalContext); } } else if (container.getExternalContext().getApplication() == null && externalContext != null) { container.getExternalContext().setApplication( externalContext.getApplication()); } if (container.getExternalContextComponentDefRegister() == null && externalContextComponentDefRegister != null) { container .setExternalContextComponentDefRegister(externalContextComponentDefRegister); } container.init();
container = S2ContainerFactory.create(configPath)用来生成app.dicon的s2container容器并把dicon文件中的component注册到容器中,然后container.init()执行dicon文件中component的生成。
首先是create函数中:
public static synchronized S2Container create(final String path) { if (StringUtil.isEmpty(path)) { throw new EmptyRuntimeException("path"); } if (!initialized) { configure(); } return getProvider().create(path); }
调用了configure()函数(其实在S2containerFactory类载入时运行的static代码段就调用了 ):
public static void configure() { final String configFile = System.getProperty(FACTORY_CONFIG_KEY, FACTORY_CONFIG_PATH); configure(configFile); }
这里的configFile是"s2container.dicon"。这个dicon文件及其子dicon文件里声明的组件都是用来为app.dicon中的组件服务的,主要是提供一些AOP的设定。(关于Seasar的AOP,请查阅官方文档http://s2container.seasar.org/2.4/en/aop.html)
在进行下一步之前,先来查看一下s2container.dicon的结构。s2container.dicon是Seasar web项目默认提供的。其内容如下:
引用
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
<include condition="#ENV == 'ut'" path="warmdeploy.dicon"/>
<include condition="#ENV == 'ct'" path="hotdeploy.dicon"/>
<include condition="#ENV != 'ut' and #ENV != 'ct'" path="cooldeploy.dicon"/>
</components>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
<include condition="#ENV == 'ut'" path="warmdeploy.dicon"/>
<include condition="#ENV == 'ct'" path="hotdeploy.dicon"/>
<include condition="#ENV != 'ut' and #ENV != 'ct'" path="cooldeploy.dicon"/>
</components>
在实际运行中,是调用hotdeploy.dicon文件,这个dicon隐藏在s2-framework-XX.jar中。内容如下:
引用
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
<include path="convention.dicon"/>
<include path="customizer.dicon"/>
<include path="creator.dicon"/>
<component class="org.seasar.framework.container.hotdeploy.HotdeployBehavior"/>
</components>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
<include path="convention.dicon"/>
<include path="customizer.dicon"/>
<include path="creator.dicon"/>
<component class="org.seasar.framework.container.hotdeploy.HotdeployBehavior"/>
</components>
这四行存在依次依赖关系。熟悉seasar注入机制的就知道,这意味着每一个component的生成都会注入之前所依赖的component。在hotdeploy.dicon声明的组件是对以后用户自定义的app.dicon中的component作一些设定,主要是AOP的设定。比如以后用户自己定义的Page类,就会对Page类中的do*, initialize, prerender函数添加j2ee.requireTx的transaction AOP。(关于j2ee.requireTx及更多的Seasar transaction机制,请查阅官方文档http://s2container.seasar.org/2.4/en/tx.html)
回到configure(configureFile)函数:
public static synchronized void configure(final String configFile) { if (configuring) { return; } configuring = true; if (provider == null) { provider = new DefaultProvider(); } if (defaultBuilder == null) { defaultBuilder = new XmlS2ContainerBuilder(); } if (ResourceUtil.isExist(configFile)) { final S2ContainerBuilder builder = new XmlS2ContainerBuilder(); configurationContainer = builder.build(configFile); configurationContainer.init(); Configurator configurator; if (configurationContainer.hasComponentDef(Configurator.class)) { configurator = (Configurator) configurationContainer .getComponent(Configurator.class); } else { configurator = new DefaultConfigurator(); } configurator.configure(configurationContainer); } DisposableUtil.add(new Disposable() { public void dispose() { S2ContainerFactory.destroy(); } }); configuring = false; initialized = true; }
这个函数就是负责s2container.dicon文件的container的生成和初始化。builder.build(configFile)用来解析dicon文件(本质上是xml),将其中的<include>标签封装为子container,将其中<component>标签之间的内容封装为ComponentDef实例,并注册进该container中(在这里就是 configurationContainer)。然后comfigurationContainer.init()函数的作用实际上和之前的container.init()函数是差不多的。只不过这个是s2container.dicon的容器初始化,而后者是app.dicon容器的初始化。该init()函数核心代码片断如下:
for (int i = 0; i < getChildSize(); ++i) { getChild(i).init(); } for (int i = 0; i < getComponentDefSize(); ++i) { getComponentDef(i).init(); }
首先是递归地调用子container的init函数(每个container对应一个include的子dicon) ,其次是对本dicon中注册的component进行实例生成。在第二步 getComponentDef(i).init()的代码如下:
public void init() { getConcreteClass(); getComponentDeployer().init(); }
其中getConreteClass函数是把AOP的行为封装在要生成的实际类对象(例如GreetingClient对象)的相关函数上(在dicon中AOP绑定的函数)。而getComponentDeployer().init()则是采用策略模式(前文已经介绍)由componentDef中的componentDeployer来实现实际类对象的生成,其中依次调用它的构造函数、属性(如果属性是私有则调用setter)注入和@initMethod函数的调用。
多说一句,在对dicon文件解析的build过程中,根据每个component定义的 "instance"来定义相应componentDef的componentDeployer(如instance=singleton则componentDeployer=new SingletonComponentDeployer() )。
重新回到S2ContainerFactory的init函数。configurationContainer.init()之后,又设定了一个DefaultConfigurator,并运行configurator.configure(configurationFactory)。代码如下:
public void configure(final S2Container configurationContainer) { provider = createProvider(configurationContainer); defaultBuilder = createDefaultBuilder(configurationContainer); setupBehavior(configurationContainer); setupDeployer(configurationContainer); setupAssembler(configurationContainer); }
这里是为下一步app.dicon的container容器初始化作准备工作。将S2ContainerBehavior(这个类的功能类似于ComponentDefFactory)、ComponentDeployerFactory和AssemblerFactory的provider设定好。事实上在实际过程中,只有S2ContainerBehavior的provider设定为org.seasar.framework.container.hotdeploy.HotdeployBehavior。这个HotdeployBehavior实例是在s2container.dicon下的子dicon文件hotdeploy.dicon中定义的(此时s2container.dicon相关的组件已经初始化完成)。其余两个provider仍是默认提供的provider。
configurationContainer容器初始化完成以后,跳回S2ContainerFactory的create函数,执行最后一句 return getProvider().create(path)。这个是初始化app.dicon的container,相关代码如下:
public S2Container create(final String path) { ClassLoader classLoader; if (configurationContainer != null && configurationContainer .hasComponentDef(ClassLoader.class)) { classLoader = (ClassLoader) configurationContainer .getComponent(ClassLoader.class); } else { classLoader = Thread.currentThread().getContextClassLoader(); } S2Container container = StringUtil.isEmpty(path) ? new S2ContainerImpl() : build(path, classLoader); if (container.isInitializeOnCreate()) { container.init(); } return container; }
初始化过程和configurationContainer的初始化过程是一样的。都是先解析文件(build函数)然后初始化(init函数),不过在实际运行中,init并不在这一步进行。
回到SingletonS2Factory的init函数。app.dicon的container的init函数是在这里调用。这样就完成了应用程序容器的初始化。
而在之后的web交互中,每一个request都会被过滤器HotdeployFilter和S2containerFilter拦截(感觉也没有做什么实际性的过滤工作,读者可自行研究)。
对组件的调用也是通过container.getComponent函数完成的。相关代码如下:
public Object getComponent(Object componentKey) { assertParameterIsNotNull(componentKey, "componentKey"); ComponentDef cd = S2ContainerBehavior.acquireFromGetComponent(this, componentKey); if (cd == null) { return null; } return cd.getComponent(); }
进入S2ContainerBehavior.acquireFromGetComponent(this,
componentKey),代码如下:
public static ComponentDef acquireFromGetComponent(S2Container container, final Object key) { return getProvider().acquireFromGetComponent(container, key); }
注意此时的provider是HotdeployBehavior类型。这里的aquireFromGetComponent函数会调用HotdeployBehavior的getComponentDef函数,完成获取ComponentDef的工作,。在HotdeployBehavior的acquireFromGetComponent函数中,就会把在前文中介绍的hotdeploy.dicon中声明的AOP设定添加进componentDef中。
多说一句,所谓HotDeploy,实际上他的本意是类的实例不是以<component>在app.dicon声明,而是预先设置好相应的AOP(这一部分是在customer.dicon中定义)和Creator(这一部分是在creator.dicon定义)。然后通过将一个HotdeployBehavior实例赋值到S2ContainerBehavior的一个静态成员变量,通过这个静态变量的穿针引线,在需要调用container.getComponent (XXClass)函数的时候利用这个HotdeployBehavior察看是否XXClass是否符合一定的命名规则(主要是看类的路径是否有相应的creator处理以及类的名字后缀是否合法,比如jp.co.worksap.cim.service这个路径下的类就归ServiceCreator生成,而该目录下RunSericeImpl是合法命名,RunServiceImpl1就不是合法命名,具体规则可察看ServiceCreator的定义),如果一切符合则生成实例。这样实际上在app.dicon中并没有定义该类的<component>却可以最终生成该类的实例,这就是HotDeploy。
这里可能有人会有疑问,如果我在app.dicon或者其子dicon下定义了某个component,而又符合Creator可以自动构造的命名规则的话,究竟是这个component的ComponentDef是谁来生成呢?查看HotdeployBehavior类的getCompoonentDef类,如下:
protected ComponentDef getComponentDef(S2Container container, Object key) { ComponentDef cd = super.getComponentDef(container, key); if (cd != null) { return cd; } if (container != container.getRoot()) { return null; } cd = getComponentDefFromCache(key); if (cd != null) { return cd; } if (key instanceof Class) { cd = createComponentDef((Class) key); } else if (key instanceof String) { cd = createComponentDef((String) key); if (cd != null && !key.equals(cd.getComponentName())) { logger.log("WSSR0011", new Object[] { key, cd.getComponentClass().getName(), cd.getComponentName() }); cd = null; } } else { throw new IllegalArgumentException("key"); } if (cd != null) { register(cd); S2ContainerUtil.putRegisterLog(cd); cd.init(); } return cd; }
重点看第一行,进入这个函数,有
protected ComponentDef getComponentDef(final S2Container container, final Object key) { return ((S2ContainerImpl) container).internalGetComponentDef(key); }
再进入S2ContainerImpl的internalGetComponentDef函数, 有
protected ComponentDef internalGetComponentDef(Object key) { ComponentDefHolder holder = (ComponentDefHolder) componentDefMap .get(key); if (holder != null) { return holder.getComponentDef(); } if (key instanceof String) { String name = (String) key; int index = name.indexOf(NS_SEP); if (index > 0) { String ns = name.substring(0, index); name = name.substring(index + 1); if (ns.equals(namespace)) { return internalGetComponentDef(name); } } } return null; }
这里有个Map叫做componentDefMap, 在解析app.dicon及其子dicon的xml的时候就会将新生成的componentDef添加到这个Map。所以说如果你在app.dicon中自己定义了component,那么seasar会优先取你自己的定义的这个component,而不再用creator来生成。
返回到container.getComponent函数中。在真实的Seasar项目运行过程中,一般首先会调用getComponent(XXPage.class)获得某个相关html的后台Page类。由之前的代码可以知道,我们首先获得XXPage的相关的ComponentDef,然后调用cd.getComponent()获得XXPage的实例。在cd.getComponent()中调用deploy()函数完成Page实例的生成。而deploy()中又分别调用ConstructorAssembler, PropertyAssembler,InitMethodAssmebler等(根据不同的instance决定,比如Prototype和Singleton在生成时就有差异)完成对构造函数的调用,对类的内部属性的自动注入以及initMethod的调用。在对类的内部属性的自动注入中,就把后台的什么Service,Logic,Dao等等也会一层一层迭代地调用container.getComponent(XXClass)。所以说实际上,只需要container.getComponent(XXPageClass),根据自动注入,就可以把所有的类都实例化了。
相关推荐
在Seasar2中,DI通过配置文件或注解来定义对象之间的依赖关系,使得在运行时可以动态地改变对象的配置,从而实现不同环境下的灵活部署。 例如,一个简单的DI示例包括一个接口`Greeting`,它的实现类`GreetingImpl`...
数据访问对象(DAO)模式是数据库操作的标准设计模式,Seasar的S2DAO模块实现了这一模式,提供了一种统一的方式来处理各种数据库操作。它封装了SQL的编写和执行,减轻了开发者的工作负担。S2DAO支持多种数据库,包括...
为了理解Seasar2框架的基本概念及如何快速启动一个项目,我们首先介绍一个简单的示例:实现一个问候功能。在这个过程中,我们将学习Seasar2中的核心组件之一——`S2Container`。 ##### 登场人物 - **问候语类** (`...
Seasar2还提供了AOP(面向切面编程)支持,通过定义切面和通知,可以在不修改原有代码的情况下,实现如日志记录、权限检查等功能。此外,Seasar2还集成了测试框架,使得单元测试和集成测试变得更加方便。 总的来说...
7. **S2Aspect**:Seasar2的AOP功能允许开发者定义切面,以实现如日志记录、性能监控等跨切面关注点。 8. **配置文件**:Seasar2项目中通常包含多个配置文件,如`s2-tight coupling.xml`、`s2-component.xml`等,...
1. **S2Container**:这是Seasar2的核心,它负责管理应用中的对象,实现了依赖注入(Dependency Injection,DI)和控制反转(Inversion of Control,IoC)。通过S2Container,开发者可以方便地配置和管理对象的生命...
Seasar2是一个源自日本的开源框架,其设计目标是为Java开发者提供轻量级的容器服务,以提高开发效率和代码质量。与许多其他轻量级容器不同,Seasar2强调了无需编写配置文件的特性,它采用了Convention over ...
Seasar2的核心设计理念是组件化和容器化,通过提供一个统一的框架来管理对象的生命周期和依赖关系,使得开发者能够更加专注于业务逻辑的实现,而不是基础设施的搭建。 Seasar2框架包含了多个子项目,其中Teeda...
Seasar for .NET 的核心组件 S2Container.NET 是一个类似于 IoC(Inversion of Control)或 DI(Dependency Injection)容器,它负责管理对象的生命周期和依赖关系。S2Container.NET 1.3.14 版本可能包含以下功能和...
Seasar2是一个已退役的Java应用框架,它旨在简化企业级Java开发,提供了一系列的工具和组件,包括数据库访问、事务管理、IOC(控制反转)和AOP(面向切面编程)等功能。Seasar2的核心组件包括S2Container、S2DAO、S2...
Seasar2其实就是类似于spring的一个提供DI功能的开源框架,但比Sping轻量级。 并且同“其它轻量级容器”不同的是,“完全不需要书写设定文件”,“就算是应用程序发生改动也无需再次起动即可直接识别变更,因此具有...
seasar教程,最流行的java开发框架之一,再过几年可能成为主流. struts与Spring与Hibernate的简化版本,国外很多大公司己经用了几年了,NEC,LG的软件开发都是用这个的。兄弟们快学吧
日本框架seasar 的一个action处理
Seasar框架是一个源自日本的开源Java Web框架,它旨在简化Web应用程序的开发并提高开发效率。Seasar提供了多个组件,其中一个是DOMA(Database Object Mapping Accessor),这是一个强大的数据访问层,它允许开发者...
Seasar2虽然现在已经不太活跃,但它在当时对Java社区的贡献是显著的,它的设计理念和实现方式对后来的框架如Spring有着深远的影响。对于学习和理解Java企业级应用开发,尤其是容器管理和面向切面编程,Seasar2是一个...
该框架的主要目标是简化Java应用程序的开发过程,减少开发过程中对配置文件(尤其是XML配置文件)的依赖,并提供一种更简单的方式来实现依赖注入(Dependency Injection, DI)。Seasar2.3版本作为该系列的一个重要...