@Indexed 注解

最近在看 SpringBoot 核编程思想(核心篇),看到走向注解驱动编程这章,里面有讲解到:在SpringFramework 5.0 引入了一个注解@Indexed ,它可以为 Spring 的模式注解添加索引,以提升应用启动性能。

官网地址:

在往下阅读的时候,请注意一些模式注解:

Spring注解 场景说明
@Repository   数据仓库模式注解  
@Component   通用组件模式注解  
@Service   服务模式注解  
@Controller   Web控制器模式注解  
@Configuration   配置类模式注解  
使用场景

在应用中使用@ComponentScan扫描 package 时,如果 package 中包含很多的类,那么 Spring 启动的时候就会变慢。

提升性能的一个方案就是提供一个 Component 的候选列表,Spring 启动时直接扫描注入这些列表就行了,而不需要一个个类去扫描,再筛选出候选 Component。

需要注意的是:在这种模式下,所有组件扫描的目标模块都必须使用这种机制——大白话将就所有的 Component 组件都必须生成到列表文件中去。

While classpath scanning is very fast, it is possible to improve the startup performance of large applications by creating a static list of candidates at compilation time. In this mode, all modules that are target of component scan must use this mechanism.

使用方式

在项目中使用的时候需要导入一个spring-context-indexer jar包。

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

然后在代码中,对于使用了模式注解的类上加上@Indexed注解即可。如下:

@Indexed @Controller public class HelloController { }

加了上面的依赖后,项目就会自动使用索引的方式启动Spring。

原理说明

摘自官网:

在这里插入图片描述

简单说明一下:在项目中使用了@Indexed之后,编译打包的时候会在项目中自动生成META-INT/spring.components文件。

当Spring应用上下文执行ComponentScan扫描时,META-INT/spring.components将会被CandidateComponentsIndexLoader 读取并加载,转换为CandidateComponentsIndex对象,这样的话@ComponentScan不在扫描指定的package,而是读取CandidateComponentsIndex对象,从而达到提升性能的目的。

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

ublic final class CandidateComponentsIndexLoader { public static final String COMPONENTS_RESOURCE_LOCATION = "META-INF/spring.components"; public static final String IGNORE_INDEX = "spring.index.ignore"; private static final boolean shouldIgnoreIndex = SpringProperties.getFlag(IGNORE_INDEX); private static final Log logger = LogFactory.getLog(CandidateComponentsIndexLoader.class); private static final ConcurrentMap<ClassLoader, CandidateComponentsIndex> cache = new ConcurrentReferenceHashMap<>(); private CandidateComponentsIndexLoader() { } @Nullable public static CandidateComponentsIndex loadIndex(@Nullable ClassLoader classLoader) { ClassLoader classLoaderToUse = classLoader; if (classLoaderToUse == null) { classLoaderToUse = CandidateComponentsIndexLoader.class.getClassLoader(); } return cache.computeIfAbsent(classLoaderToUse, CandidateComponentsIndexLoader::doLoadIndex); } @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(); return (totalCount > 0 ? new CandidateComponentsIndex(result) : null); } catch (IOException ex) { throw new IllegalStateException("Unable to load indexes from location [" + COMPONENTS_RESOURCE_LOCATION + "]", ex); } } } 使用注意点

虽然这个@Indexed注解能提升性能,但是在使用的时候也需要注意下。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwgwyz.html