SpringFramework5.0 @Indexed註解 簡單解析

紙上得來終覺淺 絕知此事要躬行 —陸游

最近在看SpringBoot覈編程思想(核心篇),看到走向註解驅動編程這章,裏面有講解到:
在SpringFramework5.0引入了一個註解@Indexed ,它可以爲Spring的模式註解添加索引,以提升應用啓動性能。

在往下閱讀的時候,請注意一些模式註解:

Spring註解 場景說明
@Repository 數據倉庫模式註解
@Component 通用組件模式註解
@Service 服務模式註解
@Controller Web控制器模式註解
@Configuration 配置類模式註解

使用場景

在應用中有大量使用@ComponentScan掃描的package包含的類越多的時候,Spring模式註解解析耗時就越長。

使用方法

在項目中使用的時候需要導入一個spring-context-indexer jar包,有Maven和Gradle 兩種導入方式,具體可以看官網,我這裏使用maven方式,引入jar配置如下:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-indexer</artifactId>
        <version>5.1.12.RELEASE</version>
        <optional>true</optional>
    </dependency>
</dependencies>

然後在代碼中,對於使用了模式註解的類上加上@Indexed註解即可。如下:

@Indexed
@Controller
public class HelloController {

}

原理說明

摘自官網:
在這裏插入圖片描述
簡單說明一下:在項目中使用了@Indexed之後,編譯打包的時候會在項目中自動生成META-INT/spring.components文件。
當Spring應用上下文執行ComponentScan掃描時,META-INT/spring.components將會被CandidateComponentsIndexLoader 讀取並加載,轉換爲CandidateComponentsIndex對象,這樣的話@ComponentScan不在掃描指定的package,而是讀取CandidateComponentsIndex對象,從而達到提升性能的目的。

知道上面的原理,可以看一下org.springframework.context.index.CandidateComponentsIndexLoader的源碼。


public class CandidateComponentsIndexLoader {

	/**
	 * The location to look for components.
	 * <p>Can be present in multiple JAR files.
	 */
	public static final String COMPONENTS_RESOURCE_LOCATION = "META-INF/spring.components";

	// 省略了的代碼......
	
	@Nullable
	private static CandidateComponentsIndex doLoadIndex(ClassLoader classLoader) {
		if (shouldIgnoreIndex) {
			return null;
		}

		try {
			Enumeration<URL> urls = classLoader.getResources(COMPONENTS_RESOURCE_LOCATION);
			if (!urls.hasMoreElements()) {
				return null;
			}
			List<Properties> result = new ArrayList<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
				result.add(properties);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + result.size() + "] index(es)");
			}
			int totalCount = result.stream().mapToInt(Properties::size).sum();
			
			// 轉換爲CandidateComponentsIndex對象
			return (totalCount > 0 ? new CandidateComponentsIndex(result) : null);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Unable to load indexes from location [" +
					COMPONENTS_RESOURCE_LOCATION + "]", ex);
		}
	}
}

感興趣的可以自行查看全部源碼內容。

使用需注意點

雖然這個@Indexed註解能提升性能,但是在使用的時候也需要注意一一下。

假設Spring應用中存在一個包含META-INT/spring.components資源的a.jar,b.jar僅存在模式註解,那麼使用@ComponentScan掃描這兩個JAR中的package時,b.jar 中的模式註解不會被識別。

請務必注意這樣的問題。

案例說明

使用時候存在上面的注意點,還是用一個簡單的demo進行一下說明,能夠更好的理解。

  • DemoA項目(使用@Indexed註解
    在這裏插入圖片描述

  • DemoB項目(不使用@Indexed註解)

在這裏插入圖片描述

  • SpringBootDemo項目
    在此項目中引入DemoA.jarDemoB.jar 。然後進行如下測試,測試代碼如下:

配置類,掃描模式註解

@Configuration
@ComponentScan(basePackages = "org.springboot.demo")
public class SpringIndexedConfiguration {
}

測試類:


 @Test
    public void testIndexedAnnotation(){

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringIndexedConfiguration.class);

        System.out.println("獲取DemoA Jar中【org.springboot.demo.controller.DemoAController】");
        DemoAController demoAController = context.getBean(DemoAController.class);
        System.out.println("DemoAController = " + demoAController.getClass());

        System.out.println("獲取DemoB Jar中【org.springboot.demo.controller.DemoBController】");
        DemoBController demoBController = context.getBean(DemoBController.class);
        System.out.println("DemoBController = " + demoBController.getClass());
    }

結果:

beanDefinitionName = demoAController
獲取DemoA Jar中【org.springboot.demo.controller.DemoAController】
DemoAController = class org.springboot.demo.controller.DemoAController
獲取DemoB Jar中【org.springboot.demo.controller.DemoBController】

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springboot.demo.controller.DemoBController' available


找不到 DemoBController

通過這樣一個簡單的Demo,驗證了上面提到的使用注意點。

參考資料


歡迎關注我的公衆號,技術路,一起成長。

在這裏插入圖片描述

發佈了299 篇原創文章 · 獲贊 1848 · 訪問量 152萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章