Spring-based scalable Schema-based custom configuration (2)
This chapter provides configuration support, annotation scanning, and other functions. For the core of this tutorial
Namespace support
To support namespaces, you must inherit fromNamespaceHandlerSupport
.
Package com. codestd. spring. cxf. config. schema; import org. springframework. beans. factory. xml. namespaceHandlerSupport; import com. codestd. spring. cxf. config. endpointBeanProcessor;/*** processing namespace * @ 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 ));}}
You can use the registerBeanDefinitionParser method to add configurations to Spring.annotation-endpoint
Is an element supported by the configuration.AnnotationBeanDefinitionParser
Is the class for processing configuration.EndpointBeanProcessor
Yes@Endpoint
Annotation Bean class, which will be described in detail later.
Processing Configuration
BeanDefinitionParser needs to be implemented
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; }}
For BeanDefinitionParser applications, see the official Spring documentation.
Bean registration tool
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; }}
Processing @ 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. classpathbeandefinition.pdf; 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 implements attributes, DisposableBean, BeanPostProcessor, ApplicationContextAware {private final String attributes = ","; private ApplicationContext applicationContext; private String annotationPackage; private String [] annotationPackages; private BeanRegistry beanRegistry; public void setAnnotationPackage (St Ring 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 {}/*** whether the package matches * @ 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 ;}/ *** scan {@ link com. codestd. spring. cxf. annotation. endpoint} annotation */@ Override public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException {if (annotationPackage = null | annotationPackage. length () = 0) {return;} if (beanFactory instanceof BeanDefinitionRegistry) {describeandefinitionregistry = (BeanDefinitionRegistry) beanFactory; describeandefinitionregistry; true ); annotationTypeFilter filter = new AnnotationTypeFilter (Endpoint. class); program. addmediadefilter (filter); optional. scan (annotationPackages );}}}
Annotation scanning has been implemented here. Then you needpostProcessAfterInitialization
Method. AfterInitialization indicates that the Bean has been created and the attributes are injected.
postProcessBeforeInitialization
It is mainly used to inject attributes during Bean instantiation.
Extend Spring Recognition
First create spring. handlers in the META-INF of classpath, the content is as follows
http\://www.codestd.com/schema/std/ws=com.codestd.spring.cxf.config.schema.WebServiceAnnotationNamespaceHandler
In this file, specify which namespace needs to be processed by the class.
Then create spring. schemas
http\://www.codestd.com/schema/std/ws/stdws-1.0.xsd=META-INF/schema/stdws-1.0.xsd
Specifies the location of the Sechma file. Spring will use the xsd file specified here to verify whether the configuration is correct.
Test
Create Interface
package com.codestd.spring.cxf.ws;import javax.jws.WebService;/** * @author jaune(Wang Chengwei) * @since 1.0.0 */@WebServicepublic interface HelloService { public String syHi(String name);}
Implementation class
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; }}
Test Cases
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations={"classpath:applicationContext.xml"})public class InitializationTest { @Test public void test(){ }}
There is a piece of code in the processing class that prints out all classes with @ Endpoint annotation, so if the class name is printed, the configuration is normal.
Run Test Cases
The console shows
class com.codestd.spring.cxf.ws.HelloServiceImpl
This extension is basically implemented.
The content of this tutorial can be found in Chapter 42nd of Spring official documentation.
Note
This time, the WebService function has not been automatically released. This function is complicated and has not yet been implemented yet. If it is implemented, it will be added in the following blog post.