【Spring源码】- 07 扩展点之自定义标签
Spring
中正逐渐采用注解方式取代XML
配置方式,所以,使用XML
配置的机会正越来越少。然后,如果你开发的工具模块可能会被很多系统使用,考虑到兼容性问题,就需要提供XML
方式集成,这时就需要自定义标签;还有,你在看一些开源源码时,一般也是提供自定义标签方式集成。所以,还是可以去了解一下自定义标签实现。
在Spring
中使用自定义标签还是比较简单,下面我们就实现一个自定义标签
,其功能类似
标签:将指定包路径下带有指定注解的Bean
扫描注册。
【资料图】
1、首先,在resources/META-INF
目录下定义一个xsd
文件,描述自定义
标签属性:
2、自定义NamespaceHandler
,注册
使用CustomScannerBeanDefinitionParser
解析器进行处理:
public class ScannerNameSpaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("scan", new CustomScannerBeanDefinitionParser()); }}
3、自定义CustomScannerBeanDefinitionParser
解析器:
public class CustomScannerBeanDefinitionParser extends AbstractBeanDefinitionParser { @Override protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomScannerConfigurer.class); ClassLoader classLoader = ClassUtils.getDefaultClassLoader(); try { String annotationClassName = element.getAttribute("annotation"); if (StringUtils.hasText(annotationClassName)) { Class extends Annotation> annotationClass = (Class extends Annotation>) classLoader .loadClass(annotationClassName); builder.addPropertyValue("annotationClass", annotationClass); } } catch (Exception ex) { XmlReaderContext readerContext = parserContext.getReaderContext(); readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause()); } builder.addPropertyValue("basePackage", element.getAttribute("base-package")); return builder.getBeanDefinition(); }}
parseInternal()
方法解析标签,然后生成一个BeanDefinition
,Spring
会自动将其注册到IoC
容器中。如果标签只会注册单个Bean
,这里是需要返回注册Bean
对应的BeanDefinition
即可;如果是多个情况,这里一般是注册一个配置类,将标签配置的属性注入到配置类中,然后由配置类统一处理。
4、自定义CustomScannerConfigurer
配置类:
public class CustomScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean { private String basePackage; private Class extends Annotation> annotationClass; @Override public void afterPropertiesSet() throws Exception { //参数校验 notNull(this.basePackage, "Property "basePackage" is required"); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, false); scanner.addIncludeFilter(new AnnotationTypeFilter(annotationClass)); scanner.setIncludeAnnotationConfig(false); int beanCount = scanner.scan(basePackage); registry.getBeanDefinitionNames(); } public String getBasePackage() { return basePackage; } public void setBasePackage(String basePackage) { this.basePackage = basePackage; } public Class extends Annotation> getAnnotationClass() { return annotationClass; } public void setAnnotationClass(Class extends Annotation> annotationClass) { this.annotationClass = annotationClass; }}
CustomScannerConfigurer
实现了BeanDefinitionRegistryPostProcessor
, InitializingBean
两个接口,之前分析过这两个接口。重点在BeanDefinitionRegistryPostProcessor
这个接口,其是一个BeanFactoryPostProcessor
类型扩展,可以向IoC
容器注册BeanDefinition
。在postProcessBeanDefinitionRegistry()
方法中创建一个ClassPathBeanDefinitionScanner
对象,并将标签中配置设置进去,即可实现扫描指定包路径下带有指定注解的Bean
。
5、xsd
是标签描述文件,NamespaceHandler
则是标签后台处理逻辑入口,现在需要将两者进行关联,在resources/META-INF
目录下创建两个文件:Spring.schemas
和Spring.handlers
,分别指定xsd
文件位置和NamespaceHandler
位置,这样就实现了标签和后台逻辑关联,其内容见下:
Spring.schemashttp\://www.simon.org/schema/scan.xsd=META-INF/custom-scan.xsd
Spring.handlershttp\://www.simon.org/schema/scan=customschema.demo03.ScannerNameSpaceHandler
自定义标签描述以及对于的后台处理逻辑都配置完成,下面我们就开始进行测试。
1、首先,定义个注解,用于在扫描Bean
时过滤使用:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Indexedpublic @interface MyComponent { String value() default "";}
2、在customschema.demo03.bean
包路径下定义三个类:TestService01
、TestService02
、TestService03
,将后面两个类使用@MyComponent
注解标注下;
3、编写Spring
的Xml
配置文件,这里就可以使用我们刚才自定义的标签:
4、测试用例:
@Testpublic void test01() { ApplicationContext context = new ClassPathXmlApplicationContext("custom-schema.xml"); Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println);}
从输出结果就可以看到,TestService01
由于没有带有@MyComponent
注解,所以没有注册,TestService02
和TestService03
都会被注册到容器中。
-
【Spring源码】- 07 扩展点之自定义标签
腾讯云 2023-03-28
-
中跆协官网个人会员证查询_太阳神会员查询
互联网 2023-03-28
-
当前动态:鄂汇办查询档案在哪里流程图解
本地宝 2023-03-28
-
炖豆角的正确方法_炖豆角
元宇宙网 2023-03-28
-
中金公司:小米集团-W(01810)主业规模与利润并重,关注造车等创新业务进展
智通财经网 2023-03-28
-
现金分红34.6亿元!双汇发展2022年盈利56.2亿元
大河财立方 2023-03-28
-
个人社保多少岁可以领养老金?领取流程有哪些?|今头条
社保网 2023-03-28
-
世界热资讯!卢家培:助力解决中小企业运输痛点 Lalamove“致胜运送”品牌活动出海
中国青年网 2023-03-28
-
坚持工作不彷徨猜生肖_坚持工作不彷徨打一生肖 全球报道
互联网 2023-03-28
-
咸阳城建投资完成发行2亿短期融资券 利率5.0%
观点网 2023-03-28
-
【Spring源码】- 07 扩展点之自定义标签
腾讯云 2023-03-28
-
中跆协官网个人会员证查询_太阳神会员查询
互联网 2023-03-28
-
当前动态:鄂汇办查询档案在哪里流程图解
本地宝 2023-03-28
-
炖豆角的正确方法_炖豆角
元宇宙网 2023-03-28
-
中金公司:小米集团-W(01810)主业规模与利润并重,关注造车等创新业务进展
智通财经网 2023-03-28
-
现金分红34.6亿元!双汇发展2022年盈利56.2亿元
大河财立方 2023-03-28
-
个人社保多少岁可以领养老金?领取流程有哪些?|今头条
社保网 2023-03-28
-
世界热资讯!卢家培:助力解决中小企业运输痛点 Lalamove“致胜运送”品牌活动出海
中国青年网 2023-03-28
-
坚持工作不彷徨猜生肖_坚持工作不彷徨打一生肖 全球报道
互联网 2023-03-28
-
咸阳城建投资完成发行2亿短期融资券 利率5.0%
观点网 2023-03-28
-
芯德科技终止创业板IPO 保荐机构为招商证券-世界新要闻
中国经济网 2023-03-28
-
驰骋深蓝,护卫海天!海军某支队舰艇编队出海训练掠影
解放军报 2023-03-28
-
天天观焦点:青岛啤酒的焦虑藏在Q4财报里
钛媒体APP 2023-03-28
-
新资讯:前两月工业利润总额降22.9% 工信部部署新一轮稳增长
第一财经 2023-03-28
-
科士达(002518):3月27日北向资金减持524.7万股
证券之星 2023-03-28
-
瑞信危机期间 瑞士央行的活期存款创2011年来以来最大增幅
财联社 2023-03-27
-
深航复航洲际航线!新航季深圳机场国际航线加快“上新”-焦点热闻
深圳特区报 2023-03-27
-
微头条丨这项民心工程让生活品质、地区能级双跃升,上海今年将启动十个“城中村”改造项目
东方网 2023-03-27
-
向着春天再出发:在民营经济发祥地探寻民企动力源
海口网 2023-03-27
-
医院挂号指南 武科大研究发新通用基因编辑工具
城市网 2023-03-27
-
奇瑞QQ冰淇淋、小蚂蚁和无界Pro最高降价9千元,其他车企会降价吗-天天热点评
懂车帝 2023-03-27
-
炒股怎么看均线?均线怎么运用?
万隆证券网 2023-03-27
-
大湾区早报|广东“1+14+15”产业有序转移政策体系成型;广东经济运行企稳回升 1—2月工业投资增长24.9%
21世纪经济报道 2023-03-27
-
用嘴喘气,到底错在哪了?
蝌蚪五线谱 2023-03-27
-
世界新消息丨悦心健康:公司是以现有的部份投资性房地产作价增资到全资子公司,便于后续工业地产转型开发业务开展
证券之星 2023-03-27
-
中天科技:中天科技深耕通信产业多年,在相关领域拥有较好的技术储备和客户基础
证券之星 2023-03-27
-
讯息:新华社《新华每日电讯》头版头条:全面振兴谱新篇——吉林加快推进高质量发展观察
新华网 2023-03-27
-
全球快看:房租装修合同范本(合集16篇)
互联网 2023-03-27
-
游戏里的中国:传统文化与游戏双向赋能,打开更多想象空间
南方都市网 2023-03-26
-
菠萝蜜剥完果肉发现没熟怎么办?
南方养生网 2023-03-26