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

这篇文章主要介绍了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

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

相关文章

HashMap是Java中最常用的集合类框架,也是Java语言中非常典型...
在EffectiveJava中的第 36条中建议 用 EnumSet 替代位字段,...
介绍 注解是JDK1.5版本开始引入的一个特性,用于对代码进行说...
介绍 LinkedList同时实现了List接口和Deque接口,也就是说它...
介绍 TreeSet和TreeMap在Java里有着相同的实现,前者仅仅是对...
HashMap为什么线程不安全 put的不安全 由于多线程对HashMap进...