探究 Spring 框架中使用的设计模式

前言

  Spring 是 Java 领域中最流行的应用程序开发框架之一,它为 Java 程序员们提供了很多强大的功能和工具,以帮助开发出更高效、更健壮、更可维护的应用系统。在 Spring 的源码实现过程中,借鉴和运用了许多经典的设计模式,这些模式可以帮助我们更好地理解 Spring 的设计和实现思路。本文将介绍 Spring 框架内部使用的一些重要的设计模式,以及它们的应用和好处。

工厂模式

  工厂模式是一种常用的创建型设计模式,它将对象的创建过程封装在一个单独的类(即工厂类)中,并由工厂类来负责生成需要的对象。这种方式可以有效地避免创建对象时的重复代码,同时也可以更好地控制对象的创建过程。在 Spring 框架中,BeanFactory 就是一个典型的工厂类,它负责创建和管理应用中所有的 Bean 实例。

  BeanFactory 接口定义了一系列方法,用于获取、创建和销毁 Bean 实例。其中,getBean(String name) 方法就是一个典型的工厂方法,它接受一个字符串类型的参数 name,表示要获取的 Bean 实例的名称,然后通过配置文件或注解等方式来确定具体的 Bean 实现类,最终返回对应的 Bean 实例。使用工厂模式可以帮助我们更好地组织和管理应用中的对象,提高代码的重用性和可维护性。

源码解析

@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}

protected T doGetBean(final String name, final Class requiredType, final Object[] args,
boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;

// 1. 尝试从 singleton 缓存中获取指定名称的 singleton 实例
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
    if (logger.isTraceEnabled()) {
        if (isSingletonCurrentlyInCreation(beanName)) {
            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                    "' that is not fully initialized yet - a consequence of a circular reference");
        }
        else {
            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
        }
    }
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
    // 2. 处理单例缓存中不存在指定名称的 singleton 实例的情况
    if (isPrototypeCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }

    // 3. 将当前 beanName 标记为正在创建中
    beforeSingletonCreation(beanName);

    try {
        // 4. 获取指定名称的 BeanDefinition 对象,如果不存在则抛出 NoSuchBeanDefinitionException 异常
        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        checkMergedBeanDefinition(mbd, beanName, args);

        // 5. 进行 factory-bean 的处理和初始化方法的合并
        String[] dependsOn = mbd.getDependsOn();
        if (dependsOn != null) {
            for (String dep : dependsOn) {
                if (isDependent(beanName, dep)) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                }
                registerDependentBean(dep, beanName);
                try {
                    getBean(dep);
                }
                catch (NoSuchBeanDefinitionException ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                }
            }
        }

        // 6. 在缓存中删除当前 beanName 对应的 singleton 实例,以确保每次都能够重新创建实例
        if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
                try {
                    return createBean(beanName, mbd, args);
                }
                catch (BeansException ex) {
                    // 7. 创建失败时需要在缓存中清除当前缓存的 singleton 实例
                    destroySingleton(beanName);
                    throw ex;
                }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
        else if (mbd.isPrototype()) {
            // 8. 处理 prototype 类型的 Bean 实例
            Object prototypeInstance = null;
            try {
                beforePrototypeCreation(beanName);
                prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
                afterPrototypeCreation(beanName);
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
        }
        else {
            String scopeName = mbd.getScope();
            final Scope scope = this.scopes.get(scopeName);
            if (scope == null) {
                throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
            }
            try {
                Object scopedInstance = scope.get(beanName, () -> {
                    beforePrototypeCreation(beanName);
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        // 9. 创建失败时需要在删除当前 scope 中缓存的实例
                        if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                            destroyScopedBean(beanName);
                        }
                        throw ex;
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                });
                bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
            catch (IllegalStateException ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                        ex);
            }
        }
    }
    finally {
        // 10. 创建 Bean 实例完成后取消当前 beanName 的创建标记
        afterSingletonCreation(beanName);
    }
}

// 11. 兼容性处理
if (requiredType != null && !requiredType.isInstance(bean)) {
    return getTypeConverter().convertIfNecessary(bean, requiredType);
}
return (T) bean;

}

代理模式

  代理模式是一种常用的结构型设计模式,它允许一个对象(即代理类)作为另一个对象(即被代理对象)的替身,以控制对被代理对象的访问。在 Spring 框架中,AOP(面向切面编程)就是典型的代理模式的应用。通过使用 AOP,Spring 能够在运行时将某些通用的行为(例如事务、日志记录等)动态地织入到应用程序中的某个切面里,从而实现更好的解耦合和可维护性。

  Spring 框架中使用了两种代理模式:JDK 动态代理和 CGLIB 代理。JDK 动态代理是基于 Java 反射机制实现的,它只能代理接口的实现类,不支持非接口的类。而 CGLIB 代理是基于字节码生成技术实现的,它可以代理任意的类,但需要依赖于字节码生成技术,所以效率上不如 JDK 动态代理。

单例模式

  单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。在 Spring 框架中,单例模式扮演了非常重要的角色,它是 Spring 容器中 Bean 的默认作用域,确保了应用中某些关键对象的唯一性和全局可见性。

  Spring 框架通过一个叫做 SingletonBeanRegistry 的接口来实现单例模式的管理。这个接口定义了一系列方法,如 registerSingleton()、getSingleton() 和 containsSingleton() 等,用于注册、获取和判断单例实例。Spring 容器在初始化时会自动创建并缓存所有的单例 Bean 实例,之后所有的 getBean() 请求都会从缓存中获取实例,以确保每个对象的唯一性和全局可见性。

观察者模式

  观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,即当一个对象的状态发生改变时,所有的依赖对象都会收到通知并自动更新。在 Spring 框架中,事件驱动模型就是典型的观察者模式的应用。通过使用事件驱动模型,Spring 能够实现对象之间的松耦合和模块化设计。

  Spring 框架中的事件驱动模型由 ApplicationEvent 和 ApplicationListener 两个接口组成,其中 ApplicationEvent 定义了应用程序中所有事件的基类,而 ApplicationListener 则定义了所有事件监听器的基本方法。使用观察者模式可以将各个模块或组件之间的依赖关系降至最低,从而提高了应用的灵活性和可维护性。

总结

  Spring 框架是一个非常重要的 Java 应用程序开发框架,它运用了许多经典的设计模式来实现各种功能和工具。在本文中,我们介绍了 Spring 中使用的一些重要的设计模式,包括工厂模式、代理模式、单例模式和观察者模式。这些模式不仅能够帮助我们更好地理解 Spring 的设计和实现思路,还能够提高代码的复用性、可维护性和扩展性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值