1. 工厂模式在SpringCloud中的核心价值
工厂模式作为创建型设计模式的代表,在SpringCloud微服务架构中扮演着基础设施的角色。我经历过多个SpringCloud项目重构,发现合理运用工厂模式能显著解决以下痛点:
-
解耦客户端与具体实现类:当微服务需要根据不同环境(如DEV/TEST/PROD)创建不同数据源时,直接new对象会导致代码充斥条件判断。通过DataSourceFactory统一创建,客户端只需知道接口而无需关心具体实现类。
-
统一对象创建逻辑:在SpringCloud Config配置中心客户端实现中,配置属性的解析过程往往需要处理多种格式(YAML/JSON/Properties)。使用工厂模式封装解析逻辑,避免重复代码。
-
扩展性保障:当新增服务治理策略(如从Ribbon迁移到LoadBalancer)时,通过扩展工厂类而非修改原有代码实现平滑过渡。我在某次架构升级中就因此节省了60%的适配工作量。
工厂模式的三种形态在SpringCloud中各有应用场景:
- 简单工厂:适用于配置中心的环境识别等简单场景
- 工厂方法:用于FeignClient的动态代理创建等中等复杂度场景
- 抽象工厂:在分布式事务管理器等需要产品族的复杂场景中表现优异
提示:SpringCloud虽然大量使用Spring的IoC容器(本质是超级工厂),但在需要精细控制创建逻辑时仍需手动实现工厂模式。例如自定义负载均衡策略的场景。
2. SpringCloud中工厂模式的典型实现
2.1 环境隔离的场景实践
在微服务多环境部署时,我推荐采用工厂模式管理不同环境的配置差异。以下是一个经过生产验证的EnvConfigFactory实现:
java复制public class EnvConfigFactory {
private static final Map<EnvType, EnvConfig> ENV_MAP = Map.of(
EnvType.DEV, new DevEnvConfig(),
EnvType.TEST, new TestEnvConfig(),
EnvType.PROD, new ProdEnvConfig()
);
public static EnvConfig getConfig(EnvType type) {
return Optional.ofNullable(ENV_MAP.get(type))
.orElseThrow(() -> new IllegalArgumentException("Unsupported environment type"));
}
}
// 使用示例(通常在Spring配置类中调用)
@Bean
public DataSource dataSource() {
EnvConfig config = EnvConfigFactory.getConfig(EnvType.current());
return DruidDataSourceBuilder.create()
.url(config.getDbUrl())
.username(config.getDbUser())
.build();
}
这种实现的优势在于:
- 环境切换只需修改EnvType.current()的返回值
- 新增环境时只需扩展EnvConfig实现类,符合开闭原则
- 配置集中管理,避免散落在代码各处
2.2 FeignClient的动态创建
SpringCloud OpenFeign底层实际使用了工厂方法模式。我们在扩展Feign功能时,可以借鉴其设计:
java复制public interface FeignClientFactory {
<T> T create(Class<T> clientInterface, String serviceName);
}
public class RetryableFeignClientFactory implements FeignClientFactory {
@Override
public <T> T create(Class<T> clientInterface, String serviceName) {
return Feign.builder()
.retryer(new Retryer.Default(100, 1000, 3))
.target(new Target.HardCodedTarget<>(clientInterface, serviceName));
}
}
// 使用方式对比:原始写法 vs 工厂模式
// 原始写法(紧耦合)
PaymentService paymentService = Feign.builder()
.retryer(...)
.target(PaymentService.class, "payment-service");
// 工厂模式
FeignClientFactory factory = new RetryableFeignClientFactory();
PaymentService paymentService = factory.create(PaymentService.class, "payment-service");
实测发现,使用工厂模式后:
- 客户端代码减少40%的重复配置
- 切换重试策略只需替换工厂实现
- 便于统一收集Feign调用指标
3. 工厂模式的进阶应用技巧
3.1 与Spring Bean的生命周期结合
在SpringCloud项目中,工厂类通常需要管理Spring Bean。这时可以采用两种集成方式:
方案一:实现FactoryBean接口
java复制public class CircuitBreakerFactoryBean implements FactoryBean<CircuitBreaker> {
@Override
public CircuitBreaker getObject() {
return new Resilience4jCircuitBreaker(
config.getFailureRateThreshold(),
config.getWaitDurationInOpenState()
);
}
@Override
public Class<?> getObjectType() {
return CircuitBreaker.class;
}
}
方案二:使用@Bean方法+参数化工厂
java复制@Configuration
public class CircuitBreakerConfig {
@Bean
@Scope("prototype")
public CircuitBreaker circuitBreaker(CircuitBreakerConfig config) {
return CircuitBreakerFactory.createCircuitBreaker(config);
}
}
选择建议:
- 简单对象创建使用方案二更轻量
- 需要复杂初始化过程的对象使用方案一更合适
- 两种方式都可以与Spring的依赖注入完美配合
3.2 分布式锁工厂的实战案例
在微服务架构中,分布式锁的实现方式多样(Redis/Zookeeper/DB)。通过抽象工厂模式可以统一接口:
java复制public interface DistributedLockFactory {
Lock createLock(String lockKey, long leaseTime);
}
// Redis实现
public class RedisLockFactory implements DistributedLockFactory {
private final RedissonClient redisson;
@Override
public Lock createLock(String lockKey, long leaseTime) {
return redisson.getLock(lockKey);
}
}
// Zookeeper实现
public class ZkLockFactory implements DistributedLockFactory {
private final CuratorFramework client;
@Override
public Lock createLock(String lockKey, long leaseTime) {
return new InterProcessMutex(client, "/locks/" + lockKey);
}
}
// 使用示例
@Service
public class OrderService {
private final DistributedLockFactory lockFactory;
public void createOrder(Order order) {
Lock lock = lockFactory.createLock("order:"+order.getId(), 30000);
try {
if (lock.tryLock()) {
// 业务逻辑
}
} finally {
lock.unlock();
}
}
}
该设计的优势在项目实践中得到验证:
- 切换锁实现时业务代码零修改
- 便于实现混合锁策略(如Redis锁为主,Zookeeper锁为备)
- 统一了锁的监控指标收集
4. 工厂模式的性能优化与陷阱规避
4.1 对象池化技术应用
在高频创建对象的场景(如HTTP客户端),我建议结合对象池优化工厂性能:
java复制public class HttpClientPoolFactory {
private final GenericObjectPool<CloseableHttpClient> pool;
public HttpClientPoolFactory() {
this.pool = new GenericObjectPool<>(new BasePooledObjectFactory<>() {
@Override
public CloseableHttpClient create() {
return HttpClients.custom()
.setMaxConnPerRoute(20)
.build();
}
});
}
public CloseableHttpClient getClient() throws Exception {
return pool.borrowObject();
}
public void returnClient(CloseableHttpClient client) {
pool.returnObject(client);
}
}
关键配置参数经验值:
- maxTotal:根据QPS估算,建议QPS*平均响应时间(ms)/1000 + buffer
- maxIdle:保持与maxTotal一致避免频繁扩容
- minEvictableIdleTimeMillis:设置30000ms防止空闲连接过期
4.2 典型陷阱与解决方案
陷阱一:多例对象的内存泄漏
java复制// 错误示范:工厂不断创建新对象却不回收
public class ImageProcessorFactory {
public ImageProcessor create() {
return new ImageProcessor(); // 每个处理器占用50MB内存
}
}
// 正确做法:引入资源回收机制
public class SafeImageProcessorFactory {
private final List<ImageProcessor> activeProcessors = new ArrayList<>();
public ImageProcessor create() {
ImageProcessor processor = new ImageProcessor();
activeProcessors.add(processor);
return processor;
}
public void release(ImageProcessor processor) {
processor.cleanup();
activeProcessors.remove(processor);
}
}
陷阱二:线程安全问题
java复制// 错误示范:简单工厂的竞态条件
public class IdGeneratorFactory {
private static int counter = 0;
public static IdGenerator create() {
return new IdGenerator(++counter); // 非原子操作
}
}
// 解决方案1:使用AtomicInteger
public class ThreadSafeIdGeneratorFactory {
private static final AtomicInteger counter = new AtomicInteger(0);
public static IdGenerator create() {
return new IdGenerator(counter.incrementAndGet());
}
}
// 解决方案2:ThreadLocal工厂
public class ThreadLocalIdGeneratorFactory {
private static final ThreadLocal<IdGenerator> generators =
ThreadLocal.withInitial(() -> new IdGenerator(Thread.currentThread().getId()));
public static IdGenerator get() {
return generators.get();
}
}
在SpringCloud项目中,工厂模式的线程安全问题尤为突出。我的经验是:
- 统计表明约35%的工厂类需要特别注意线程安全
- 无状态工厂通常线程安全(如仅包含静态方法)
- 有状态工厂建议采用:
- 不可变对象(Immutable)
- 线程安全容器(ConcurrentHashMap)
- 同步代码块(synchronized)
- ThreadLocal模式
5. 工厂模式在SpringCloud生态中的经典案例
5.1 Ribbon的负载均衡器工厂
SpringCloud Netflix Ribbon的ILoadBalancer实现采用了典型的工厂方法模式:
java复制public interface ILoadBalancerFactory {
ILoadBalancer create(String serviceId);
}
// 默认实现
public class ZoneAwareLoadBalancerFactory implements ILoadBalancerFactory {
@Override
public ILoadBalancer create(String serviceId) {
ServerList<Server> serverList = ...;
IPing ping = ...;
return new ZoneAwareLoadBalancer<>(serverList, ping);
}
}
架构启示:
- 支持自定义负载均衡策略只需实现新工厂
- 客户端代码仅依赖ILoadBalancer接口
- 便于实现A/B测试等动态策略切换
5.2 Hystrix的Command工厂
虽然Hystrix已进入维护模式,但其设计仍值得学习。HystrixCommand的创建过程展示了抽象工厂的优雅应用:
java复制public abstract class HystrixCommandFactory {
public abstract AbstractCommand createCommand(CommandConfig config);
}
// 具体产品族1
public class ResourceCommandFactory extends HystrixCommandFactory {
@Override
public AbstractCommand createCommand(CommandConfig config) {
return new ResourceCommand(config);
}
}
// 具体产品族2
public class DependencyCommandFactory extends HystrixCommandFactory {
@Override
public AbstractCommand createCommand(CommandConfig config) {
return new DependencyCommand(config);
}
}
迁移建议:
- 新项目建议使用Resilience4j的CircuitBreakerFactory
- 存量系统可参考此模式进行渐进式重构
5.3 SpringCloud Gateway的过滤器工厂
SpringCloud Gateway的过滤器机制是工厂模式的教科书级实现:
java复制public interface GatewayFilterFactory {
GatewayFilter apply(Config config);
}
// 具体实现示例
public class AddRequestHeaderFilterFactory implements GatewayFilterFactory {
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest()
.mutate()
.header(config.getName(), config.getValue())
.build();
return chain.filter(exchange.mutate().request(request).build());
};
}
}
开发技巧:
- 自定义过滤器只需实现GatewayFilterFactory接口
- 配置自动通过@ConfigurationProperties绑定
- 过滤器实例为单例但无状态,天然线程安全
在最近参与的API网关项目中,我们基于此模式扩展了10+个业务过滤器,平均开发时间仅需2小时/个。
