基于Spring可扩展Schema自定义配置(2)

本章主要实现配置支持,注解扫描等功能。为本次教程的核心

命名空间支持

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

本次扩展基本实现。

本此教程的内容可以在Spring官方文档第42章中找到。

Note

本次并没有实现自动发布WebService的功能,这块儿功能比较复杂暂时还没有实现,如果实现会在后面的博文中补充。

时间: 2024-10-01 04:43:19

基于Spring可扩展Schema自定义配置(2)的相关文章

Dubbo源码分析(三):自定义Schema--基于Spring可扩展Schema提供自定义配置支持(spring配置文件中 配置标签支持)

在很多情况下,我们需要为系统提供可配置化支持,简单的做法可以直接基于Spring的标准Bean来配置,但配置较为复杂或者需要更多丰富控制的时候,会显得非常笨拙.一般的做法会用原生态的方式去解析定义好的xml文件,然后转化为配置对象,这种方式当然可以解决所有问题,但实现起来比较繁琐,特别是是在配置非常复杂的时候,解析工作是一个不得不考虑的负担.Spring提供了可扩展Schema的支持,这是一个不错的折中方案,完成一个自定义配置一般需要以下步骤: 设计配置属性和JavaBean 编写XSD文件 编

Spring可扩展Schema标签

基于Spring可扩展Schema提供自定义配置支持 http://blog.csdn.net/cutesource/article/details/5864562 WARN : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Ignored XML validation warning org.xml.sax.SAXParseException; lineNumber: 7; columnNumber: 66; s

Spring Boot 2.0+ 自定义配置类扩展springMVC的功能

在spring boot1.0+,我们可以使用WebMvcConfigurerAdapter来扩展springMVC的功能,其中自定义的拦截器并不会拦截静态资源(js.css等). 在Spring Boot2.0版本中,WebMvcConfigurerAdapter这个类被弃用了. @Deprecated public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer { 那么我们如何来扩展关于MVC的配置呢?

Spring Security(4):自定义配置

接着上节的讲,在添加了@EnableWebSecurity注解后,如果需要自定义一些配置,则需要和继承WebSecurityConfigurerAdapter后,覆盖某些方法. 我们来看一下WebSecurityConfigurerAdapter中哪些方法可以重写,需要重写. (1)WebSecurity 默认是一个空方法,一般也不会再重写. public void configure(WebSecurity web) throws Exception { } (2)HttpSecurity 默

Spring Boot 2 使用自定义配置

在application.yml定义配置后,可以使用Environment来读取配置,也可以使用@Value注解让业务代码去读取配置.如果属性较多,可以定义属性映射对象. 开发环境:IntelliJ IDEA 2019.2.2Spring Boot版本:2.1.8 新建一个名称为demo的Spring Boot项目. 一.使用@Value注解 1.application.yml配置为 jdbc: url: localhost:3306 2.添加一个类 ValueProp.cs 注解@Compon

基于.net 的加载自定义配置-误操作

有时候 需要 将程序加载自定义的配置文件,除了自己写解析xml文件.内置的ConfigutionManager对象 是个不错的选项. 按照 app.config 的方式,做一个副本.然后从你的配置文件中,加载指定的配置 键值对! //方法1-可以读取任意位置的xml文件 ExeConfigurationFileMap filemap = new ExeConfigurationFileMap(); filemap.ExeConfigFilename = QuartzConfigPath; //f

基于 Spring + Atomikos 的多数据源配置(含有BaseDao,BaseService)

1.spring配置文件 classpath:/system.properties classpath:/jdbc.properties classpath:/system.properties UTF-8 mysql xph datasource ${mysql_url_xph} ${mysql_user_xph} ${mysql_password_xph} mysql qs datasource ${mysql_url_qs} ${mysql_user_qs} ${mysql_passwor

spring schema自定义

今天看了一下分布式服务框架的那本书,于是里面提到了spring schema的自定义,于是去简单的了解了一下 参考资源:spring schema扩展: http://www.yihaomen.com/article/java/438.htm schema定义:http://www.w3school.com.cn/schema/schema_schema.asp spring schema扩展:http://blog.csdn.net/cutesource/article/details/586

基于Spring Boot自建分布式基础应用

目前刚入职了一家公司,要求替换当前系统(单体应用)以满足每日十万单量和一定系统用户负载以及保证开发质量和效率.由我来设计一套基础架构和建设基础开发测试运维环境,github地址. 出于本公司开发现状及成本考虑,我摒弃了市面上流行的Spring Cloud以及Dubbo分布式基础架构,舍弃了集群的设计,以Spring Boot和Netty为基础自建了一套RPC分布式应用架构.可能这里各位会有疑问,为什么要舍弃应用的高可用呢?其实这也是跟公司的产品发展有关的,避免过度设计是非常有必要的.下面是整个系