Spring自定義配置Schema可擴(kuò)展(二)
命名空間支持
要實(shí)現(xiàn)命名空間支持,需要繼承自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)); } }
通過(guò)registerBeanDefinitionParser方法講配置支持添加到Spring中。annotation-endpoint是配置支持的元素。AnnotationBeanDefinitionParser是處理配置的類。EndpointBeanProcessor是處理@Endpoint注解的Bean的類,后面會(huì)有詳細(xì)的講述。
處理配置
需要實(shí)現(xiàn)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的應(yīng)用參見Spring官方文檔。
Bean注冊(cè)工具類
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); } } }
這里已經(jīng)實(shí)現(xiàn)了注解的掃描。然后需要在postProcessAfterInitialization方法中寫業(yè)務(wù)處理代碼。AfterInitialization表示Bean已經(jīng)創(chuàng)建并且注入屬性。
postProcessBeforeInitialization主要是為了在Bean實(shí)例化時(shí)注入屬性。
讓Spring識(shí)別擴(kuò)展
首先在classpath的META-INF下創(chuàng)建spring.handlers,內(nèi)容如下
http\://www.codestd.com/schema/std/ws=com.codestd.spring.cxf.config.schema.WebServiceAnnotationNamespaceHandler
在這個(gè)文件中指明了哪個(gè)命名空間需要哪個(gè)類來(lái)處理。
然后再創(chuàng)建spring.schemas
http\://www.codestd.com/schema/std/ws/stdws-1.0.xsd=META-INF/schema/stdws-1.0.xsd
指明了Sechma文件的位置,Spring會(huì)使用這里制定的xsd文件來(lái)驗(yàn)證配置是否正確。
測(cè)試
創(chuàng)建接口
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); }
實(shí)現(xiàn)類
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; } }
測(cè)試用例
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:applicationContext.xml"}) public class InitializationTest { @Test public void test(){ } }
在處理類中有一段代碼是將有@Endpoint注解的類都打印出來(lái),所以如果類名被打印出來(lái)就表示配置正常了。
運(yùn)行測(cè)試用例
控制臺(tái)能夠看到
class com.codestd.spring.cxf.ws.HelloServiceImpl
通過(guò)以上內(nèi)容的介紹本次擴(kuò)展基本上就實(shí)現(xiàn)了。
相關(guān)文章
java 反射getClass .class 的使用方法示例
這篇文章主要介紹了java 反射getClass .class 的使用方法,結(jié)合實(shí)例形式分析了java類反射機(jī)制的相關(guān)操作技巧,需要的朋友可以參考下2019-11-11Spring data elasticsearch使用方法詳解
這篇文章主要介紹了Spring data elasticsearch使用方法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01java 注解annotation的使用以及反射如何獲取注解
這篇文章主要介紹了java 注解annotation的使用以及反射如何獲取注解的相關(guān)資料,需要的朋友可以參考下2017-01-01MyBatis-Plus自動(dòng)填充功能失效導(dǎo)致的原因及解決
這篇文章主要介紹了MyBatis-Plus自動(dòng)填充功能失效導(dǎo)致的原因及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02Java數(shù)據(jù)結(jié)構(gòu)及算法實(shí)例:插入排序 Insertion Sort
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)及算法實(shí)例:插入排序 Insertion Sort,本文直接給出實(shí)例代碼,代碼中包含詳細(xì)注釋,需要的朋友可以參考下2015-06-06MyBatis查詢時(shí)屬性名和字段名不一致問(wèn)題的解決方法
這篇文章主要給大家介紹了關(guān)于MyBatis查詢時(shí)屬性名和字段名不一致問(wèn)題的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01