使用 @Component 注释接口对于 Spring 类很常见,尤其是对于一些 Spring 原型注释:
package org.springframework.stereotype;
...
@Component
public @interface Service {...}
或:
package org.springframework.boot.test.context;
...
@Component
public @interface TestComponent {...}
@Component 未声明为继承注释:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {...}
但无论如何,在加载上下文期间,Spring 通过考虑候选类中声明的注释的层次结构来发现 bean。
在从底层源加载bean定义的org.springframework.boot.BeanDefinitionLoader类(包含在Spring Boot依赖项中)中,您可以看到一个示例
org.springframework.core.annotation.AnnotationUtils.findAnnotation() Spring 用来在注解的整个层次结构中检索注解:
class BeanDefinitionLoader {
...
private boolean isComponent(Class<?> type) {
// This has to be a bit of a guess. The only way to be sure that this type is
// eligible is to make a bean definition out of it and try to instantiate it.
if (AnnotationUtils.findAnnotation(type, Component.class) != null) {
return true;
}
// Nested anonymous classes are not eligible for registration, nor are groovy
// closures
if (type.getName().matches(".*\\$_.*closure.*") || type.isAnonymousClass()
|| type.getConstructors() == null || type.getConstructors().length == 0) {
return false;
}
return true;
}
...
}
具体来说,这意味着@Service注解本身就是用@Component注解的,Spring会将一个用@Service注解的候选类作为一个bean来实例化。
所以,你的猜测是正确的:
实现此类接口的类将被视为组件
好吧。
但这仅适用于作为 Java 注释的接口(例如 @Service),不适用于普通接口。
对于 Spring 类,这种做法是有意义的(例如丰富实际的原型),但对于您自己的 bean,使用@Component 作为接口而不是实现将不起作用,并且弊大于利: