快訊 >

        世界觀天下!【Spring源碼】- 07 擴展點之自定義標簽

        時間:2023-03-29 09:30:05       來源:騰訊云

        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 annotationClass = (Class) 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()方法解析標簽,然后生成一個BeanDefinitionSpring會自動將其注冊到IoC容器中。如果標簽只會注冊單個Bean,這里是需要返回注冊Bean對應的BeanDefinition即可;如果是多個情況,這里一般是注冊一個配置類,將標簽配置的屬性注入到配置類中,然后由配置類統一處理。

        4、自定義CustomScannerConfigurer配置類:

        public class CustomScannerConfigurer  implements BeanDefinitionRegistryPostProcessor, InitializingBean { private String basePackage; private Class 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 getAnnotationClass() {  return annotationClass; } public void setAnnotationClass(Class annotationClass) {  this.annotationClass = annotationClass; }}

        CustomScannerConfigurer實現了BeanDefinitionRegistryPostProcessor, InitializingBean兩個接口,之前分析過這兩個接口。重點在BeanDefinitionRegistryPostProcessor這個接口,其是一個BeanFactoryPostProcessor類型擴展,可以向IoC容器注冊BeanDefinition。在postProcessBeanDefinitionRegistry()方法中創建一個ClassPathBeanDefinitionScanner對象,并將標簽中配置設置進去,即可實現掃描指定包路徑下帶有指定注解的Bean

        5、xsd是標簽描述文件,NamespaceHandler則是標簽后臺處理邏輯入口,現在需要將兩者進行關聯,在resources/META-INF目錄下創建兩個文件:Spring.schemasSpring.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包路徑下定義三個類:TestService01TestService02TestService03,將后面兩個類使用@MyComponent注解標注下;

        3、編寫SpringXml配置文件,這里就可以使用我們剛才自定義的標簽:

         

        4、測試用例:

        @Testpublic void test01() { ApplicationContext context = new ClassPathXmlApplicationContext("custom-schema.xml"); Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println);}

        從輸出結果就可以看到,TestService01由于沒有帶有@MyComponent注解,所以沒有注冊,TestService02TestService03都會被注冊到容器中。

        關鍵詞:

        首頁
        頻道
        底部
        頂部
        閱讀下一篇

        亚洲综合在线成人一区| 国产成人精品日本亚洲专区| 亚洲线精品一区二区三区| 亚洲精品无码你懂的| 色婷婷亚洲一区二区三区| 日韩亚洲产在线观看| 色偷偷女男人的天堂亚洲网| 亚洲人成免费电影| 亚洲免费视频网址| 亚洲国产精品一区第二页| 亚洲五月综合缴情在线观看| 中文亚洲成a人片在线观看| 国产成人亚洲精品91专区手机| 国产成人99久久亚洲综合精品| 亚洲中文字幕成人在线| 久久久久亚洲爆乳少妇无| 久久亚洲精品无码观看不卡| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 精品亚洲成a人片在线观看 | 久久精品亚洲综合一品| 久久精品国产亚洲av四虎| 亚洲激情视频在线观看| 在线观看亚洲一区二区| 亚洲国产韩国一区二区| 国产成人精品日本亚洲专| 亚洲色丰满少妇高潮18p| 亚洲AV无码资源在线观看| 亚洲欧洲日韩国产| 亚洲国产成人va在线观看网址| 久久精品国产亚洲av麻豆图片| 亚洲最大中文字幕无码网站| 亚洲中文无码mv| 亚洲A∨精品一区二区三区下载| www.亚洲色图| 国产乱辈通伦影片在线播放亚洲 | 国产亚洲一区二区精品| 亚洲卡一卡2卡三卡4卡无卡三| 久久夜色精品国产噜噜亚洲AV| 亚洲国产韩国一区二区| 亚洲熟妇AV日韩熟妇在线| 久久久久亚洲精品无码网址色欲 |