实现套路
1、自定义xsd
示例:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:tool="http://www.springframework.org/schema/tool" xmlns="http://lybgeek.github.com/schema/spi" targetNamespace="http://lybgeek.github.com/schema/spi"> <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/> <xsd:import namespace="http://www.springframework.org/schema/beans" schemaLocation="http://www.springframework.org/schema/beans/spring-beans.xsd"/> <xsd:import namespace="http://www.springframework.org/schema/tool"/> <xsd:annotation> <xsd:documentation> <![CDATA[ Namespace support for spi services ]]></xsd:documentation> </xsd:annotation> <xsd:complexType name="scanType"> <xsd:attribute name="id" type="xsd:ID"> <xsd:annotation> <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation> </xsd:annotation> </xsd:attribute> <xsd:attribute name="basePackages" type="xsd:string" use="required"> <xsd:annotation> <xsd:documentation><![CDATA[ Specify the spi package name to scan, multiple scan packages are separated by commas ]]></xsd:documentation> </xsd:annotation> </xsd:attribute> </xsd:complexType> <xsd:complexType name="interceptorType"> <xsd:attribute name="id" type="xsd:ID"> <xsd:annotation> <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation> </xsd:annotation> </xsd:attribute> <xsd:attribute name="class" type="xsd:string" use="required"> <xsd:annotation> <xsd:documentation><![CDATA[ Interceptor class name]]></xsd:documentation> </xsd:annotation> </xsd:attribute> </xsd:complexType> <xsd:complexType name="interceptorChainType"> <xsd:choice> <xsd:element ref="interceptor" minOccurs="1" maxOccurs="unbounded"/> </xsd:choice> </xsd:complexType> <xsd:element name="scan" type="scanType"> <xsd:annotation> <xsd:documentation><![CDATA[ The scan config ]]></xsd:documentation> </xsd:annotation> </xsd:element> <xsd:element name="interceptor" type="interceptorType"> <xsd:annotation> <xsd:documentation><![CDATA[ The interceptor config ]]></xsd:documentation> </xsd:annotation> </xsd:element> <xsd:element name="interceptorChain" type="interceptorChainType"> <xsd:annotation> <xsd:documentation><![CDATA[ The interceptorChainType config ]]></xsd:documentation> </xsd:annotation> </xsd:element> </xsd:schema>
2、自定义解析BeanDefinitionParser解析器
示例:
public class AnnotationBeanDefinitionParser implements BeanDefinitionParser { private final Class<?> beanClass; public AnnotationBeanDefinitionParser(Class<?> beanClass) { this.beanClass = beanClass; } @Override public BeanDefinition parse(Element element, ParserContext parserContext) { String packageToScan = element.getAttribute("basePackages"); String[] packagesToScan = trimArrayElements(commaDelimitedListToStringArray(packageToScan)); RootBeanDefinition beanDefinition = new RootBeanDefinition(); beanDefinition.setBeanClass(beanClass); beanDefinition.setLazyInit(false); beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,packagesToScan); String beanName = BeanUtils.generateBeanName(element,"id",parserContext,beanClass.getName()); parserContext.getRegistry().registerBeanDefinition(beanName,beanDefinition); return beanDefinition; } }
3、定义NamespaceHandler实现类处理自定义标签的处理器
示例:
public class SpiNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("scan", new AnnotationBeanDefinitionParser(SpiAnnotationPostProcessor.class)); } }
4、将写入处理器、标签的位置写入spring.handlers、spring.schemas中
示例:
spring.handlers
http\://lybgeek.github.com/schema/spi=com.github.lybgeek.spring.schema.SpiNamespaceHandler
spring.schemas
http\://lybgeek.github.com/schema/spi/spi.xsd=META-INF/spi/spi.xsd
注:spring.handlers、spring.schemas需放置在resource/META-INF目录底下
示例演示
1、配置xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:spi="http://lybgeek.github.com/schema/spi" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://lybgeek.github.com/schema/spi http://lybgeek.github.com/schema/spi/spi.xsd"> <spi:scan basePackages="com.github.lybgeek"></spi:scan>
2、在启动类上导入xml
@SpringBootApplication @ImportResource(locations = "classpath:/spi.xml") public class SpiTestXmlApplication { public static void main(String[] args) throws Exception{ SpringApplication.run(SpiTestXmlApplication.class); } }
3、验证SPI是否注入spring容器
@Override public void run(ApplicationArguments args) throws Exception { applicationContext.getBeansOfType(SpringSqlDialect.class) .forEach((beanName,bean) -> System.out.println(beanName + "-->" + bean)); }
控制台输入如下
springMysqlDialect-->com.github.lybgeek.dialect.mysql.SpringMysqlDialect@73041b7d mysql-hello-->com.github.lybgeek.dialect.mysql.SpringMysqlDialect@574059d5 springOracleDialect-->com.github.lybgeek.dialect.oracle.SpringOracleDialect@4a50d04a
说明已经导入到spring容器中
总结
自从spring3+开始引入注解驱动后,在新项目基本上很少会使用xml,但如果是一些老旧的项目,大家如果想实现自定义标签注入到spring,就可以使用本文的方式。
套路就是如下
- 1、自定义xsd
- 2、自定义解析BeanDefinitionParser解析器
- 3、定义NamespaceHandler实现类处理自定义标签的处理器
- 4、将写入处理器、标签的位置写入spring.handlers、spring.schemas中