Namespace support
To implement namespace support, it needs to be inherited from NamespaceHandlerSupport.
package com.codestd.spring.cxf.config.schema;import org.springframework.beans.factory.xml.NamespaceHandlerSupport;import com.codestd.spring.cxf.config.EndpointBeanProcessor;/*** Handle namespace* @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));}}Use the registerBeanDefinitionParser method to explain configuration support added to Spring. annotation-endpoint is an element that is supported by configuration. AnnotationBeanDefinitionParser is a class that handles configuration. EndpointBeanProcessor is a class that processes the Bean annotated @Endpoint, and will be described in detail later.
Processing configuration
Need to implement 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;}}For the application of BeanDefinitionParser, please refer to the official Spring documentation.
Bean registration tool class
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;}}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.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 {}/*** Does the package match* @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*/@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {if (annotationPackage == null || annotationPackage.length() == 0) {return;}if (beanFactory instance of BeanDefinitionRegistry) {BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry)beanFactory;ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry,true);AnnotationTypeFilter filter = new AnnotationTypeFilter(Endpoint.class);scanner.addIncludeFilter(filter);scanner.scan(annotationPackages);}}} Annotation scanning has been implemented here. Then you need to write business processing code in the postProcessAfterInitialization method. AfterInitialization means that the Bean has been created and injected with attributes.
postProcessBeforeInitialization is mainly used to inject properties when bean instantiation.
Let Spring recognize extensions
First create spring.handlers under META-INF in 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 which class to handle.
Then create spring.schemas
http/://www.codestd.com/schema/std/ws/stdws-1.0.xsd=META-INF/schema/stdws-1.0.xsd=META-INF/schema/stdws-1.0.xsd
Specify the location of the Sechma file, Spring will use the xsd file formulated here to verify that the configuration is correct.
test
Create an 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{@Overridepublic String syHi(String name) {return "Hello "+name;}}Test cases
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations={"classpath:applicationContext.xml"})public class InitializationTest {@Testpublic void test(){}} There is a piece of code in the processing class that prints all classes with @Endpoint annotation, so if the class name is printed out, it means that the configuration is normal.
Run test cases
The console can see
class com.codestd.spring.cxf.ws.HelloServiceImpl
Through the introduction of the above content, this extension is basically realized.