欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring自定义配置Schema可扩展(二)

程序员文章站 2024-03-08 14:45:17
命名空间支持 要实现命名空间支持,需要继承自namespacehandlersupport。 package com.codestd.spring.cxf.co...

命名空间支持

要实现命名空间支持,需要继承自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

通过以上内容的介绍本次扩展基本上就实现了。