@Indexed
Spring 提供类路径扫描,用于查找指定包下的带注解的组件。假设指定包下有 1000 个类,其中只有 500 个是 Bean,那么类路径扫描会多扫描 500 次;为了解决这个问题并提高应用启动速度,会将 500 个 Bean 保存到 META-INF/spring.components 文件中,当 ClassPathBeanDefinitionScanner 实例化时,会读取该文件中的数据。
@Indexed 注解不需要我们单独使用,因为 @Component 注解使用了它:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
但是,还需要引入一个依赖,不然 @Indexed 注解不起效果。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-indexer</artifactId>
<version>5.3.20</version>
</dependency>
添加依赖后,不需要执行其它操作,当我们编译项目时,Spring 会生成 META-INF/spring.components 文件。此文件中包含候选组件的索引:
com.javabyexamples.spring.core.beanindexing.indexedbased.SampleComponent1=org.springframework.stereotype.Component
com.javabyexamples.spring.core.beanindexing.indexedbased.SampleRepository1=org.springframework.stereotype.Component
com.javabyexamples.spring.core.beanindexing.javaxbased.NamedService=javax.inject.Named
...
例如,Spring 将 SampleComponent1 添加到索引中,因为它具有 @Component 注释。同样,索引包含 NamedService 类,因为它具有 @java.inject.Named 注解。当 Spring 应用程序启动时,如果它找到索引文件,它将使用此静态组件列表并跳过类路径扫描。
示例运行显示了索引使用情况:
DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Using candidate component class from index:
com.javabyexamples.spring.core.beanindexing.custom.CustomComponent1
DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Using candidate component class from index:
com.javabyexamples.spring.core.beanindexing.javaxbased.NamedService
...
值得注意的是:如果组件没有在索引文件中列出,那么这个组件不会被加载,会被忽略。
@Indexed 注解
首先,Spring 会查找使用 @Indexed 注解的类并将其添加到索引中;Spring 还会将 @Component 注解的类添加到索引中:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component { }
也适用于使用 @Component 进行元注解的其它注解:
@Component
public class SampleComponent1 { }
@Repository
public class SampleRepository1 { }
@Service
public class SampleService1 { }
在这里,我们有三个用 @Component、@Repository 和 @Service 注解的类;当我们编译应用程序时,生成的索引文件包含以下三个类:
com.javabyexamples.spring.core.beanindexing.indexedbased.SampleComponent1=org.springframework.stereotype.Component
com.javabyexamples.spring.core.beanindexing.indexedbased.SampleRepository1=org.springframework.stereotype.Component
com.javabyexamples.spring.core.beanindexing.indexedbased.SampleService1=org.springframework.stereotype.Component
Javax 注解
Spring 还会查找使用了 javax.* 注解的类,并将它们添加到候选组件索引中。
例如,它可以使用 @javax.persistence.Entity 查找 JPA 实体类或者使用 @javax.inject.Named 定义的组件:
@Entity
public class SampleEntity1 { }
@Named
public class NamedService { }
索引文件中的每个条目都引用相关的 javax 注解:
com.javabyexamples.spring.core.beanindexing.javaxbased.NamedService=javax.inject.Named
com.javabyexamples.spring.core.beanindexing.javaxbased.SampleEntity1=javax.persistence.Entity
值得注意的是:在 @Entity 的情况下,Spring 不会为 SampleEntity1 创建 Bean。但尽管如此,它仍然需要进行类路径扫描,从而添加到候选组件索引中。
自定义注解
接下来,我们将创建自定义注解,将类标记为候选组件。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface CustomIndexed {
}
当我们用 @CustomIndexed 注解一个类时,Spring 会将其添加到索引文件中:
@CustomIndexed
public class CustomIndexed1 {
}
生成的索引文件包含 CustomIndexed1 类:
com.javabyexamples.spring.core.beanindexing.custom.CustomIndexed1=com.javabyexamples.spring.core.beanindexing.custom.CustomIndexed
多个注解
最后,我们将看看 Spring 如何处理具有多个注解的候选组件:
@Component
@CustomIndexed
@Named
public class MultiComponent1 {
}
在这里,我们使用 @Component、@Named 和 @CustomIndexed 对 MultiComponent1 类进行了注解;当我们编译应用程序时,生成的 spring.components 文件包含:
com.javabyexamples.spring.core.beanindexing.custom.CustomComponent1=org.springframework.stereotype.Component,
com.javabyexamples.spring.core.beanindexing.custom.CustomIndexed,javax.inject.Named
一个索引可以引用多个注解。
禁用候选组件索引
我们可以通过将 spring.index.ignore 设置为 true 来回退到常规类路径扫描;我们可以将此属性定义为系统属性,也可以在类路径的 spring.properties 文件中定义此属性:
spring.index.ignore=true
参考资料
本文作者:不是很聪明
本文链接:https://www.cnblogs.com/baoboshi/p/16388147.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步