在面试中,“Spring框架用到了哪些设计模式”几乎是必考题。很多人能背出“工厂、单例、代理”几个名字,却说不清它们在源码里到底怎么用的。Spring的本质是一套设计模式的“组合拳”——你每天用的@Autowired背后是工厂模式加单例模式,AOP核心是代理模式的灵活运用,容器事件通知则是观察者模式的经典实现。理解这些模式在Spring中的实战用法,才能真正看懂源码、写出好代码。

一、工厂模式:IOC容器的“Bean生产线”

Spring的核心容器就是一个大工厂。BeanFactory和ApplicationContext是工厂模式的典型应用,负责根据配置或注解创建和管理Bean实例,隐藏了对象创建的细节。

核心接口定义如下:

public interface BeanFactory {
    Object getBean(String name) throws BeansException;
}

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory {
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    
    public Object getBean(String name) {
        Object sharedInstance = getSingleton(name);
        if (sharedInstance != null) return sharedInstance;
        BeanDefinition bd = getBeanDefinition(name);
        return createBean(name, bd);
    }
}

BeanFactory采用延迟加载——使用到某个Bean时才会创建,占用内存更少、启动更快。ApplicationContext则是一次性创建所有Bean,功能更丰富。ApplicationContext作为“超级工厂”,组合了BeanFactory、ResourceLoader等多个工厂的功能,形成层级化工厂体系。

实际开发中,你只需要写@Service或@Component,Spring容器自动帮你创建和管理对象——这就是工厂模式把创建权从业务代码转移到容器的体现。

二、单例模式:Bean默认是“独生子”

Spring中所有Bean默认都是单例的。容器初始化时创建一个实例,之后所有请求都返回同一个对象。DefaultSingletonBeanRegistry通过ConcurrentHashMap加锁保证同一个Bean名只注册一个实例:

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        this.singletonObjects.put(beanName, singletonObject);
    }
}

单例模式避免了重复创建对象的资源浪费,保证全局状态的一致性。但要注意:单例不等于线程安全——如果Bean里写了可变状态变量,线程安全问题需要自己处理。

三、代理模式:AOP的“隐形护卫”

Spring AOP本质就是一套动态代理。它有两种实现方式:JDK动态代理(基于接口)和CGLIB代理(基于子类)。

当你写@Transactional时,Spring在运行时为这个Bean生成代理对象,方法调用前后织入事务逻辑。源码中JdkDynamicAopProxy实现了InvocationHandler,在invoke方法中通过拦截器链增强目标方法。你以为调用的是原方法,其实调用的是代理对象。代理模式让开发者在不修改原始代码的情况下增强对象功能。

四、模板方法模式:“帮你做脏活累活”

Spring里一堆以Template结尾的类——JdbcTemplate、RestTemplate、RedisTemplate——背后都是模板方法模式。父类封装公共流程(获取连接、异常处理、关闭资源),子类或回调实现具体步骤。

以JdbcTemplate为例:

public void execute(final String sql) {
    class ExecuteStatementCallback implements StatementCallback<Object> {
        public Object doInStatement(Statement stmt) throws SQLException {
            stmt.execute(sql);
            return null;
        }
    }
    execute(new ExecuteStatementCallback());
}

你只需要写SQL和处理结果,不用管连接管理和异常处理——模板方法全包了。Spring还在模板方法基础上做了创新,配合回调一起使用。

五、观察者模式:事件驱动的“广播网”

Spring的事件机制是标准的观察者模式。ApplicationEventPublisher发布事件,ApplicationListener监听事件。

使用示例:

@Component
public class MyListener implements ApplicationListener<MyEvent> {
    public void onApplicationEvent(MyEvent event) {
        System.out.println("收到事件:" + event.getMsg());
    }
}

这种松耦合的事件驱动思想广泛用于系统解耦、领域事件发布、状态监听等场景。

六、策略模式:同一问题,多种解法

Spring在实例化Bean时采用了策略模式——可以选择反射或CGLIB两种策略构造类实例。HandlerMapping接口也是策略模式的应用:不同实现类定义不同的请求映射策略,如根据URL路径或请求参数映射。Resource接口的不同实现类针对不同资源文件实现了不同方式的资源获取策略。

七、适配器模式:统一接口的“翻译官”

Spring MVC通过适配器模式将HandlerMapping转换为HandlerAdapter,处理HTTP请求接收与结果返回。适配器让Spring能灵活扩展和集成各种不同组件,而不需要修改这些组件的源代码。

八、装饰器模式:不修改,只增强

Spring中只要见到以Wrapper命名的类,基本都是装饰器模式。例如DelegatingErrorHandlingRunnable对Runnable进行了错误处理能力的增强。

总结:设计模式不是理论,是Spring的“源代码”

学习Spring中的设计模式,不是为了“找模式而看源码”,而是“通过源码理解模式的适用场景和演化逻辑”。Spring大量使用了工厂、代理、模板方法等模式,不是生搬硬套,而是根据具体场景灵活变通。理解这些模式在Spring源码中的实战用法,是打通“理论→源码→实战”的关键一步。