SpringBoot用ServiceLocatorFactoryBean优雅切换支付渠道

 更新时间:2025年10月21日 08:54:10   作者:风象南  
本文主要介绍了SpringBoot用ServiceLocatorFactoryBean优雅切换支付渠道,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、引言

项目开发中,我们经常需要根据不同条件动态选择服务实现,例如根据支付类型选择不同的支付处理器,或根据数据源类型选择不同的数据访问策略。

ServiceLocatorFactoryBean是Spring框架提供的一个特殊工厂Bean,它实现了服务定位模式,允许开发者在运行时根据标识符动态获取服务实现。

二、服务定位模式与ServiceLocatorFactoryBean

1. 服务定位模式简介

服务定位模式(Service Locator Pattern)是一种创建型设计模式,它提供了一个中央组件(服务定位器)来管理和获取各种服务。客户端不直接实例化服务,而是通过服务定位器来获取所需的服务实例。

这种模式的核心优势在于将服务的使用者与服务的提供者解耦,使系统更加灵活和可维护。

2. ServiceLocatorFactoryBean的作用

ServiceLocatorFactoryBean是Spring框架中服务定位模式的一种实现。它的主要功能包括:

  • 自动创建服务定位器接口的代理实现
  • 维护服务标识符与实际服务实现的映射关系
  • 根据客户端请求的标识符,动态返回对应的服务实现
  • 提供类型安全的服务查找机制

3. 与传统依赖注入的区别

虽然Spring框架主要基于依赖注入(DI)模式,但ServiceLocatorFactoryBean提供了一种补充的服务获取方式。两者的主要区别如下:

特性依赖注入ServiceLocatorFactoryBean
依赖获取方式被动接收(Push)主动获取(Pull)
依赖确定时机容器启动/装配时运行时动态选择
客户端感知度对依赖来源无感知需要了解服务定位器接口
实现复杂度通常较低略高(需要额外接口)
动态能力相对固定高度灵活

在实践中,依赖注入和服务定位模式常常是互补使用的,而非相互排斥。

三、ServiceLocatorFactoryBean基本使用

下面通过一个简单示例来说明ServiceLocatorFactoryBean的基本使用方法。

1. 定义服务接口和实现

首先,我们定义一个通用服务接口和多个实现类:

// 支付处理器接口
public interface PaymentProcessor {
    void processPayment(double amount);
}

// 支付宝实现
@Component("alipayProcessor")
public class AlipayProcessor implements PaymentProcessor {
    @Override
    public void processPayment(double amount) {
        System.out.println("处理支付宝支付: " + amount);
    }
}

// 微信支付实现
@Component("wechatPayProcessor")
public class WechatPayProcessor implements PaymentProcessor {
    @Override
    public void processPayment(double amount) {
        System.out.println("处理微信支付: " + amount);
    }
}

// 银行卡支付实现
@Component("bankCardProcessor")
public class BankCardProcessor implements PaymentProcessor {
    @Override
    public void processPayment(double amount) {
        System.out.println("处理银行卡支付: " + amount);
    }
}

2. 定义服务定位器接口

接下来,定义一个服务定位器接口用于获取不同的支付处理器:

public interface PaymentProcessorLocator {
    // 根据支付类型获取对应的处理器
    PaymentProcessor getPaymentProcessor(String paymentType);
}

3. 配置ServiceLocatorFactoryBean

在Spring Boot配置类中配置ServiceLocatorFactoryBean:

@Configuration
public class ServiceLocatorConfig {
    
    @Bean
    public ServiceLocatorFactoryBean paymentProcessorLocator() {
        ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
        factoryBean.setServiceLocatorInterface(PaymentProcessorLocator.class);
        return factoryBean;
    }
}

4. 使用服务定位器

现在我们可以在任何需要处理支付的组件中注入服务定位器,并根据支付类型动态获取对应的处理器:

@Service
public class PaymentService {
    
    private final PaymentProcessorLocator paymentProcessorLocator;
    
    @Autowired
    public PaymentService(PaymentProcessorLocator paymentProcessorLocator) {
        this.paymentProcessorLocator = paymentProcessorLocator;
    }
    
    public void processPayment(String paymentType, double amount) {
        // 通过服务定位器获取对应的支付处理器
        PaymentProcessor processor = paymentProcessorLocator.getPaymentProcessor(paymentType);
        
        // 执行支付处理
        processor.processPayment(amount);
    }
}

5. 工作原理解析

ServiceLocatorFactoryBean的工作流程如下:

  1. Spring容器初始化时,创建ServiceLocatorFactoryBean

  2. ServiceLocatorFactoryBean创建服务定位器接口的代理实现

  3. 当客户端调用服务定位器的方法时,代理实现会:

    • 获取方法的参数(服务标识符)
    • 根据参数查找对应的Bean(默认情况下参数即为Bean名称)
    • 返回对应的服务实现给调用者
  4. 如果找不到匹配的服务实现,ServiceLocatorFactoryBean会抛出异常

四、进阶配置与自定义

ServiceLocatorFactoryBean提供了多种配置选项,可以根据需求进行自定义。

1. 自定义查找过程

默认情况下,ServiceLocatorFactoryBean使用方法参数作为Bean的名称。但有时我们可能需要一个更灵活的查找机制,如添加前缀或后缀:

@Configuration
public class CustomServiceLocatorConfig {
    
    @Bean
    public ServiceLocatorFactoryBean paymentProcessorLocator() {
        ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
        factoryBean.setServiceLocatorInterface(PaymentProcessorLocator.class);
        
        // 设置自定义名称解析器
        factoryBean.setServiceMappings(customServiceMappings());
        
        return factoryBean;
    }
    
    @Bean
    public Properties customServiceMappings() {
        Properties mappings = new Properties();
        mappings.setProperty("alipay", "alipayProcessor");
        mappings.setProperty("wechat", "wechatPayProcessor");
        mappings.setProperty("bankcard", "bankCardProcessor");
        return mappings;
    }
}

这样,客户端可以使用简化的标识符(如"alipay"),而不必知道实际的Bean名称("alipayProcessor")。

2. 处理异常情况

如果客户端请求一个不存在的服务,ServiceLocatorFactoryBean默认会抛出异常。我们可以配置它返回一个默认实现:

@Configuration
public class ServiceLocatorWithDefaultConfig {
    
    @Bean
    public ServiceLocatorFactoryBean paymentProcessorLocator() {
        ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
        factoryBean.setServiceLocatorInterface(PaymentProcessorLocator.class);
        
        // 当请求的Bean不存在时,设置默认实现
        factoryBean.setSingletonBeanName("defaultPaymentProcessor");
        
        return factoryBean;
    }
    
    @Bean("defaultPaymentProcessor")
    public PaymentProcessor defaultPaymentProcessor() {
        return new PaymentProcessor() {
            @Override
            public void processPayment(double amount) {
                System.out.println("使用默认处理器处理支付: " + amount);
            }
        };
    }
}

3. 扩展查找Key的生成策略

我们还可以通过自定义FactoryBean来扩展查找Key的生成策略:

public class EnhancedServiceLocatorFactoryBean extends ServiceLocatorFactoryBean {
    
    @Override
    protected String getServiceBeanName(Method method, Object[] args) {
        // 默认情况下,使用第一个参数作为Bean名称
        if (args != null && args.length > 0) {
            String paymentType = String.valueOf(args[0]);
            
            // 添加处理器后缀
            return paymentType + "Processor";
        }
        
        return super.getServiceBeanName(method, args);
    }
}

@Configuration
public class EnhancedServiceLocatorConfig {
    
    @Bean
    public EnhancedServiceLocatorFactoryBean paymentProcessorLocator() {
        EnhancedServiceLocatorFactoryBean factoryBean = new EnhancedServiceLocatorFactoryBean();
        factoryBean.setServiceLocatorInterface(PaymentProcessorLocator.class);
        return factoryBean;
    }
}

这种方式允许我们实现更复杂的Bean名称生成逻辑,如根据多个参数生成名称或添加前缀/后缀。

五、实战案例:多策略支付系统

下面通过一个完整的多策略支付系统案例,展示ServiceLocatorFactoryBean在实际项目中的应用。

1. 定义支付相关模型

// 支付请求
@Data
public class PaymentRequest {
    private int amount;
    private String paymentMethod;
}

// 支付结果
@Data
@AllArgsConstructor
public class PaymentResult {
    private boolean success;
    private String transactionId;
    private String message;
}

2. 定义支付处理器接口

public interface PaymentProcessor {
    PaymentResult process(PaymentRequest request);
}

3. 实现多种支付处理器

@Component("alipay")
public class AlipayProcessor implements PaymentProcessor {
    
    @Override
    public PaymentResult process(PaymentRequest request) {
        // 模拟支付宝支付处理逻辑
        System.out.println("使用支付宝处理支付: " + request.getAmount());
        
        // 生成交易流水号
        String transactionId = "ALI" + System.currentTimeMillis();
        
        return new PaymentResult(true, transactionId, "支付宝支付成功");
    }
}

@Component("wechat")
public class WechatPayProcessor implements PaymentProcessor {
    
    @Override
    public PaymentResult process(PaymentRequest request) {
        // 模拟微信支付处理逻辑
        System.out.println("使用微信支付处理支付: " + request.getAmount());
        
        // 生成交易流水号
        String transactionId = "WX" + System.currentTimeMillis();
        
        return new PaymentResult(true, transactionId, "微信支付成功");
    }
}

@Component("default")
public class DefaultPaymentProcessor implements PaymentProcessor {
    
    @Override
    public PaymentResult process(PaymentRequest request) {
        // 默认支付处理逻辑
        System.out.println("使用默认方式处理支付: " + request.getAmount());
        
        // 生成交易流水号
        String transactionId = "DEFAULT" + System.currentTimeMillis();
        
        return new PaymentResult(true, transactionId, "默认支付成功");
    }
}

4. 定义支付处理器定位器接口

public interface PaymentProcessorLocator {
    PaymentProcessor getProcessor(String paymentMethod);
}

5. 配置ServiceLocatorFactoryBean

@Configuration
public class PaymentConfig {
    
    @Bean
    public ServiceLocatorFactoryBean paymentProcessorLocator() {
        ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
        factoryBean.setServiceLocatorInterface(PaymentProcessorLocator.class);
        return factoryBean;
    }
}

6. 实现支付服务

@Service
public class PaymentService {

    private static final Logger logger = LoggerFactory.getLogger(PaymentService.class);

    @Autowired
    private PaymentProcessorLocator paymentProcessorLocator;
    
    public PaymentResult processPayment(PaymentRequest request) {
        // 获取对应的支付处理器
        PaymentProcessor processor = paymentProcessorLocator.getProcessor(request.getPaymentMethod());
        try {
            // 处理支付
            return processor.process(request);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            return new PaymentResult(false, null, "支付处理失败: " + e.getMessage());
        }
    }
}

7. 创建控制器

@RestController
public class PaymentController {
    
    private final PaymentService paymentService;
    
    @Autowired
    public PaymentController(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    @PostMapping("/pay")
    public ResponseEntity<PaymentResult> processPayment(@RequestBody PaymentRequest request) {
        PaymentResult result = paymentService.processPayment(request);
        return ResponseEntity.ok(result);
    }
}

六、与其他技术的对比

1. ServiceLocatorFactoryBean vs 工厂方法模式

ServiceLocatorFactoryBean工厂方法模式
由Spring容器管理通常需要手动创建和管理
支持Spring的各种注入特性需要自己实现依赖管理
可利用Spring的类型转换系统需要自己处理类型转换
配置较为简单可能需要编写更多代码
与Spring生态系统集成独立于任何框架

2. ServiceLocatorFactoryBean vs @Qualifier注解

ServiceLocatorFactoryBean@Qualifier注解
运行时动态选择装配时确定
基于方法参数选择基于注解值选择
客户端主动获取服务容器注入服务
适合复杂、动态的服务选择适合简单的限定场景

3. ServiceLocatorFactoryBean vs Spring的抽象工厂

ServiceLocatorFactoryBeanAbstractFactoryBean
创建代理实现服务定位器接口需要手动实现getObject()方法
专注于服务定位通用的工厂Bean机制
配置简单通常需要子类化
根据方法参数选择Bean固定创建特定类型的Bean
可处理多种服务类型通常针对单一类型

4. ServiceLocatorFactoryBean vs 策略模式

ServiceLocatorFactoryBean策略模式
服务发现和管理由Spring容器负责需要手动管理策略实现集合
基于服务标识符动态查找通常需要显式选择策略实现
引入额外的接口层(定位器接口)直接使用策略接口,结构更简单
适合服务较多且变化频繁的场景适合算法族固定但需要运行时切换的场景
与IoC容器紧密集成不依赖特定框架,更加通用

七、总结

ServiceLocatorFactoryBean是Spring框架提供的一种强大服务定位机制,它巧妙地结合了服务定位模式和Spring的依赖注入特性,为开发者提供了一种灵活、类型安全的服务动态选择方案。

虽然服务定位模式有时被视为依赖注入的"反模式",但在特定场景下,ServiceLocatorFactoryBean是一种非常实用的技术,能够在保持代码松耦合的同时,提供运行时的灵活性。

到此这篇关于SpringBoot用ServiceLocatorFactoryBean优雅切换支付渠道的文章就介绍到这了,更多相关SpringBoot ServiceLocatorFactoryBean支付内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java设计模式之桥接模式详解

    Java设计模式之桥接模式详解

    桥接模式(Bridge Pattern)是一种结构型设计模式,用于将抽象部分和实现部分`分离开来,从而使它们可以独立地进行变化,本节给大家讲一下设计模式中的桥接模式,并结合实际业务场景给大家讲解如何使用,需要的朋友可以参考下
    2023-07-07
  • Spring装配Bean教程之XML安装配置bean详解

    Spring装配Bean教程之XML安装配置bean详解

    大家都知道spring有多重配置方式,基于XML,基于注解,基于java类的配置,其中基于XML是最强大的一种,下面这篇文章主要给大家介绍了关于Spring装配Bean之XML安装配置bean的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-10-10
  • 详解SpringBoot的事务管理

    详解SpringBoot的事务管理

    Springboot内部提供的事务管理器是根据autoconfigure来进行决定的。接下来通过本文给大家介绍SpringBoot的事务管理相关知识,感兴趣的朋友一起学习吧
    2017-04-04
  • Java数据结构之图的两种搜索算法详解

    Java数据结构之图的两种搜索算法详解

    在很多情况下,我们需要遍历图,得到图的一些性质。有关图的搜索,最经典的算法有深度优先搜索和广度优先搜索,接下来我们分别讲解这两种搜索算法,需要的可以参考一下
    2022-11-11
  • 一文带你全面了解Java Hashtable

    一文带你全面了解Java Hashtable

    HashTable是jdk 1.0中引入的产物,基本上现在很少使用了,但是会在面试中经常被问到。本文就来带大家一起深入了解一下Hashtable,需要的可以参考一下
    2022-09-09
  • java字符串中提取数字的方法

    java字符串中提取数字的方法

    Java中提取字符串中的数字,可以使用正则表达式或非正则表达式的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-06-06
  • java使用java.io.File类和java.nio.file.Path类对文件重命名

    java使用java.io.File类和java.nio.file.Path类对文件重命名

    这篇文章主要给大家介绍了关于java使用java.io.File类和java.nio.file.Path类对文件重命名的相关资料,本文仅为日常操作记录,方便后期使用查找本地电脑文件太多了,又不想一个一个重命名,改名字什么的很麻烦,需要的朋友可以参考下
    2024-02-02
  • Java中RestTemplate调用API的几种常用写法

    Java中RestTemplate调用API的几种常用写法

    本文介绍了RestTemplate调用http的几种写法,包括post+get,及传递参数的方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-10-10
  • SSM+微信小程序实现物业管理系统及实例代码

    SSM+微信小程序实现物业管理系统及实例代码

    这篇文章主要介绍了SSM+微信小程序实现物业管理系统,ssm微信小程序物业管理系统,有网站后台管理系统,本文通过实例代码给大家展示系统的功能,需要的朋友可以参考下
    2022-02-02
  • SpringMVC访问controller报错404的解决办法(总结超详细)

    SpringMVC访问controller报错404的解决办法(总结超详细)

    纯注解配置SpringMVC程序,使用tomcat8.5.95版本启动,能启动成功并且访问index.jsp页面,但是访问/save时出现404无法访问,本文给大家介绍了SpringMVC访问controller报错404的解决办法,文章总结的非常详细,需要的朋友可以参考下
    2024-05-05

最新评论