@Component 注解高端玩法【策略模式】

news/2025/1/15 18:03:33/

优质博文:IT-BLOG-CN

在这里插入图片描述

Spring框架中,@Component注解本身并不支持直接通过注解参数来定义一个key值。不过,你可以通过自定义注解和@Qualifier注解来实现类似的功能。

以下是一个示例,展示如何通过自定义注解和@Qualifier来实现将不同的实现类注入到Map中,并为每个实现类定义不同的key值。

一、定义接口和实现类

首先,定义一个接口和它的多个实现类。

MyService.java

java">public interface MyService {void execute();
}

MyServiceImpl1.java

java">import org.springframework.stereotype.Component;@Component("service1")
public class MyServiceImpl1 implements MyService {@Overridepublic void execute() {System.out.println("Executing MyServiceImpl1");}
}

MyServiceImpl2.java

java">import org.springframework.stereotype.Component;@Component("service2")
public class MyServiceImpl2 implements MyService {@Overridepublic void execute() {System.out.println("Executing MyServiceImpl2");}
}

自动注入所有实现类到Map

接下来,在需要使用这些实现类的地方,使用@Autowired注解和一个 Map<String, MyService>来自动注入所有实现类。

MyServiceConsumer.java

java">import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.Map;@Component
public class MyServiceConsumer {@Autowiredprivate 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

java">import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.List;@Component
public class MyServiceConsumer {@Autowiredprivate final List<MyService> myServices;public void executeAll() {for (MyService myService : myServices) {myService.execute();}}
}

最后,配置Spring应用程序上下文并执行所得实现类。

java">Application.javaimport 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);}@Beanpublic 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。这个注解通常用于那些没有特定角色的类。

示例:

java">import org.springframework.stereotype.Component;@Component
public class MyService {// 业务逻辑
}

Spring扫描类路径时,带有@Component注解的类会被自动注册为Spring容器中的Bean

【2】@Qualifier @Qualifier注解通常与@Autowired注解一起使用,用于消除Bean注入时的歧义。当有多个相同类型的Bean可供注入时,@Qualifier可以指定要注入的具体Bean

示例:假设我们有两个实现了相同接口的类:

java">import org.springframework.stereotype.Component;@Component
public class ServiceA implements MyService {// 实现
}@Component
public class ServiceB implements MyService {// 实现
}
import org.springframework.stereotype.Component;

如果我们在某个地方自动注入MyService,会产生歧义:

java">@Autowired
private MyService myService; // Spring 不知道注入 ServiceA 还是 ServiceB

这时,我们可以使用@Qualifier来指定具体的Bean

java">@Autowired
@Qualifier("serviceA")
private MyService myService; // 明确指定注入 ServiceA

在这个例子中,"serviceA"ServiceA类的默认Bean名称(类名首字母小写)。

三、源码

Component注解的源码实现主要涉及到两个方面:自动扫描和注册。

首先,Spring框架通过类路径扫描机制自动扫描带有Component注解的类。这是通过使用Java的反射机制实现的。下面是Component注解的简化源码示例:

java">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的简化源码示例:

java">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注解指定扫描范围。


http://www.ppmy.cn/news/1505014.html

相关文章

Python爬虫技术 第33节 未来趋势和技术发展

网络爬虫&#xff08;Web crawler&#xff09;是一种自动化的程序或脚本&#xff0c;用于遍历互联网上的网页并收集所需的数据。爬虫技术在许多领域都有广泛的应用&#xff0c;从搜索引擎到数据分析、市场研究、竞争情报等。 爬虫技术的基础 基本原理&#xff1a; URL管理&…

十大机器学习算法-学习笔记-章节1-线性回归—

一、前言 学习视频&#xff1a;第一章&#xff1a;线性回归原理推导 1-回归问题概述_哔哩哔哩_bilibili 相关资料 该内容仅作为个人笔记使用&#xff0c;希望看到的各位能有所获&#xff0c;博主有误的地方&#xff0c;各位可以在评论区有所指正 二、正文 1、线性回归 什…

高等数学精解【3】

文章目录 线性方程组齐次线性方程组高阶行列式 参考文献 线性方程组 齐次线性方程组 含有两个三元齐次线性方程的方程组 两个三元齐次线性方程通常指的是形如&#xff1a; a 1 x b 1 y c 1 z 0 a 2 x b 2 y c 2 z 0 a_1x b_1y c_1z 0 \\a_2x b_2y c_2z 0 a1​xb…

山东青岛高校大学智能制造实验室数字孪生可视化系统平台建设项目验收

青岛高校大学智能制造实验室作为高校科研和人才培养的重要基地&#xff0c;一直致力于推动智能制造技术的研发和应用。为了提升实验室在智能制造领域的教学、科研和产业合作能力&#xff0c;实验室决定建设数字孪生可视化系统平台。 智能制造数字孪生项目旨在通过搭建一个全面…

C#中的Modbus协议

协议介绍 关于Modbus协议&#xff1a; Modbus协议是MODICON&#xff08;莫迪康&#xff09;&#xff08;现施耐德品牌&#xff09;在1979年开发的&#xff0c;是全球第一个真正用于现场的总线协议&#xff1b;Modbus协议是应用于电子控制器上的一种通用语言。通过此协议&…

举例说明计算机视觉(CV)技术的优势和挑战

计算机视觉&#xff08;CV&#xff09;技术是一种利用计算机算法和技术来解析和理解图像和视频数据的领域。它的优势和挑战如下&#xff1a; 优势&#xff1a; 高速处理&#xff1a;计算机视觉可以快速处理大量的图像和视频数据&#xff0c;使得它在实时应用中非常有用。例如&…

Android应用开发面试之Jetpack面试题分析汇总

Jetpack作为Android开发的一个重要框架,其相关问题在Android原生开发面试中也非常常见。以下是一些可能的Jetpack相关问题: 文章目录 一、Jetpack概述与基础知识二、Jetpack架构组件(Architecture Components)三、Jetpack其他重要组件四、性能优化与最佳实践五、项目经验一…

Python | Leetcode Python题解之第318题最大单词长度乘积

题目&#xff1a; 题解&#xff1a; class Solution:def maxProduct(self, words: List[str]) -> int:masks defaultdict(int)for word in words:mask reduce(lambda a, b: a | (1 << (ord(b) - ord(a))), word, 0)masks[mask] max(masks[mask], len(word))return…