2008-02-16

3.3stripes配置

3.3stripes配置
3.3.1闲话配置
说到配置文件,先扯几句,笔者在和朋友聊.net技术,发现.net世界有一种趋势,什么都喜欢用web.config配置文件,而java世界正相反,在反对配置文件。孔子说过:过犹不及。Java用配置文件用过了。而stripnate它的反配置也过度,把Hibernate.cfg.xml中配置也放在web.xml中,结果会形成一个巨大的web.xml文件,又形成了structs-config.xml文件那样。.net世界什么配置都放在web.config中。也会导致这个结果。任何事情都有一个度。
在上一章中们也可以看到Stripes的配置很简单,除了annotaion(这应该不算配置),除下就是全部都在web.xml。其实stripes配置很复杂。Stripes是扩展性极强的框架,基本所有的功能模块都解耦的,完成可以在web.xml中stripesFilter去配置自己的实现类,实现功能强大又适合自己的框架。Stripes中有11种可配置组件,这些组件又可以配置自己的参数。而组合这11个配置组件的配置类也可以配置。我们可以通过stripesFilter来配置扩展连自己都不知道的web框架出来。
Stripes的所有的配置都是通过stripesFilter在web.xml中的<init-param>实现的。没有层次,没有顺序,看起来比较混乱,但是stripes基本都给了我们默认值。我们一般不要去考虑很多,但是对于想完全了解stripes功能和扩展stripes,那就得精通这个配置。Stripenate就是扩展stripes,把stripes和hibernate结合起来,使我们开发中小型的应用系统非常备方便。
3.3.2stripes配置类的配置
上面讲了那么闲话,那么现在开始stripes的配置。Stripes的还有最大的好处就是文档很丰富。我们可以看看stripes文档的配置方法的东西。现在所有web系统说的zero configuration都是噱头,没有系统不要配置,没有配置就不可能有扩展性。Stripes所说的zero configuration指的是每个actionbean和每个页面。
Stripea需要的最小配置在第二章已经给出了。在上一节中,我们可以stripes生命周期中的大部分功能都是从配置类中取到的。即然叫配置类,肯定是负责配置的。看看是何方神圣?
上面的图是stripes的configuration的类的关系图。从上面我们可以看出configuration是一个接口,同时还有继承类,一个是default ,一个是runtime。从名字我们就可以看出:runtimeconfiguration是运行时的配置。它通过configruation接口使用启动属解析器从stripeFilter到取到配置的信息。而stripesFilter又使用了configruation的实现(默认是Runtimeconfiguration的对象),让框架的其它程序通过stripesFilter来获得configruation的实现中的所有可配置的对象。
我们在stripesFilter的init()中:
BootstrapPropertyResolver bootstrap = new BootstrapPropertyResolver(filterConfig);
String configurationClassName = bootstrap.getProperty(CONFIG_CLASS);
if (configurationClassName != null) {
try { Class clazz = ReflectUtil.findClass(configurationClassName);
this.configuration = (Configuration) clazz.newInstance();}
catch (Exception e) {
.. .. ..
} }
else { this.configuration = new RuntimeConfiguration(); }
this.configuration.setBootstrapPropertyResolver(bootstrap);
this.configuration.init();
可以看出默认的情况下:stripes是调用RuntimeConfiguration,之后把启动属性解析器传进去,之后就是调用它的init();
我们再转到RuntimeConfiguration类看看,没有init()方法,怎么回事?是不是哪里出错了,这个init()在RuntimeConfiguration的父类中。
public void init() {
try {
this.actionResolver = initActionResolver();
if (this.actionResolver == null) {
this.actionResolver = new NameBasedActionResolver();
this.actionResolver.init(this);
}

this.actionBeanPropertyBinder = initActionBeanPropertyBinder();
if (this.actionBeanPropertyBinder == null) {
this.actionBeanPropertyBinder = new DefaultActionBeanPropertyBinder();
this.actionBeanPropertyBinder.init(this);
}

this.actionBeanContextFactory = initActionBeanContextFactory();
if (this.actionBeanContextFactory == null) {
this.actionBeanContextFactory = new DefaultActionBeanContextFactory();
this.actionBeanContextFactory.init(this);
}

this.typeConverterFactory = initTypeConverterFactory();
if (this.typeConverterFactory == null) {
this.typeConverterFactory = new DefaultTypeConverterFactory();
this.typeConverterFactory.init(this);
}

this.localizationBundleFactory = initLocalizationBundleFactory();
if (this.localizationBundleFactory == null) {
this.localizationBundleFactory = new DefaultLocalizationBundleFactory();
this.localizationBundleFactory.init(this);
}

this.localePicker = initLocalePicker();
if (this.localePicker == null) {
this.localePicker = new DefaultLocalePicker();
this.localePicker.init(this);
}

this.formatterFactory = initFormatterFactory();
if (this.formatterFactory == null) {
this.formatterFactory = new DefaultFormatterFactory();
this.formatterFactory.init(this);
}

this.tagErrorRendererFactory = initTagErrorRendererFactory();
if (this.tagErrorRendererFactory == null) {
this.tagErrorRendererFactory = new DefaultTagErrorRendererFactory();
this.tagErrorRendererFactory.init(this);
}

this.populationStrategy = initPopulationStrategy();
if (this.populationStrategy == null) {
this.populationStrategy = new DefaultPopulationStrategy();
this.populationStrategy.init(this);
}

this.exceptionHandler = initExceptionHandler();
if (this.exceptionHandler == null) {
this.exceptionHandler = new DefaultExceptionHandler();
this.exceptionHandler.init(this);
}

this.multipartWrapperFactory = initMultipartWrapperFactory();
if (this.multipartWrapperFactory == null) {
this.multipartWrapperFactory = new DefaultMultipartWrapperFactory();
this.multipartWrapperFactory.init(this);
}

this.interceptors = initInterceptors();
if (this.interceptors == null) {
this.interceptors = new HashMap<LifecycleStage, Collection<Interceptor>>();
Class<? extends Interceptor> bam = BeforeAfterMethodInterceptor.class;
BeforeAfterMethodInterceptor interceptor = new BeforeAfterMethodInterceptor();

for (LifecycleStage stage : bam.getAnnotation(Intercepts.class).value()) {
Collection<Interceptor> instances = new ArrayList<Interceptor>();
instances.add(interceptor);
this.interceptors.put(stage, instances);
}
}
}
catch (Exception e) {
throw new StripesRuntimeException
("Problem instantiating default configuration objects.", e);
}
}
这个init()方法一同初始化十二个组件。如:actionResolver、actionBeanPropertyBinder、actionBeanContextFactory等框架必要的功能。在上面的程序中:十二个的实现都如:
this.actionResolver = initActionResolver();
if (this.actionResolver == null) {
this.actionResolver = new NameBasedActionResolver();
this.actionResolver.init(this); }
也就是说initActionResolver()、或initLocalePicker()这样的函数的实现优先,没有得到对象才会去运行下的下面的如new NameBasedActionResolver()的默认的功能。看看initActionResolver()之类的函数:protected ActionResolver initActionResolver() { return null; }所有的在defaultConfiguration中都返回null.也就是相当于没有用?那为什么还要用呢?
还就是设计模式中的模版模式,这个函数的功能留给子类去实现。这不是强制性的模版,因为没有给这些方法定义为abstract。也就是子类可以不实现.在Runtimeconfiguration中的实现如下:@Override protected ActionResolver initActionResolver() {
return initializeComponent(ActionResolver.class, ACTION_RESOLVER); }
这个方法调用了:
protected <T extends ConfigurableComponent> T initializeComponent(Class<T> componentType, String propertyName) {
String className = getBootstrapPropertyResolver().getProperty(propertyName);
if (className != null) {
String componentTypeName = componentType.getSimpleName();
try {
log.info("Found configured ", componentTypeName, " class [", className, "], attempting to instantiate and initialize.");
T component = (T) ReflectUtil.findClass(className).newInstance();
component.init(this);
return component;
}
catch (Exception e) {
throw new StripesRuntimeException("Could not instantiate configured "+ componentTypeName + " of type [" + className + "]. Please check " + "the configuration parameters specified in your web.xml.", e);
}
}
else { return null; }
}
其主要功能就是从配置中取到可可配置的组件类,并生成对象。通过@Override的模版方法传到defaultConfiguration中init()方法。最终初stripes调用。

从这上面的一连串的代码,我们可以看出:configuration的采用了模版模式,也就是可以通过继承defaultConfiguration来定制自己的配置类。当然也可以实现configuration接口而完成定制功能。这个定制的配置如下:
<init-param> <param-name>Configuration.Class</param-name>
<param-value> com.morik.config.MyRuntimeConfiguration</param-value </init-param>形成而配置。



3.3.3配置类中组件的配置
我们配置完了配置类,现在要了解是如何去配置配置类中的组件了。在上一节的代码中我们可以看出配置类中的组件都是可以通过web.xml中配置来定制的,它们都是通过initializeComponent(Class<T> componentType, String propertyName) 中
String className = getBootstrapPropertyResolver().getProperty(propertyName);语句来取到配置组件类。
共有
public static final String ACTION_RESOLVER = "ActionResolver.Class";
public static final String ACTION_BEAN_PROPERTY_BINDER = "ActionBeanPropertyBinder.Class";
public static final String ACTION_BEAN_CONTEXT_FACTORY = "ActionBeanContextFactory.Class";
public static final String TYPE_CONVERTER_FACTORY = "TypeConverterFactory.Class";
public static final String LOCALIZATION_BUNDLE_FACTORY = "LocalizationBundleFactory.Class";
public static final String LOCALE_PICKER = "LocalePicker.Class";
public static final String FORMATTER_FACTORY = "FormatterFactory.Class";
public static final String TAG_ERROR_RENDERER_FACTORY = "TagErrorRendererFactory.Class";
public static final String POPULATION_STRATEGY = "PopulationStrategy.Class";
public static final String EXCEPTION_HANDLER = "ExceptionHandler.Class";
public static final String MULTIPART_WRAPPER_FACTORY = "MultipartWrapperFactory.Class";
public static final String INTERCEPTOR_LIST = "Interceptor.Classes";
十二个可配置的组件类。
<init-param>
<param-name>Interceptor.Classes</param-name>
<param-value> com.mongus.stripes.HibernateInterceptor, net.sourceforge.stripes.extras.binding.BindAccessInterceptor, net.sourceforge.stripes.controller.BeforeAfterMethodInterceptor
</param-value>
</init-param>

<init-param> <param-name>ActionBeanPropertyBinder.Class</param-name>
<param-value> com.mongus.stripes.HibernatePropertyBinder</param-value>
</init-param>
<init-param>
<param-name>TypeConverterFactory.Class</param-name>
<param-value> com.mongus.stripes.HibernateTypeConverterFactory</param-value>
</init-param>
<init-param>
<param-name>FormatterFactory.Class</param-name>
<param-value> com.mongus.stripes.HibernateFormatterFactory</param-value>
</init-param>
所有配置类如上面的实现就可以了,所有的配置组件类只要实现相应的接口就可以了。一般都是从stripes默认的配置组件类去继承,实现自己的特有的功能。
看到这里,我们肯定很想看看这样组件和配置之间的关系。


十一个组件接口都继承于ConfigurableComponent接口。ConfigurableComponent接口使用了Configuration接口。于是每个ConfigurableComponent的实现类都可以从Configuration的实现类中得到Configuration的定义的方法。Configuration的定义的方法又全都是获得十二个组件接口类型(包括interceptor接口),这样一来,每个ConfigurableComponent的实现类都可以获得相互的方法。在structs2、wicket的框架也就是采用这种结构的。

3.3.4可配置组件的配置
配置类可以配置,它中间的组件也可以配置,而可配置组件中的属性也可以配置。
ActionResolver(action解析器)


Stripes默认的actionReslover是NameBasedActionResolver。这中间可以配置的属性有:
"ActionResolver.UrlFilters、 ActionResolver.PackageFilters",stripes1.5中已经变成私有的,用不了。没有配置的属性。

ActionBeanPropertyBinder.Class



Stripes默认的actionReslover是DefaultActionBeanPropertyBinder。这中间没有可配置的属性。

ActionBeanContextFactory.Class

Stripes默认的actionReslover是DefaultActionBeanContextFactory,它的可配置属性是actionbean上下文: "ActionBeanContext.Class";我们可以自己实现自己的actionbean上下文,把一些公有的东西写到内面去:
<init-param>
<param-name>ActionBeanContext.Class</param-name>
<param-value>com.jzjt.guyou.service.GuyouActionContext</param-value> </init-param>
TypeConverterFactory.Class

Stripes默认的actionReslover是DefaultTypeConverterFactory,它没有可配置属性。

LocalizationBundleFactory.Class


它没有可配置属性为:LocalizationBundleFactory.ErrorMessageBundle、LocalizationBundleFactory.FieldNameBundle我们在国际化时,stripes会默认找StripesResources.properties中定义的国际化属性。 我们可以把所有的国际化属性放在StripesResources.properties,我们还可可以自已配置国际化文件名,ErrorMessageBundle是出现错误找的文件,.FieldNameBundle是字段找到的文件。在第二章我们已经看到了。
<init-param>
<param-name>LocalizationBundleFactory.FieldNameBundle</param-name>
<param-value>myfieldnamebundle</param-value> </init-param>
<init-param>
<param-name> LocalizationBundleFactory.ErrorMessageBundle </param-name>
<param-value>myerrornamebundle</param-value> </init-param>
Stripes会从myfieldnamebundle。.properties myerrornamebundle。.properties中去找到对应的国际化属性名。如果没有配置,就到StripesResources.properties中找。

"LocalePicker.Class"

它没有可配置属性为:LocalePicker.Locales,它是一个list.我们可以配置多个,如
<init-param>
<param-name>LocalePicker.Locales</param-name>
<param-value>zh:UTF-8</param-value>
</init-param>
这种配置是代表:本地化:中国, 编码采用:UTF-8 我们也可以采用:en_US:UTF-8,Zh:gbk等


"FormatterFactory.Class"

没有可配置属性
"TagErrorRendererFactory.Class"

它没有可配置属性为:TagErrorRenderer.Class
PopulationStrategy.Class

它没有可配置属性;

"ExceptionHandler.Class"

默认是defalutExceptionHandler,delegatingExceptionHandler的可配置属性为:"DelegatingExceptionHandler.UrlFilters";
"DelegatingExceptionHandler.PackageFilters";

"MultipartWrapperFactory.Class"

有MultipartWrapper.Class、FileUpload.MaximumPostSize两个属性,前一个是处理上传的文件类:默认是net.sourceforge.stripes.controller.multipart.CosMultipartWrapper。stripes提供了:
net.sourceforge.stripes.controller.multipart.CommonsMultipartWrapper的common上传的实现。
第二个上传文件的最大:默认是10M。可以采用:10K,5M这样的写法。
"Interceptor.Classes
它是一个list.我们可以采用<init-param>
<param-name>Interceptor.Classes</param-name>
<param-value> com.mongus.stripes.HibernateInterceptor, net.sourceforge.stripes.extras.binding.BindAccessInterceptor, net.sourceforge.stripes.controller.BeforeAfterMethodInterceptor
</param-value>
</init-param>
最后还有一个Validation Properties
Validation.InvokeValidateWhenErrorsExist,默认是否。它是用来判断annotation出了验证错误,还会不会继续运行验证方法。
3.4解析ActionResolver
评论
发表评论

您还没有登录,请登录后发表评论

jljlpch
搜索本博客
最近加入圈子
存档
最新评论