@Indexed
Spring
在进行组件扫描时,会遍历项目中依赖的所有 Jar
包中类路径下所有的文件,找到被 @Component
及其衍生注解标记的类,然后把它们组装成 BeanDefinition
添加到 Spring
容器中。
如果扫描的返回过大,势必会大大地影响项目启动速度。
为了优化扫描速度,引入以下依赖,Spring
将扫描过程提前到编译期:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-indexer</artifactId> <optional>true</optional> </dependency>
package com.example.index; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; import org.springframework.stereotype.Component; import java.util.Arrays; public class IndexApplication { @Component static class Bean1 {} @Component static class Bean2 {} @Component static class Bean3 {} public static void main(String[] args) { DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(factory); String packageName = IndexApplication.class.getPackageName(); System.out.println(">>>>> packageName="+packageName); int scan = scanner.scan(packageName); System.out.println(">>>>> scan="+scan); Arrays.stream(factory.getBeanDefinitionNames()).forEach(System.out::println); } }
运行结果
>>>>> packageName=com.example.index >>>>> scan=8 indexApplication.Bean1 indexApplication.Bean2 indexApplication.Bean3 org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory
运行完了之后,会生成一份 target/classes/META-INF/spring.components
文件,里面的内容是($ 表示内部类
)
com.example.index.IndexApplication$Bean1=org.springframework.stereotype.Component com.example.index.IndexApplication$Bean2=org.springframework.stereotype.Component com.example.index.IndexApplication$Bean3=org.springframework.stereotype.Component
如果把这个文件的某个 bean
删除之后,那么这个 bean
就不会被注册到 ioc
容器。
它是在引入 spring-context-indexer
依赖后,在编译期根据类是否被 @Indexed
注解标记,生成 spring.components
文件及内容。
到目前为止,虽然都没显式使用 @Indexed
注解,但它包含在 @Component
注解中:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Indexed public @interface Component { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean name in case of an autodetected component. * @return the suggested component name, if any (or empty String otherwise) */ String value() default ""; }
导入
spring-context-indexer
依赖后,在编译期根据@Indexed
生成META-INF/spring.components
文件。
Spring
在扫描组件时,如果发现META-INF/spring.components
文件存在,以它为准加载BeanDefinition
,反之遍历包含Jar
包类路径下所有class
信息。