1、@Component
@Component:泛指各种组件;它允许 Spring 自动检测自定义 Bean。换句话说,无需编写任何明确的代码,Spring 就能做到:
- 扫描应用,查找注解为 @Component的类
- 将它们实例化,并注入任何指定的依赖
- 在需要的地方注入
不过,大多数时候应该使用更专业的元(Stereotype)注解来实现这一功能。
2、Spring元注解
Spring 提供了一些专门的元注解:@Controller、@Service 和 @Repository。它们都提供了与 @Component 相同的功能。都可以称为@Component。它们的作用都是一样的,因为它们都是由 @Component 作为元注解组成的注解。它们就像 @Component 别名,在 Spring 自动检测或依赖注入之外有专门的用途和意义。理论上,如果愿意,可以只使用 @Component 来满足我们对 Bean 自动检测的需求。反过来,也可以编写使用 @Component 的专用注解。
不过,Spring 的其他领域会专门使用 Spring 的专用注解来提供额外的自动化优势。因此,应该在大多数情况下坚持使用预定义的专用注解。
@Controller:控制层
@Service:业务层
@Repository:数据访问层
假设在 Spring Boot 项目中拥有上述每种情况的示例:
@Controller
public class ControllerExample {
}@Service
public class ServiceExample {
}@Repository
public class RepositoryExample {
}@Component
public class ComponentExample {
}@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface CustomComponent {
}@CustomComponent
public class CustomComponentExample {
}可以编写一个测试,证明 Spring 能自动检测到每个 Bean 并将其添加到 ApplicationContext 中:
@SpringBootTest
@ExtendWith(SpringExtension.class)
public class ComponentUnitTest {@Autowiredprivate ApplicationContext applicationContext;@Testpublic void givenInScopeComponents_whenSearchingInApplicationContext_thenFindThem() {assertNotNull(applicationContext.getBean(ControllerExample.class));assertNotNull(applicationContext.getBean(ServiceExample.class));assertNotNull(applicationContext.getBean(RepositoryExample.class));assertNotNull(applicationContext.getBean(ComponentExample.class));assertNotNull(applicationContext.getBean(CustomComponentExample.class));}
}3、@ComponentScan
 
@Component 只是一个普通的注解。该注解的作用是将 Bean 与其他对象(如 Domain 对象)区分开来。
Spring 使用 @ComponentScan 注解将它们收集到 ApplicationContext 中。
Spring Boot 中的 @SpringBootApplication 注解就是一个包含了 @ComponentScan 的注解。只要 @SpringBootApplication 类位于项目根目录,它就会默认扫描应用中定义的每个 @Component。
如果 @SpringBootApplication 类不在项目根目录下,或者想扫描外部资源,可以显式配置 @ComponentScan 来查找指定的任何包,只要它存在于 classpath 上。
定义一个超出扫描范围的 @Component Bean:
package com.baeldung.component.scannedscope;@Component
public class ScannedScopeExample {
}接着,通过 @ComponentScan 注解指定其所在的包:
package com.baeldung.component.inscope;@SpringBootApplication
@ComponentScan({"com.baeldung.component.inscope", "com.baeldung.component.scannedscope"})
public class ComponentApplication {//public static void main(String[] args) {...}
}最后,可以测试一下它是别成功扫描加载到:
@Test
public void givenScannedScopeComponent_whenSearchingInApplicationContext_thenFindIt() {assertNotNull(applicationContext.getBean(ScannedScopeExample.class));
}当要扫描项目中的外部依赖时,这种情况更有可能发生。
4、@Component 的限制
 
在某些情况下,无法使用 @Component。但仍希望指定对象成为 Spring 管理的 Bean。
在项目外的包中定义一个使用 @Component 注解的对象:
package com.baeldung.component.outsidescope;@Component
public class OutsideScopeExample {
}下面的测试可以证明 ApplicationContext 不包含外部包中定义的组件:
@Test
public void givenOutsideScopeComponent_whenSearchingInApplicationContext_thenFail() {assertThrows(NoSuchBeanDefinitionException.class, () -> applicationContext.getBean(OutsideScopeExample.class));
}另外,因为它来自第三方,可能无法编辑源码,无法添加 @Component 注解。又或者,我们想根据运行环境有条件地使用一种 Bean 实现,而不是另一种。自动检测通常就足够了,但当它无法满足需求时,可以使用 @Bean 注解。
5、@Component 和 @Bean
 
@Bean 也是 Spring 用于在运行时收集 Bean 的注解,但它不是用在类级别上的。相反,使用 @Bean 注解方法,以便 Spring 可以将方法的结果存储为 Spring Bean。
首先,创建一个没有注解的 POJO:
public class BeanExample {
}在 @Configuration 注解的配置类中,可以创建一个生成 Bean 的方法:
@Bean
public BeanExample beanExample() {return new BeanExample();
}BeanExample 可能代表一个本地类,也可能是一个外部类。这并不重要,只需要返回它的一个实例即可。
然后,编写一个测试,验证 Spring 是否加载了 Bean:
@Test
public void givenBeanComponents_whenSearchingInApplicationContext_thenFindThem() {assertNotNull(applicationContext.getBean(BeanExample.class));
}由于 @Component 和 @Bean 之间的差异,应该注意一些重要的影响。
- @Component是一个类级别的注解,而- @Bean是方法级别的注解,因此只有在类的源代码可编辑时,才可以使用- @Component作为选项。- @Bean始终可以使用,但它的语法更加冗长。
- @Component与 Spring 的自动检测兼容,但- @Bean需要手动实例化类。
- 使用 @Bean可以将 Bean 的实例化与其类定义分离。因此,可以使用它将第三方类转化为 Spring Bean。这也意味着可以添加逻辑来决定要使用哪个实例作为 Bean。
6、总结
本文介绍了 Spring @Component 注解和其他相关主题。
各种 Spring 元注解,只是 @Component 的专门版本。
@Component 注解的组件依需要被 @ComponentScan 扫描才能被实例化为 Spring Bean。
如果不能编辑源码,没法给组件类添加 @Component 注解,那么可以自定义配置类,在方法上使用 @Bean 注解手动地初始化组件类为 Spring Bean。
转载自:https://springdoc.cn/spring-component-annotation/