当前位置: 首页 > news >正文

spring常用的设计模式

一、单例模式        

         首先要说的便是单例模式,单例模式大家都知道目的是为了确保一个类只有一个实例,在spring中,我们就拿最典型的三级缓存来说明吧。

         我们看下spring中DefaultSingletonBeanRegistry类中的getSingleton方法的源码,如下所示,相信看了代码中的详细说明可以很清楚的知道单例模式在spring中用三级缓存解决循环依赖的用处了。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // Quick check for existing instance without full singleton lock
    //singletonObjects这个是第一级缓存,这个缓存里面存放的是已经准备就绪的bean
    //先根据beanName从第一级缓存中找,如果找到直接返回第一级缓存中缓存的bean。
    Object singletonObject = this.singletonObjects.get(beanName);
    //如果第一级缓存中没有找到对应的实例,并且发现这个bean目前正在创建中,还没有创建完成
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        //这里就从第二级缓存中尝试获取,第二级缓存缓存的是半成品bean(实例化已完成但还未完成
        //初始化),如果第二级缓存中有这个bean,那么就直接返回半成品bean
        singletonObject = this.earlySingletonObjects.get(beanName);
        //如果第二级缓存里面也没有这个bean,并且允许早期引用(主要是为了解决循环依赖)
        if (singletonObject == null && allowEarlyReference) {
            //前两级缓存都没有,就要使用第三级缓存了,但使用前要先加锁,对第一级缓存加锁
            synchronized(this.singletonObjects) {
                // Consistent creation of early reference within full singleton lock
                //加锁成功后,为了避免重复创建对象,再次尝试从第一级缓存获取,有就直接返回
                singletonObject = this.singletonObjects.get(beanName);
                //如果第一级缓存中依然没有这个bean
                if (singletonObject == null) {
                    //那么就接着从第二级缓存中尝试获取,有就直接返回
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    //如果发现第二级缓存中还没有
                    if (singletonObject == null) {
                        //接着就从第三级缓存中获取到由创建bean所需元素组成的ObjectFactory
                        //(这是一个lambda表达式)
                        ObjectFactory <? > singletonFactory = this.singletonFactories.get(beanName);
                        //如果第三级缓存中找到了这个bean进行实例化的信息
                        if (singletonFactory != null) {
                            //执行第三级缓存中的lambda表达式,从而创建bean实例
                            singletonObject = singletonFactory.getObject();
                            //将新创建的实例放入第二级缓存中(第二级缓存存的就是实例化完,
                            //但还未初始化的半成品)
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            //放入第二级缓存的同时,从第三级缓存中删掉该bean,这么做也是为
                            //了避免重复创建bean的实例。也就是说第二级缓存和第三级缓存是
                            //互斥的,而且都是在加锁的场景下操作的,这也就是为啥第一级缓存
                            //用的是concurrenthashmap,而第二、第三级缓存用的是普通
                            //的hashmap,因为人家都前提加锁了,再用线程安全的map也没啥意义。
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
        }
    }
    return singletonObject;
}

二、工厂模式

         先来简单说下什么是工厂模式,工厂模式是将对象的创建交由统一的工厂类来生成对象,避免直接在代码中硬编码具体类的实例化过程。它适用于需要灵活管理对象创建的场景,例如根据条件动态创建不同类型对象,隐藏对象创建的复杂性等。

       那么在spring中,工厂模式最典型的当然要数自动创建bean对象了,我们在类上加上@Component注解或@Resource等注解,spring就会帮我们去自动创建bean对象,不需要我们再手动专门new一个对象出来,下面我举spring中创建bean对象的一个关键方法来说明

       我们先来看下AbstractBeanFactory工厂类,也叫抽象工厂类,这个工厂类只提供了一个抽象方法,createBean,具体创建bean的过程由对应的子类来实现。

/**
 * Create a bean instance for the given merged bean definition (and arguments).
 * The bean definition will already have been merged with the parent definition
 * in case of a child definition.
 * <p>All bean retrieval methods delegate to this method for actual bean creation.
 * @param beanName the name of the bean
 * @param mbd the merged bean definition for the bean
 * @param args explicit arguments to use for constructor or factory method invocation
 * @return a new instance of the bean
 * @throws BeanCreationException if the bean could not be created
 */
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException;

          AbstractAutowireCapableBeanFactory是AbstractBeanFactory的子类,这个从名字上就可以知道它也是一个工厂类,是管理spring bean生命周期的核心实现类,属于IoC容器的底层基础设施。它直接负责Bean的实例化、属性填充(依赖注入)、初始化方法调用等关键操作,是Spring实现依赖注入(DI)和自动装配(Autowiring)的核心引擎,如下图所示。

        这个类就实现了父类createBean的方法,如下所示,我们不做深入研究源码,而是重点看工厂模式的运用,这个方法最下面的那个try代码块中有一行是Object beanInstance = doCreateBean(beanName, mbdToUse, args);这是真正去创建bean对象的方法。

/**
 * Central method of this class: creates a bean instance,
 * populates the bean instance, applies post-processors, etc.
 * @see #doCreateBean
 */
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {

    if (logger.isTraceEnabled()) {
        logger.trace("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;

    // Make sure bean class is actually resolved at this point, and
    // clone the bean definition in case of a dynamically resolved Class
    // which cannot be stored in the shared merged bean definition.
    Class <? > resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    // Prepare method overrides.
    try {
        mbdToUse.prepareMethodOverrides();
    } catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
    }

    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    } catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
            "BeanPostProcessor before instantiation of bean failed", ex);
    }

    try {
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isTraceEnabled()) {
            logger.trace("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        // A previously detected exception with proper bean creation context already,
        // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
        throw ex;
    } catch (Throwable ex) {
        throw new BeanCreationException(
            mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    }
}

            doCreateBean方法源码如下,下面实例化、属性填充、初始化的地方我都用中文加了注释,也就是执行完这个方法后,我们写在项目里的实体类就被spring自动给创建好了,这省去了我们非常多的麻烦,让我们可以专心关注具体业务,而不用操心繁杂的bean创建过程。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        //这行代码是去创建bean的实例(但还未填充属性也未初始化)
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    Object bean = instanceWrapper.getWrappedInstance();
    Class <? > beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    // Allow post-processors to modify the merged bean definition.
    synchronized(mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            } catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Post-processing of merged bean definition failed", ex);
            }
            mbd.postProcessed = true;
        }
    }

    // Eagerly cache singletons to be able to resolve circular references
    // even when triggered by lifecycle interfaces like BeanFactoryAware.
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isTraceEnabled()) {
            logger.trace("Eagerly caching bean '" + beanName +
                "' to allow for resolving potential circular references");
        }
        addSingletonFactory(beanName, () - > getEarlyBeanReference(beanName, mbd, bean));
    }

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        //这行代码是要填充bean属性(也就是依赖注入)
        populateBean(beanName, mbd, instanceWrapper);
        //这行代码是要对bean进行初始化,这里面包括初始化前Aware接口回调,初始化前置处理、初始化、初始化后置处理等动作
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    } catch (Throwable ex) {
        if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
            throw (BeanCreationException) ex;
        } else {
            throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
        }
    }

    if (earlySingletonExposure) {
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set < String > actualDependentBeans = new LinkedHashSet < > (dependentBeans.length);
                for (String dependentBean: dependentBeans) {
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
                }
                if (!actualDependentBeans.isEmpty()) {
                    throw new BeanCurrentlyInCreationException(beanName,
                        "Bean with name '" + beanName + "' has been injected into other beans [" +
                        StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                        "] in its raw version as part of a circular reference, but has eventually been " +
                        "wrapped. This means that said other beans do not use the final version of the " +
                        "bean. This is often the result of over-eager type matching - consider using " +
                        "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
                }
            }
        }
    }

    // Register bean as disposable.
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    } catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
}

三、代理模式

        首先说下什么是代理模式,它是通过创建一个代理对象来控制对原始对象(目标对象)的访问。代理对象在客户端和目标对象之间充当中介,可以在不修改目标对象代码的前提下,增强其功能(如添加日志、权限控制、加缓存等)。

        在spring中用到的代理分为两类,一类是JDK动态代理,这种针对的是是接口,如果目标对象实现了接口,那么就使用JDK动态代理。另一类是CGLIB代理,这种是目标对象没有实现接口。

        我们举个例子就比较清楚了,像下面这样,UserServiceImpl实现了UserService的接口,那么这种场景,spring就使用JDK动态代理来生成代理对象。

public interface UserService {
    void saveUser(User user);
}

@Service
public class UserServiceImpl implements UserService {
    @Override
    public void saveUser(User user) {
        // 数据库操作
    }
}

          而比如像我们下面的这个Student类,它只是加了@Component注解,而没有实现具体的接口,因此这个类在spring中就以CGLIB的代理模式创建代理对象。

package com.example.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Student {

    @Autowired
    private Cource cource;

    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

}

四、策略模式

         首先说下什么是策略模式,策略模式是一种行为型设计模式,它定义了一系列算法(策略),并将每个算法封装成独立的类,使得它们可以相互替换。策略模式的核心思想是将算法的使用和算法的实现解耦,客户端可以根据需求动态选择不同的策略,而无需修改原有代码。

       那么在spring中哪些场景用到了策略模式呢?下面我们举两个最常用的例子

第一个:创建代理对象

策略接口:AopProxy

具体策略:

        JdkDynamicAopProxy:基于JDK动态代理生成接口代理。

       CglibAopProxy:基于CGLIB生成子类代理。

第二个例子:资源加载(ResourceLoader)

策略接口:ResourceLoader

具体策略:

       ClassPathResource:加载类路径资源。

       FileSystemResource:加载文件系统资源。

       UrlResource:加载网络资源(URL)

应用场景:根据资源路径前缀(如classpath:、file:)选择资源加载策略。

五、观察者模式

       首先说下什么是观察者模式,观察者模式是一种行为型设计模式,用于定义对象间的一对多依赖关系。当一个对象(称为主题或被观察者)的状态发生改变时,所有依赖它的对象(称为观察者)都会自动收到通知并更新自身状态。该模式的核心思想是解耦主题与观察者,使它们可以独立变化和扩展。

        观察者模式在spring中的应用,举个例子:bean的初始化与销毁回调

场景描述:Bean的初始化(如@PostConstruct)和销毁(如@PreDestry)通过事件机制触发,监听器执行回调逻辑。

源码实现:

        事件类型:BeanInitializationEventBeanDestructionEvent(内部事件,非直接暴露)。

        处理逻辑:InitDestroyAnnotationBeanPostProcessor 监听 Bean 的创建过程,解析 @PostConstruct 和 @PreDestroy 注解。

六、模板模式

        模板模式是一种行为型设计模式,用于定义一个操作中算法的骨架,将某些步骤的具体实现延迟到子类中去完成。它允许子类在不改变算法结构的情况下,重新定义某些步骤的实现。

       在spring中,使用模板模式的例子,像下面这个类,commit方法定义了事务的提交流程,提供了一个抽象方法doCommit(),交由实现具体的事务提交逻辑。

public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager {
    @Override
    public final void commit(TransactionStatus status) {
        // 固定流程:检查状态 → 处理回滚 → 触发同步 → 提交
        if (status.isCompleted()) {
            throw new IllegalTransactionStateException("事务已提交或回滚");
        }
        DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
        if (defStatus.isLocalRollbackOnly()) {
            processRollback(defStatus, false);
            return;
        }
        if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
            processRollback(defStatus, true);
            return;
        }
        processCommit(defStatus);  // 调用具体提交逻辑
    }

    // 抽象方法,由子类实现
    protected abstract void doCommit(DefaultTransactionStatus status);
}

          子类DataSourceTransactionManager为例,实现了doCommit方法,同时又可以利用父类的commit公共方法,这种就是模板模式的应用。

public class DataSourceTransactionManager extends AbstractPlatformTransactionManager {
    @Override
    protected void doCommit(DefaultTransactionStatus status) {
        Connection con = status.getTransaction().getConnectionHolder().getConnection();
        try {
            con.commit();  // 实际提交事务(JDBC 实现)
        } catch (SQLException ex) {
            throw new TransactionSystemException("提交失败", ex);
        }
    }
}

相关文章:

  • MySQL基础命令
  • 【蓝桥杯】15届java研究生组E砍柴
  • UIMeter-UI自动化软件(产品级)
  • 2025前端面试题
  • C++中std::move()的正确使用相关例子
  • C语言个人笔记
  • 前端面试总结3
  • Lumion 与 Enscape 怎么选?附川翔云电脑适配指南
  • 在3ds Max中视口显示为黑色或深灰色
  • leetcode68.左右文本对齐
  • 《DeepSeek RAG 增强检索知识库系统》Ollama RAG 知识库上传、解析和验证之四
  • mysql 禁止 读 某个 表
  • 第18章:基于Global Context Vision Transformers(GCTx_unet)网络实现的oct图像中的黄斑水肿和裂孔分割
  • 【Audio开发三】音频audio中帧frameSize ,周期大小periodsize,缓冲区buffer原理详解以及代码流程分析
  • 《嵌入式开发实战:基于Linux串口的LED屏显系统设计与实现》
  • Clickhouse试用单机版部署
  • 【完整可用】使用openhtmltopdf生成PDF(带SVG)
  • 策略模式结合模板方法模式
  • Go语言入门-反射4(动态构建类型)
  • PyCharm Community社区版链接WSL虚拟环境
  • 邯郸做网站熊掌号/网络营销的方式有十种
  • 营销类的网站/微营销是什么
  • 长春网站seo哪家好/大量微信群推广代发广告
  • 做网站注册页面/营销网站建站公司
  • 做百度移动网站/营销型网站建设方案
  • 简单的英文网站模板/郑州今日头条