Spring用到了哪些設計模式?

👉 這是一個或許對你有用的社群
🐱 一對一交流/面試小冊/簡歷最佳化/求職解惑,歡迎加入芋道快速開發平臺知識星球。下面是星球提供的部分資料:
👉這是一個或許對你有用的開源專案
國產 Star 破 10w+ 的開源專案,前端包括管理後臺 + 微信小程式,後端支援單體和微服務架構。
功能涵蓋 RBAC 許可權、SaaS 多租戶、資料許可權、商城、支付、工作流、大屏報表、微信公眾號、ERPCRMAI 大模型等等功能:
  • Boot 多模組架構:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • Cloud 微服務架構:https://gitee.com/zhijiantianya/yudao-cloud
  • 影片教程:https://doc.iocoder.cn

今天和大夥總結下 Spring 中都用到了哪些設計模式。
Spring 作為企業級應用開發中最受歡迎的框架之一,其內部廣泛採用了多種設計模式,使得框架不僅功能強大,而且具有很高的可擴充套件性和靈活性。是我們學習設計模式不可多得的優質材料。

一 單例模式 (Singleton Pattern)

在 Spring 框架中,單例模式被廣泛應用於各種元件和工具類,以確保在整個應用程式生命週期中,這些物件只有一個例項,從而節省記憶體和提高效能。
這裡給大家舉幾個常見的 Spring 中單例的應用。
BeanFactory
BeanFactory 是 Spring 框架中的另一個核心介面,它負責建立和管理 bean。BeanFactory 的實現類(如 DefaultListableBeanFactory)也通常以單例模式存在。
原始碼示例 :
publicclassDefaultListableBeanFactoryextendsAbstractAutowireCapableBeanFactoryimplementsConfigurableListableBeanFactoryBeanDefinitionRegistrySerializable{privatefinal Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);@Overridepublic Object getSingleton(String beanName){return getSingleton(beanName, true);    }@Overridepublic Object getSingleton(String beanName, boolean allowEarlyReference){        Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {                singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {                    singletonObject = getEarlyBeanReference(beanName, mbd, bean);                }            }        }return (singletonObject != NULL_OBJECT ? singletonObject : null);    }}
DefaultListableBeanFactory 本身的初始化邏輯如下:

可以看到,如果存在 BeanFactory,則先銷燬,再建立新的 BeanFactory。
基於 Spring Boot + MyBatis Plus + Vue & Element 實現的後臺管理系統 + 使用者小程式,支援 RBAC 動態許可權、多租戶、資料許可權、工作流、三方登入、支付、簡訊、商城等功能
  • 專案地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 影片教程:https://doc.iocoder.cn/video/

二 工廠模式 (Factory Pattern)

工廠模式提供了一種建立物件的介面,但讓子類決定例項化哪一個類。Spring 中的 BeanFactory 介面及其實現類(如 DefaultListableBeanFactory)就是工廠模式的應用。透過這些工廠,我們可以方便地管理和建立bean例項。

Spring 原始碼案例

publicinterfaceBeanFactory{Object getBean(String name)throws BeansException;}publicclassDefaultListableBeanFactoryextendsAbstractAutowireCapableBeanFactoryimplementsConfigurableListableBeanFactoryBeanDefinitionRegistrySerializable{@Overridepublic Object getBean(String name)throws BeansException {return doGetBean(name, nullnullfalse);    }}
DefaultListableBeanFactory 是 BeanFactory 的一個實現,負責建立和管理 bean 的例項。
基於 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現的後臺管理系統 + 使用者小程式,支援 RBAC 動態許可權、多租戶、資料許可權、工作流、三方登入、支付、簡訊、商城等功能
  • 專案地址:https://github.com/YunaiV/yudao-cloud
  • 影片教程:https://doc.iocoder.cn/video/

三 原型模式 (Prototype Pattern)

原型模式透過複製現有物件來建立新物件,而無需知道任何建立細節。在 Spring 中,我們可以透過設定 bean 的 scope 屬性為 prototype 來實現每次請求時都建立一個新的 bean 例項。

Spring 原始碼案例

<beanid="exampleBean"class="com.example.ExampleBean"scope="prototype"/>
這個配置表示每次請求 exampleBean 時,都會建立一個新的例項。

四 模板方法模式 (Template Method Pattern)

在 Spring 框架中,模板方法模式被廣泛應用於多個模組,以提供靈活且可擴充套件的解決方案。模板方法模式的核心思想是定義一個操作中的演算法骨架,而將一些步驟延遲到子類中實現。這樣,子類可以不改變演算法結構的情況下重新定義演算法的某些特定步驟。
這裡和大家分享兩個經典的模版方法模式:JdbcTemplate 和 PlatformTransactionManager。
JdbcTemplate
JdbcTemplate 是 Spring JDBC 模組中的一個核心類,它使用模板方法模式來簡化資料庫操作。
模板方法 :
  • execute:執行 SQL 語句的基本方法。
  • query:查詢資料庫的基本方法。
  • update:執行更新操作的基本方法。
具體實現 :
  • queryForObject:查詢單個物件。
  • queryForList:查詢列表。
  • batchUpdate:批次更新。
原始碼示例 :
publicabstractclassJdbcOperations{public <T> queryForObject(String sql, RowMapper<T> rowMapper, Object... args)throws DataAccessException {return queryForObject(sql, args, getJdbcOperations().new SingleColumnRowMapper(rowMapper));    }publicintupdate(String sql, PreparedStatementSetter pss)throws DataAccessException {        Assert.notNull(sql, "SQL must not be null");if (logger.isDebugEnabled()) {            logger.debug("Executing SQL update [" + sql + "]");        }        Connection con = DataSourceUtils.getConnection(getDataSource());        PreparedStatement ps = null;try {            ps = con.prepareStatement(sql);            pss.setValues(ps);int rows = ps.executeUpdate();if (logger.isDebugEnabled()) {                logger.debug(rows + " rows affected");            }return rows;        } catch (Throwable ex) {// Handle exceptionthrow translateException("PreparedStatement", sql, ex);        } finally {            JdbcUtils.closeStatement(ps);            DataSourceUtils.releaseConnection(con, getDataSource());        }    }}
PlatformTransactionManager
PlatformTransactionManager 介面定義了事務管理的基本方法,具體的事務管理實現類(如 DataSourceTransactionManager)則提供了具體的實現。
模板方法 :
  • getTransaction:獲取事務。
  • commit:提交事務。
  • rollback:回滾事務。
具體實現 :
  • DataSourceTransactionManager:基於資料來源的事務管理。
  • JtaTransactionManager:基於JTA的事務管理。
原始碼示例 :
publicinterfacePlatformTransactionManager{TransactionStatus getTransaction(TransactionDefinition definition)throws TransactionException;voidcommit(TransactionStatus status)throws TransactionException;voidrollback(TransactionStatus status)throws TransactionException;}publicclassDataSourceTransactionManagerextendsAbstractPlatformTransactionManager{@Overrideprotected TransactionStatus doBegin(Object transaction, TransactionDefinition definition){// 獲取資料庫連線        ConnectionHolder conHolder = (ConnectionHolder) transaction;        Connection con = conHolder.getConnection();// 設定事務隔離級別        Integer previousIsolationLevel = DataSourceUtils.storeIsolationLevelIfNotSet(con, definition.getIsolationLevel());// 開啟事務boolean newTransaction = false;if (!con.getAutoCommit()) {            logger.debug("Not switching JDBC Connection [" + con + "] to manual commit because already manually committed");        } else {            newTransaction = true;if (logger.isDebugEnabled()) {                logger.debug("Switching JDBC Connection [" + con + "] to manual commit");            }            con.setAutoCommit(false);        }// 返回事務狀態returnnew DataSourceTransactionObject(conHolder, previousIsolationLevel, newTransaction);    }}

五 介面卡模式 (Adapter Pattern)

介面卡模式將一個類的介面轉換成客戶希望的另一個介面。SpringMVC 中的 HandlerAdapter 介面及其多個實現類(如 RequestMappingHandlerAdapter)就是介面卡模式的應用,它們負責處理不同型別的控制器方法。

Spring 原始碼案例

publicinterfaceHandlerAdapter{booleansupports(Object handler);ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception;}publicclassRequestMappingHandlerAdapterimplementsHandlerAdapter{@Overridepublicbooleansupports(Object handler){return handler instanceof HandlerMethod;    }@Overridepublic ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return ((HandlerMethod) handler).invokeAndHandle(request, response);    }}
RequestMappingHandlerAdapter 適配了 HandlerMethod 型別的控制器方法,使其能夠處理HTTP請求。

六 裝飾者模式 (Decorator Pattern)

裝飾者模式允許動態地給一個物件新增一些額外的職責。Spring AOP 中的切面實現可以看作是對原有物件的一種裝飾。透過 @Around 註解定義的環繞通知可以在不改變原有業務邏輯的情況下增加額外的功能。

Spring 原始碼案例

publicclassTransactionInterceptorimplementsMethodInterceptor{@Overridepublic Object invoke(MethodInvocation invocation)throws Throwable {// 開始事務        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());try {            Object result = invocation.proceed();            transactionManager.commit(status);return result;        } catch (RuntimeException ex) {            transactionManager.rollback(status);throw ex;        }    }}
TransactionInterceptor 是一個典型的裝飾者模式應用,它在方法呼叫前後添加了事務管理的邏輯。

七 觀察者模式 (Observer Pattern)

觀察者模式定義了物件之間的一對多依賴關係,當一個物件的狀態發生變化時,所有依賴於它的物件都會得到通知並自動更新。Spring  中的 ApplicationEvent 和 ApplicationListener 介面共同實現了觀察者模式。

Spring 原始碼案例

publicinterfaceApplicationListener<EextendsApplicationEvent{voidonApplicationEvent(E event);}publicclassContextRefreshedEventextendsApplicationEvent{publicContextRefreshedEvent(Object source){super(source);    }}publicclassMyApplicationListenerimplementsApplicationListener<ContextRefreshedEvent{@OverridepublicvoidonApplicationEvent(ContextRefreshedEvent event){        System.out.println("Context refreshed!");    }}
MyApplicationListener 監聽了 ContextRefreshedEvent 事件,當上下文重新整理時,會輸出一條訊息。

八 代理模式 (Proxy Pattern)

代理模式為其他物件提供一個代理以控制對這個物件的訪問。Spring AOP 使用動態代理技術(JDK 動態代理或 CGLIB)來實現代理模式。例如,當你在方法上新增事務管理註解 @Transactional 時,Spring 會自動建立一個代理物件來管理事務的開始和結束。

Spring 原始碼案例

publicclassDefaultAopProxyFactoryimplementsAopProxyFactory{@Overridepublic AopProxy createAopProxy(AdvisedSupport config)throws AopConfigException {if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {            Class<?> targetClass = config.getTargetClass();if (targetClass == null) {thrownew AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation.");            }returnnew ObjenesisCglibAopProxy(config);        } else {returnnew JdkDynamicAopProxy(config);        }    }}
DefaultAopProxyFactory 根據配置選擇使用 CGLIB 或 JDK 動態代理來建立代理物件。

九 組合模式 (Composite Pattern)

組合模式允許將物件組合成樹形結構以表示“部分-整體”的層次結構。在 Spring 配置中,可以將多個 bean 組合在一起形成一個複雜的結構。

Spring 原始碼案例

<beans><beanid="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"><propertyname="driverClassName"value="com.mysql.cj.jdbc.Driver"/><propertyname="url"value="jdbc:mysql://localhost:3306/testdb"/><propertyname="username"value="root"/><propertyname="password"value="password"/></bean><beanid="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate"><propertyname="dataSource"ref="dataSource"/></bean></beans>
這個配置檔案中,jdbcTemplate 依賴於 dataSource,形成了一個簡單的組合結構。

十 策略模式 (Strategy Pattern)

策略模式定義了一系列演算法,並將每一個演算法封裝起來,使它們可以互換。Spring 中的 Resource 介面及其多個實現類(如 ClassPathResourceFileSystemResource)就是策略模式的應用,可以根據需要選擇不同的資源訪問方式。

Spring 原始碼案例

publicinterfaceResourceLoader{Resource getResource(String location);}publicclassDefaultResourceLoaderimplementsResourceLoader{@Overridepublic Resource getResource(String location){if (location.startsWith("classpath:")) {returnnew ClassPathResource(location.substring("classpath:".length()));        } else {returnnew FileSystemResource(location);        }    }}
DefaultResourceLoader 根據資源路徑的字首選擇合適的 Resource 實現類。

十一 小結

透過上述案例,我們可以看到 Spring 框架巧妙地運用了多種設計模式,不僅提高了程式碼的複用性和可維護性,還增強了框架的靈活性和擴充套件性。希望這篇文章能幫助大家更好地理解和掌握 Spring 中的設計模式,如果有任何疑問或建議,歡迎在評論區留言交流。

歡迎加入我的知識星球,全面提升技術能力。
👉 加入方式,長按”或“掃描”下方二維碼噢
星球的內容包括:專案實戰、面試招聘、原始碼解析、學習路線。

文章有幫助的話,在看,轉發吧。
謝謝支援喲 (*^__^*)

相關文章