设计模式
单例模式(singleton)
Spring默认将Bean创建为单例,避免重复创建对象带来的性能开销
-
目的:确保一个类只有一个实例,并且提供一个全局访问点
-
应用场景:数据库连接池、日志记录器、配置管理器
java@Component public class MyService{ //默认是单例 } //如果要修改作用域,可以用`@Scope("prototype")`一般在面试中可能会问手撕单例模式,一般面试最希望的成品是:
javapublic class Singleton{ private static volatile Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance == null){ synchronized(Singleton.class){ if(instance == null){ instance = new Singleton(); } } } return instance; } }-
一定要加volatile保证可见性+禁止指令重排序,因为
instance = new Singleton();并非一个原子操作,会经历3步,其他线程可能还没等对象初始化完,就操作了 -
DCL需要Double-check:
- 第一次检查(无锁):提高性能。如果实例已经创建,直接返回,避免每次都加锁。
- 第二次检查(有锁):保证线程安全。防止多个线程同时通过第一次检查后,都进入 synchronized 块并各自 new 一个实例。
总结:"DCL 中的两次 null 检查各有作用:
- 第一次检查在同步块外,是为了避免每次调用都加锁,提升性能;
- 第二次检查在 synchronized 块内,是为了防止多个线程同时通过第一次检查后,重复创建实例。
同时,instance 字段必须用
volatile修饰,禁止指令重排序,确保其他线程不会拿到一个尚未完全初始化的对象。"
Spring单例!=JVM单例:Spring单例是容器级单例(每个
ApplicationContext一个实例),不是JVM全局单例、如果有两个ApplicationContext那么就有两个MyService -
工厂方法模式(Factory Method)
Spring 的 BeanFactory 和 ApplicationContext 是典型的 工厂模式应用(更准确地说,是简单工厂的变体)。
不直接new对象,而是通过工厂来获取
-
目的:定义一个创建对象的接口,但让子类决定序列化哪一个类
-
应用场景:日志记录器、不同数据库驱动的创建
javaApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); MyService service = context.getBean(MyService.class); // 工厂方法Spring IOC容器本质就是一个工厂,负责创建管理Bean不需要手动new,通过
getBean()或依赖注入来获取,实现创建域使用的解耦
代理模式(Proxy Pattern)
实现AOP
通过代理对象,在不修改原类的情况下增强功能
java
@Service
public class UserService {
@Transactional // Spring 会为这个方法生成代理,加入事务控制
public void saveUser() { ... }
}
Spring会根据情况选择:
- JDK动态代理(基于接口)
- CGLIB代理(基于子类)
补充说明:
如果目标类实现了接口 → 默认使用 JDK 动态代理
如果目标类没有实现接口 → 使用 CGLIB 代理 (可通过配置强制使用 CGLIB)
(观察者模式)------事件驱动
虽然有时被误称为'生产-消费',但 Spring 的事件机制本质上是 观察者模式,而非基于队列的生产-消费者模型。
在Spring中更准确地体现为事件监听机制,为了实现组件间的松耦合通信
java
// 定义事件
public class UserRegisteredEvent extends ApplicationEvent { ... }
// 发布事件
applicationContext.publishEvent(new UserRegisteredEvent(user));
// 监听事件
@Component
public class EmailListener {
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
// 发邮件
}
}
Spring 提供了基于观察者模式的事件机制。通过
publishEvent()发布事件,多个监听器可以异步或同步响应,实现模块解耦。比如用户注册后触发邮件发送、积分增加等操作。