SpringBoot通过Map实现天然的策略模式

复制代码

😊 @ 作者: 一恍过去
💖 @ 主页: https://blog.csdn.net/zhuocailing3390
🎊 @ 社区: Java技术栈交流
🎉 @ 主题: SpringBoot通过Map实现天然的策略模式
⏱️ @ 创作时间: 2025年03月25日

目录

前言

策略模式是一种行为设计模式,它允许在运行时选择算法的行为。在Spring框架中,我们可以利用@Resource注解和Map集合来优雅地实现策略模式。

在Spring框架中,当你使用@Resource注解注入一个Map<String, T>时,Spring会自动将所有类型为T的bean收集到这个Map中,其中:

  • Key是bean的名称
  • Value是bean实例

底层机制解析

Spring的集合类型自动装配

Spring框架对集合类型的依赖注入有特殊处理:

  • 当注入List时,会收集所有类型为T的bean
  • 当注入Map<String, T>时,会收集所有类型为T的bean,并以bean名称作为key

@Resource注解的行为

@Resource注解默认按名称装配,但当目标是一个Map时,Spring会特殊处理:

  • 如果Map的key是String类型,value是某个接口/类
  • Spring会查找所有实现该接口/继承该类的bean
  • 将这些bean以"bean名称->bean实例"的形式放入Map

实现原理

Spring在依赖注入时的处理流程:

  • 发现字段/方法参数是Map<String, T>类型
  • 在应用上下文中查找所有类型为T的bean
  • 创建一个新的Map实例
  • 遍历找到的所有bean,以bean名称作为key,bean实例作为value放入Map
  • 将这个Map注入到目标字段/参数中

使用

直接使用Map<String,T>

我们直接定义一个Controller,并且在Controller中使用@ResourceMap<String,T>

java 复制代码
@RestController
@RequestMapping("/test")
public class TestController {
    @Resource
    private Map<String, Object> beanMap = new ConcurrentHashMap<>();
    
    public void beanMap() {
        System.out.println(beanMap.size());
    }
}

验证:
可以看到map中存了项目中所有的bean对象

指定Map中的bean类型

在实际的开发中,我们希望Map中只是存储需要的Bean,并且Controller中可以根据beanName进行转发到不同的Service中,步骤如下:

定义策略接口

java 复制代码
public interface PaymentStrategy {
    void pay();
}

定义实现类

java 复制代码
	@Service("ALI")
	@Slf4j
	public class AliStrategyService implements PaymentStrategy {
	
	    @Override
	    public void pay() {
	        log.info("使用支付宝支付");
	    }
	}


	@Service("WX")
	@Slf4j
	public class WxStrategyService implements PaymentStrategy {
	
	    @Override
	    public void pay() {
	        log.info("使用微信支付");
	    }
	}

策略使用

java 复制代码
@RestController
@RequestMapping("/test")
public class TestController {

    @Resource
    private Map<String, PaymentStrategy> beanMap = new ConcurrentHashMap<>();
    
    public void beanMap() {
        PaymentStrategy wx = beanMap.get("WX");
        wx.pay();
        PaymentStrategy ali = beanMap.get("ALI");
        ali.pay();
    }
}

验证

可以看到map中,就只有两个Bean,并且key就是我们通过@Service(value)定义的名称

自定义注解实现

  • 自定义一个注解
java 复制代码
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface PaymentType {
    String value();
}
  • 注解替换:将原有的@Service(value)替换为@PaymentType (value),比如:
java 复制代码
@PaymentType("CARD")
@Slf4j
public class CardStrategyService implements PaymentStrategy {

    @Override
    public void pay() {
        log.info("使用银行卡支付");
    }
}
  • **意义:**可以更好表示策略模式,让其他开发人员一眼可以看出当前的Service使用了策略模式
复制代码
相关推荐
A-程序设计12 小时前
基于Spring Boot+Vue的生活用品购物平台设计与实现-(源码+LW+可部署)
vue.js·spring boot·后端
k***z1112 小时前
Spring boot创建时常用的依赖
java·spring boot·后端
计算机毕设定制辅导-无忧学长12 小时前
基于Spring Boot的驾校管理系统
java·spring boot·后端
IT_陈寒13 小时前
SpringBoot3.0实战:5个高并发场景下的性能优化技巧,让你的应用快如闪电⚡
前端·人工智能·后端
GEM的左耳返13 小时前
Java面试实战:从Spring Boot到AI集成的技术深度挑战
spring boot·redis·微服务·kafka·java面试·spring ai·缓存优化
老华带你飞13 小时前
动物救助|流浪狗救助|基于Springboot+vue的流浪狗救助平台设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·流浪动物救助平台
Mr.朱鹏13 小时前
RocketMQ可视化监控与管理
java·spring boot·spring·spring cloud·maven·intellij-idea·rocketmq
p***233613 小时前
SpringBoot教程(三十二) SpringBoot集成Skywalking链路跟踪
spring boot·后端·skywalking
绝无仅有13 小时前
Elasticsearch经典面试题案例分析
后端·面试·架构
绝无仅有13 小时前
面试实战:如何实现一个完整的项目从注册到登录的功能?
后端·面试·架构