【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.xsdSpring.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 扩展点之自定义标签|环球快报
- 环球聚焦:科技资讯:亚马逊瞄准苹果iPad推出Kindle Fire HD
- “冀”录乡愁丨炸香椿鱼里的春天味道_精选
- 东莞独生子女费发放新规2022-2023 2022年东莞独生子女补贴新标准最新消息
- 贸易投资顺差去哪了 当前报道
- 【环球快播报】美国银行接连关闭引发动荡 美媒:银行并购无法消弭现存风险
- 【世界独家】五整治!五提升!舟山开启“一键美颜”模式!
- break the leg是什么意思_break a leg是什么意思
- 环球焦点!前置过滤器安装在哪个位置比较合适_前置过滤器安装在什么位置合适
- 今日热搜:蜀道装备最新公告:拟与佳纯投资等建立战略合作伙伴关系
- 天天即时看!失业保险金一次性领取条件是什么?一次领多少钱?
- 【焦点热闻】英国一港口发生重大漏油事故 当局成立最高级应急指挥部
- 河北品牌农产品进京推介会举办
- 环球速递!中国二十二冶集团华东公司 一封表扬信 见证上海生物疫苗车间项目的实力与担当
- 世界最资讯丨贵州江口:“剪”一抹春色带回家
- 上海证监局副局长王登勇:积极推动投资者教育进校园工作走向更宽领域、更深层次
- 37岁中超外援:发自内心的愿意归化,愿代表中国队参加任何比赛
- 打卡下班!完成双响的C罗被换下,贡萨洛-拉莫斯替补登场 世界动态
- “各地古镇相似度99%”是谁的尴尬?_世界热门
- 全球热点评!中国百强交通枢纽!成都南京入围第一梯队,苏州济南稍逊一筹
- 好看的美剧推荐恐怖_好看的美剧推荐-观察
- 时髦女人为何喜欢穿牛仔裤,除了显身材,竟然还能搭成通勤风 天天观速讯
- 506亿元大手笔!分红“模范生”中国神华真“壕” 焦点日报
- 嘉华股份最新公告:公司董事长逝世_天天消息
- 世界看点:后生可畏,他会在勇士的荣耀—崛起济源站取得铜腰带么?
- 每日时讯!电脑如何截屏快捷键
- 国际比赛日 | 拉马尼、厄斯蒂高出战-环球热议
- 打造一流营商环境 厦门航空物流企业合作协议集中签约
- excel银行号码格式怎么设置_excel银行账号格式
- 活蛏子怎么清洗才干净_如何清洗活蛏子_天天消息