Spring自定义配置Schema可扩展(二)
命名空间支持
要实现命名空间支持,需要继承自namespacehandlersupport。
package com.codestd.spring.cxf.config.schema; import org.springframework.beans.factory.xml.namespacehandlersupport; import com.codestd.spring.cxf.config.endpointbeanprocessor; /** * 处理命名空间 * @author jaune(wang chengwei) * @since 1.0.0 */ public class webserviceannotationnamespacehandler extends namespacehandlersupport { @override public void init() { // todo auto-generated method stub this.registerbeandefinitionparser("annotation-endpoint", new annotationbeandefinitionparser(endpointbeanprocessor.class)); } }
通过registerbeandefinitionparser方法讲配置支持添加到spring中。annotation-endpoint是配置支持的元素。annotationbeandefinitionparser是处理配置的类。endpointbeanprocessor是处理@endpoint注解的bean的类,后面会有详细的讲述。
处理配置
需要实现beandefinitionparser
package com.codestd.spring.cxf.config.schema; import org.springframework.beans.factory.config.beandefinition; import org.springframework.beans.factory.support.rootbeandefinition; import org.springframework.beans.factory.xml.beandefinitionparser; import org.springframework.beans.factory.xml.parsercontext; import org.springframework.util.stringutils; import org.w3c.dom.element; /** * @author jaune(wang chengwei) * @since 1.0.0 */ public class annotationbeandefinitionparser implements beandefinitionparser { private final class<?> beanclass; public annotationbeandefinitionparser(class<?> beanclass) { this.beanclass = beanclass; } @override public beandefinition parse(element element, parsercontext parsercontext) { rootbeandefinition beandefinition = new rootbeandefinition(); beandefinition.setbeanclass(beanclass); beandefinition.setlazyinit(false); string id = element.getattribute("id"); if(id == null || id.length() == 0 ){ string name = element.getattribute("name"); if(!stringutils.isempty(name)) id = name; else id = beanclass.getname(); } if (parsercontext.getregistry().containsbeandefinition(id)) { throw new illegalstateexception("duplicate spring bean id " + id); } parsercontext.getregistry().registerbeandefinition(id, beandefinition); string annotationpackage = element.getattribute("package"); if(!stringutils.isempty(annotationpackage)) beandefinition.getpropertyvalues().add("annotationpackage", annotationpackage); return beandefinition; } }
beandefinitionparser的应用参见spring官方文档。
bean注册工具类
package com.codestd.spring.cxf.config; import org.springframework.beans.beansexception; import org.springframework.beans.factory.config.beandefinition; import org.springframework.beans.factory.support.beandefinitionbuilder; import org.springframework.beans.factory.support.beandefinitionregistry; import org.springframework.context.applicationcontext; import org.springframework.context.applicationcontextaware; import org.springframework.context.configurableapplicationcontext; /** * registry bean. must inject the spring applicationcontext. * @author jaune(wang chengwei) * @since 1.0.0 */ public class beanregistry implements applicationcontextaware{ private applicationcontext applicationcontext; private configurableapplicationcontext configurableapplicationcontext; @override public void setapplicationcontext(applicationcontext applicationcontext) throws beansexception { this.applicationcontext = applicationcontext; if(applicationcontext instanceof configurableapplicationcontext){ this.configurableapplicationcontext = (configurableapplicationcontext)this.applicationcontext; } } public beanregistry(){ } public beanregistry(applicationcontext applicationcontext){ this.setapplicationcontext(applicationcontext); } public beandefinition register(class<?> clazz){ if(configurableapplicationcontext == null)return null; beandefinitionregistry beandefinitonregistry = (beandefinitionregistry)configurableapplicationcontext.getbeanfactory(); beandefinitionbuilder beandefinitionbuilder = this.createbuilder(clazz); beandefinition beandefinition = beandefinitionbuilder.getrawbeandefinition(); beandefinitonregistry.registerbeandefinition(clazz.getname(),beandefinition); return beandefinition; } private beandefinitionbuilder createbuilder(class<?> clazz){ beandefinitionbuilder beandefinitionbuilder = beandefinitionbuilder.genericbeandefinition(clazz); return beandefinitionbuilder; } }
处理@endpoint
package com.codestd.spring.cxf.config; import org.springframework.beans.beansexception; import org.springframework.beans.factory.disposablebean; import org.springframework.beans.factory.config.beanfactorypostprocessor; import org.springframework.beans.factory.config.beanpostprocessor; import org.springframework.beans.factory.config.configurablelistablebeanfactory; import org.springframework.beans.factory.support.beandefinitionregistry; import org.springframework.context.applicationcontext; import org.springframework.context.applicationcontextaware; import org.springframework.context.annotation.classpathbeandefinitionscanner; import org.springframework.core.type.filter.annotationtypefilter; import org.springframework.util.stringutils; import com.codestd.spring.cxf.annotation.endpoint; /** * @author jaune(wangchengwei) * @since 1.0.0 */ public class endpointbeanprocessor implements beanfactorypostprocessor, disposablebean, beanpostprocessor, applicationcontextaware{ private final string comma_split_pattern = ","; private applicationcontext applicationcontext; private string annotationpackage; private string[] annotationpackages; private beanregistry beanregistry; public void setannotationpackage(string annotationpackage) { this.annotationpackage = annotationpackage; if(!stringutils.isempty(this.annotationpackage)) this.annotationpackages = this.annotationpackage.split(this.comma_split_pattern); } @override public void setapplicationcontext(applicationcontext applicationcontext) throws beansexception { this.applicationcontext = applicationcontext; this.beanregistry = new beanregistry(this.applicationcontext); } @override public object postprocessafterinitialization(object bean, string beanname) throws beansexception { if(!this.ismatchpackage(bean))return bean; endpoint endpoint = bean.getclass().getannotation(endpoint.class); if(endpoint != null){ system.out.println(bean.getclass()); } return bean; } @override public object postprocessbeforeinitialization(object bean, string beanname) throws beansexception { return bean; } @override public void destroy() throws exception { } /** * 包是否匹配 * @param bean * @return */ private boolean ismatchpackage(object bean){ if (annotationpackages == null || annotationpackages.length == 0) { return true; } string beanclassname = bean.getclass().getname(); for (string pkg : annotationpackages) { if (beanclassname.startswith(pkg)) { return true; } } return false; } /** * 扫描{@link com.codestd.spring.cxf.annotation.endpoint}注解 */ @override public void postprocessbeanfactory(configurablelistablebeanfactory beanfactory) throws beansexception { if (annotationpackage == null || annotationpackage.length() == 0) { return; } if (beanfactory instanceof beandefinitionregistry) { beandefinitionregistry beandefinitionregistry = (beandefinitionregistry)beanfactory; classpathbeandefinitionscanner scanner = new classpathbeandefinitionscanner(beandefinitionregistry,true); annotationtypefilter filter = new annotationtypefilter(endpoint.class); scanner.addincludefilter(filter); scanner.scan(annotationpackages); } } }
这里已经实现了注解的扫描。然后需要在postprocessafterinitialization方法中写业务处理代码。afterinitialization表示bean已经创建并且注入属性。
postprocessbeforeinitialization主要是为了在bean实例化时注入属性。
让spring识别扩展
首先在classpath的meta-inf下创建spring.handlers,内容如下
http\://www.codestd.com/schema/std/ws=com.codestd.spring.cxf.config.schema.webserviceannotationnamespacehandler
在这个文件中指明了哪个命名空间需要哪个类来处理。
然后再创建spring.schemas
http\://www.codestd.com/schema/std/ws/stdws-1.0.xsd=meta-inf/schema/stdws-1.0.xsd
指明了sechma文件的位置,spring会使用这里制定的xsd文件来验证配置是否正确。
测试
创建接口
package com.codestd.spring.cxf.ws; import javax.jws.webservice; /** * @author jaune(wang chengwei) * @since 1.0.0 */ @webservice public interface helloservice { public string syhi(string name); }
实现类
package com.codestd.spring.cxf.ws; import javax.jws.webservice; import com.codestd.spring.cxf.annotation.endpoint; /** * @author jaune(wang chengwei) * @since 1.0.0 */ @endpoint(address="helloservice", id = "helloserviceendpoint") @webservice(endpointinterface="com.codestd.spring.cxf.ws.helloservice") public class helloserviceimpl implements helloservice{ @override public string syhi(string name) { return "hello "+name; } }
测试用例
@runwith(springjunit4classrunner.class) @contextconfiguration(locations={"classpath:applicationcontext.xml"}) public class initializationtest { @test public void test(){ } }
在处理类中有一段代码是将有@endpoint注解的类都打印出来,所以如果类名被打印出来就表示配置正常了。
运行测试用例
控制台能够看到
class com.codestd.spring.cxf.ws.helloserviceimpl
通过以上内容的介绍本次扩展基本上就实现了。
上一篇: MySQL数据库单表查询
下一篇: Java观察者模式例子