@Component 注解高端玩法【策略模式】
首先,定义一个接口和它的多个实现类。@Override自动注入所有实现类到Map接下来,在需要使用这些实现类的地方,使用@Autowired注解和一个来自动注入所有实现类。
优质博文:IT-BLOG-CN
在Spring
框架中,@Component
注解本身并不支持直接通过注解参数来定义一个key
值。不过,你可以通过自定义注解和@Qualifier
注解来实现类似的功能。
以下是一个示例,展示如何通过自定义注解和@Qualifier
来实现将不同的实现类注入到Map
中,并为每个实现类定义不同的key
值。
一、定义接口和实现类
首先,定义一个接口和它的多个实现类。
MyService.java
public interface MyService {
void execute();
}
MyServiceImpl1.java
import org.springframework.stereotype.Component;
@Component("service1")
public class MyServiceImpl1 implements MyService {
@Override
public void execute() {
System.out.println("Executing MyServiceImpl1");
}
}
MyServiceImpl2.java
import org.springframework.stereotype.Component;
@Component("service2")
public class MyServiceImpl2 implements MyService {
@Override
public void execute() {
System.out.println("Executing MyServiceImpl2");
}
}
自动注入所有实现类到Map
接下来,在需要使用这些实现类的地方,使用@Autowired
注解和一个 Map<String, MyService>
来自动注入所有实现类。
MyServiceConsumer.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class MyServiceConsumer {
@Autowired
private Map<String, MyService> myServices;
public void executeAll() {
for (Map.Entry<String, MyService> entry : myServices.entrySet()) {
System.out.println("Executing service with key: " + entry.getKey());
entry.getValue().execute();
}
}
}
当我们可以拿到一个Map
的时候,就可以根据客户端传递过来的key
获取到对应的实现类进行处理了。
自动注入所有实现类List
: 接下来,在需要使用这些实现类的地方,使用@Autowired
注解和一个List
或Map
来自动注入所有实现类。
MyServiceConsumer.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class MyServiceConsumer {
@Autowired
private final List<MyService> myServices;
public void executeAll() {
for (MyService myService : myServices) {
myService.execute();
}
}
}
最后,配置Spring
应用程序上下文并执行所得实现类。
Application.java
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
MyServiceConsumer myServiceConsumer = ctx.getBean(MyServiceConsumer.class);
myServiceConsumer.executeAll();
};
}
}
二、@Component 和 @Qualifier 区别
在Spring
框架中,@Qualifier
和@Component
是两个常用的注解,但它们有不同的用途和作用。
【1】@Component
: @Component
是一个通用的Spring
组件注解。它用于将一个类标记为Spring
的组件,使其能够被Spring
容器自动检测和注册为一个Bean
。这个注解通常用于那些没有特定角色的类。
示例:
import org.springframework.stereotype.Component;
@Component
public class MyService {
// 业务逻辑
}
当Spring
扫描类路径时,带有@Component
注解的类会被自动注册为Spring
容器中的Bean
。
【2】@Qualifier
: @Qualifier
注解通常与@Autowired
注解一起使用,用于消除Bean
注入时的歧义。当有多个相同类型的Bean
可供注入时,@Qualifier
可以指定要注入的具体Bean
。
示例:假设我们有两个实现了相同接口的类:
import org.springframework.stereotype.Component;
@Component
public class ServiceA implements MyService {
// 实现
}
@Component
public class ServiceB implements MyService {
// 实现
}
import org.springframework.stereotype.Component;
如果我们在某个地方自动注入MyService
,会产生歧义:
@Autowired
private MyService myService; // Spring 不知道注入 ServiceA 还是 ServiceB
这时,我们可以使用@Qualifier
来指定具体的Bean
:
@Autowired
@Qualifier("serviceA")
private MyService myService; // 明确指定注入 ServiceA
在这个例子中,"serviceA"
是ServiceA
类的默认Bean
名称(类名首字母小写)。
三、源码
Component
注解的源码实现主要涉及到两个方面:自动扫描和注册。
首先,Spring
框架通过类路径扫描机制自动扫描带有Component
注解的类。这是通过使用Java
的反射机制实现的。下面是Component
注解的简化源码示例:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
}
@Component
注解的元注解中,@Retention
注解表示Component
注解的生命周期为运行时;@Target
注解表示Component
注解可以标记在类上。
接下来,Spring
框架通过BeanDefinition
对象将扫描到的类注册到Spring
容器中。BeanDefinition
包含了类的一些元数据信息,如类名、类的全限定名、类的父类、类实现的接口等。下面是BeanDefinition
的简化源码示例:
public interface BeanDefinition {
String getBeanName();
String getBeanClassName();
Class<?> getBeanClass();
Class<?>[] getInterfaces();
Class<?> getSuperClass();
// ...省略其他方法
}
Spring
框架通过解析Component
注解,将扫描到的类封装成BeanDefinition
对象,并将其注册到BeanFactory
中。BeanFactory
是Spring
容器的核心接口,可以通过该接口获取和管理BeanDefinition
对象。
Component
注解的解析和注册过程一般在Spring
容器启动时进行。Spring
框架会扫描指定的包路径下的所有类,并解析其中的Component
注解,将其注册为BeanDefinition
对象。开发者可以通过配置文件指定要扫描的包路径,也可以使用@ComponentScan
注解指定扫描范围。
更多推荐
所有评论(0)