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

时间:2021-05-20

命名空间支持

要实现命名空间支持,需要继承自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\://.codestd.spring.cxf.ws.HelloServiceImpl

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

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章