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

网友投稿 174 2023-07-22


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;

}

@Overrhttp://ide

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\://codestd.com/schema/std/ws=com.codestd.spring.cxf.config.schema.WebServiceAnnotationNamespaceHandler

在这个文件中指明了哪个命名空间需要哪个类来处理。

然后再创建spring.schemas

http\://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

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SpringMVC上传图片与访问
下一篇:讲解Java设计模式编程中的建造者模式与原型模式
相关文章

 发表评论

暂时没有评论,来抢沙发吧~