Spring框架与JDK设计模式实践解析
Spring框架与JDK中的设计模式实践
设计模式是软件开发中解决常见问题的可复用方案。本文将深入探讨Spring框架和JDK中几种经典设计模式的实现与应用。
一、Spring框架中的模式实践
1. 工厂模式(BeanFactory)
概念解释:
工厂模式是一种创建型模式,它提供了一种创建对象的最佳方式。在Spring中,BeanFactory
是工厂模式的典型实现,负责创建和管理应用中的所有bean对象。
核心实现:
// 获取BeanFactory
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 从工厂获取bean
UserService userService = context.getBean(UserService.class);
Spring工厂层级结构:
实践建议:
- 优先使用
ApplicationContext
而非直接使用BeanFactory
,因为它提供了更多企业级功能 - 对于资源受限的移动设备应用,可以考虑使用轻量级的
StaticApplicationContext
- 使用
@Configuration
注解的Java配置类替代XML配置,这是更现代的工厂配置方式
2. 代理模式(AOP实现)
概念解释:
代理模式为其他对象提供一种代理以控制对这个对象的访问。Spring AOP使用动态代理在运行时创建代理对象。
两种代理方式:
- JDK动态代理:基于接口实现
- CGLIB代理:基于类继承实现
代码示例:
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before method: " + joinPoint.getSignature().getName());
}
}
代理模式在Spring中的应用场景:
- 声明式事务管理(@Transactional)
- 安全控制(Spring Security)
- 缓存(@Cacheable)
- 日志记录
实践建议:
- 理解AOP的术语:切点(Pointcut)、通知(Advice)、切面(Aspect)
- 优先使用基于接口的代理,因为它更符合面向接口编程的原则
- 对于final类或方法,只能使用CGLIB代理
- 注意代理自调用问题(同一个类中方法调用不会触发AOP)
3. 模板方法模式(JdbcTemplate)
概念解释:
模板方法模式定义一个操作中的算法骨架,而将一些步骤延迟到子类中。Spring的JdbcTemplate
是此模式的经典实现。
核心优势:
- 处理固定流程(获取连接、创建语句、执行SQL、处理异常、释放资源)
- 允许可变部分(SQL语句、参数绑定、结果集处理)
代码示例:
public List<User> findAllUsers() {
return jdbcTemplate.query(
"SELECT * FROM users",
(rs, rowNum) -> new User(
rs.getLong("id"),
rs.getString("name"),
rs.getString("email")
)
);
}
模板方法在Spring中的其他应用:
RestTemplate
(已弃用,推荐使用WebClient
)TransactionTemplate
JmsTemplate
HibernateTemplate
实践建议:
- 使用
NamedParameterJdbcTemplate
替代普通JdbcTemplate
,更易维护 - 对于复杂ORM操作,考虑使用Spring Data JPA
- 合理使用回调接口处理结果集(RowMapper、ResultSetExtractor)
二、JDK内置设计模式实现
1. 观察者模式(java.util.Observable)
概念解释:
观察者模式定义了对象之间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会得到通知并自动更新。
JDK实现:
// 被观察者
class NewsPublisher extends Observable {
public void publishNews(String news) {
setChanged(); // 标记状态已改变
notifyObservers(news); // 通知观察者
}
}
// 观察者
class NewsSubscriber implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("Received news: " + arg);
}
}
// 使用
NewsPublisher publisher = new NewsPublisher();
publisher.addObserver(new NewsSubscriber());
publisher.publishNews("Java 17 released!");
现代替代方案:
- Java 9+:
Flow
API(响应式流) - Spring框架:
ApplicationEvent
和@EventListener
- 第三方库:RxJava、Reactor
实践建议:
- 注意线程安全问题,考虑使用
SwingUtilities.invokeLater()
在UI编程中 - 避免观察者执行长时间操作,防止阻塞通知线程
- 对于复杂事件系统,考虑使用专业的事件总线(如Guava EventBus)
2. 迭代器模式(java.util.Iterator)
概念解释:
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部表示。
JDK实现:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 使用迭代器
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// 增强for循环(语法糖,底层使用迭代器)
for (String name : names) {
System.out.println(name);
}
Java 8+的现代迭代方式:
names.forEach(System.out::println); // 方法引用
// Stream API
names.stream()
.filter(name -> name.length() > 4)
.forEach(System.out::println);
实践建议:
- 实现
Iterable
接口使自定义类可迭代 - 注意
ConcurrentModificationException
异常(迭代时修改集合) - 对于并发集合,使用
CopyOnWriteArrayList
或ConcurrentHashMap
的迭代器 - 考虑使用
Spliterator
进行并行迭代(Java 8+)
3. 装饰器模式(java.io包)
概念解释:
装饰器模式动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更灵活。
JDK IO包中的实现:
// 基础组件
InputStream inputStream = new FileInputStream("data.txt");
// 装饰器:缓冲功能
BufferedInputStream buffered = new BufferedInputStream(inputStream);
// 装饰器:解压功能
GZIPInputStream gzip = new GZIPInputStream(buffered);
// 可以链式组合
DataInputStream data = new DataInputStream(
new BufferedInputStream(
new FileInputStream("data.bin")
)
);
装饰器模式特点:
- 装饰器和被装饰对象实现相同接口
- 可以在运行时动态添加功能
- 支持多层嵌套装饰
实践建议:
使用try-with-resources确保资源正确关闭
try (InputStream is = new BufferedInputStream(new FileInputStream("file.txt"))) { // 使用输入流 }
- 对于简单需求,考虑使用工具方法(如
Files.readAllBytes()
) - 新的NIO.2 API(
Path
和Files
)提供了更简洁的文件操作方式
三、模式选择与实践总结
框架选择:
- 优先使用Spring提供的模式实现(如AOP、模板方法)
- 对于简单场景,可以直接使用JDK内置实现
性能考量:
- 动态代理有性能开销,在高性能场景要谨慎使用
- 装饰器模式会创建多层对象,注意内存消耗
现代Java特性:
- Lambda表达式可以简化某些模式实现(如策略模式)
- Stream API提供了声明式的迭代处理方式
测试建议:
- 对代理对象进行集成测试而非单元测试
- 使用Mock对象测试观察者模式中的通知逻辑
设计模式是提高代码质量的重要工具,但切忌过度设计。理解模式的本质而非机械套用,根据实际需求灵活选择最合适的实现方式。