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

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

(0)

相关推荐

  • 详解Spring配置事务的五种方式

    Spring配置文件中关于事务配置总是由三个组成部分,分别是 DataSource .TransactionManager  和 代理机制 这三部分,无论哪种配置方式,一般变化的只是代理机制这部分. DataSource.TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager. 具

  • Spring MVC 框架搭建配置方法及详解

    现在主流的Web MVC框架除了Struts这个主力 外,其次就是Spring MVC了,因此这也是作为一名程序员需要掌握的主流框架,框架选择多了,应对多变的需求和业务时,可实行的方案自然就多了.不过要想灵活运用Spring MVC来应对大多数的Web开发,就必须要掌握它的配置及原理. 一.Spring MVC环境搭建:(Spring 2.5.6 + Hibernate 3.2.0) 1. jar包引入 Spring 2.5.6:spring.jar.spring-webmvc.jar.comm

  • Spring中多配置文件及引用其他bean的方式

    Spring多配置文件有什么好处? 按照目的.功能去拆分配置文件,可以提高配置文件的可读性与维护性,如将配置事务管理.数据源等少改动的配置与配置bean单独分开. Spring读取配置文件的几种方式: 1.使用Spring自身提供的ApplicationContext方式读取 在Java程序中可以使用ApplicationContext两个实现类ClassPathXmlApplicationContext以及FileSystemXmlApplicationContext来读取多个配置文件,他们的

  • spring aop两种配置方式

    第一种:注解配置AOP 注解配置AOP(使用 AspectJ 类库实现的),大致分为三步: 1. 使用注解@Aspect来定义一个切面,在切面中定义切入点(@Pointcut),通知类型(@Before, @AfterReturning,@After,@AfterThrowing,@Around). 2. 开发需要被拦截的类. 3. 将切面配置到xml中,当然,我们也可以使用自动扫描Bean的方式.这样的话,那就交由Spring AoP容器管理. 另外需要引用 aspectJ 的 jar 包:

  • Spring的注解配置与XML配置之间的比较

    注释配置相对于 XML 配置具有很多的优势:它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO 的属性名.类型等信息,如果关系表字段和 PO 属性名.类型都一致,您甚至无需编写任务属性映射信息--因为这些信息都可以通过 Java 反射机制获取. 注释和 Java 代码位于一个文件中,而 XML 配置采用独立的配置文件,大多数配置信息在程序开发完成后都不会调整,如果配置信息和 Java 代码放在一起,

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

    简述 本教程主要介绍如何扩展Spring的xml配置,让Spring能够识别我们自定义的Schema和Annotation. 这里我们要实现的功能如下,首先让Spring能够识别下面的配置. <std:annotation-endpoint /> 这个配置的要实现的功能是,配置完后能够让Spring扫描我们自定义的@Endpoint注解.并且根据注解自动发布WebService服务.功能未完全实现,作为扩展Spring的教程,起一个抛砖引玉的作用. 创建项目 首先需要创建一个Java项目,这里

  • 读取spring配置文件的方法(spring读取资源文件)

    1.spring配置文件 复制代码 代码如下: <bean id="configproperties"          class="org.springframework.beans.factory.config.PropertiesFactoryBean">          <property name="location" value="classpath:jdbc.properties"/>

  • 简介Java的Spring框架的体系结构以及安装配置

    体系结构 Spring有可能成为所有企业应用程序的一站式服务,然而,Spring是模块化的,使您可以挑选哪些模块是适用的,而不必把在余下的也引入.以下部分给出详细介绍在Spring框架中所有可用的模块. Spring框架提供约20个模块,可以根据应用程序的要求来使用. 核心容器: 核心容器组成的核心,Beans,上下文和表达式语言模块,其细节如下: 核心模块提供了框架的基本组成部分,包括IoC和依赖注入功能. Bean模块提供BeanFactory是工厂模式的经典实现. Context 上下文模

  • 基于Spring框架的Shiro配置方法

    一.在web.xml中添加shiro过滤器 <!-- Shiro filter--> <filter> <filter-name>shiroFilter</filter-name> <filter-class> org.springframework.web.filter.DelegatingFilterProxy </filter-class> </filter> <filter-mapping> <f

  • 解析Java中如何获取Spring中配置的bean

    一.什么是Spring?Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架 二.如何在程序中获取Spring配置的bean呢?方法一:在初始化时保存ApplicationContext对象代码: 复制代码 代码如下: ApplicationContext ac = new FileSystemXmlApplicationContex("applicationContext.xml");    ac.getBean("beanId"); 说明:

随机推荐