首页 > 编程 > Java > 正文

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

2019-11-26 14:38:53
字体:
来源:转载
供稿:网友

命名空间支持

要实现命名空间支持,需要继承自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 {@Overridepublic void init() {// TODO Auto-generated method stubthis.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;}@Overridepublic 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;@Overridepublic 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);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext)throws BeansException {this.applicationContext = applicationContext;this.beanRegistry = new BeanRegistry(this.applicationContext);}@Overridepublic 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;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException {return bean;}@Overridepublic 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}注解*/@Overridepublic 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*/@WebServicepublic 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{@Overridepublic String syHi(String name) {return "Hello "+name;}}

测试用例

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations={"classpath:applicationContext.xml"})public class InitializationTest {@Testpublic void test(){}}

在处理类中有一段代码是将有@Endpoint注解的类都打印出来,所以如果类名被打印出来就表示配置正常了。

运行测试用例

控制台能够看到

class com.codestd.spring.cxf.ws.HelloServiceImpl

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表