优质博文: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注解和一个ListMap来自动注入所有实现类。

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中。BeanFactorySpring容器的核心接口,可以通过该接口获取和管理BeanDefinition对象。

Component注解的解析和注册过程一般在Spring容器启动时进行。Spring框架会扫描指定的包路径下的所有类,并解析其中的Component注解,将其注册为BeanDefinition对象。开发者可以通过配置文件指定要扫描的包路径,也可以使用@ComponentScan注解指定扫描范围。

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐