zoukankan      html  css  js  c++  java
  • 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,验证了上面提到的使用注意点。

    参考资料


    欢迎关注我的公众号,技术路,一起成长。

    在这里插入图片描述

  • 相关阅读:
    js常见函数使用
    js数组与函数
    移动端响应式布局
    移动开发之rem布局
    移动flex布局
    移动流式布局
    [剑指offer] 矩阵覆盖
    [剑指offer] 变态跳台阶
    [剑指offer] 跳台阶
    [剑指offer] 斐波那契数列
  • 原文地址:https://www.cnblogs.com/aflyun/p/11992101.html
Copyright © 2011-2022 走看看