向Spring框架学习设计模式

简介: 设计模式是大师们总结的编码范式,用于提升代码的扩展性以及优雅性。对于一个研发人员来说,能否写出一手让人点赞的代码,很大程度上取决于我们对于设计模式的落地使用。那么对于一些初学者来说,怎么才能以最快的方式来学习和理解设计模式呢?个人觉得比较好的方式是通过优秀的开源框架来进行学习,这些开源框架中大量使用了设计模式来进行功能扩展。本文主要分析下最常用的Spring框架中蕴含了哪些设计模式以及设计思想。

引言

设计模式是大师们总结的编码范式,用于提升代码的扩展性以及优雅性。对于一个研发人员来说,能否写出一手让人点赞的代码,很大程度上取决于我们对于设计模式的落地使用。那么对于一些初学者来说,怎么才能以最快的方式来学习和理解设计模式呢?个人觉得比较好的方式是通过优秀的开源框架来进行学习,这些开源框架中大量使用了设计模式来进行功能扩展。本文主要分析下最常用的Spring框架中蕴含了哪些设计模式以及设计思想。

模版模式

顾名思义,模板模式就是根据制定的模板来创建实力对象的过程,可以这么理解,就是模版是一个印章,通过印章可以形成多个盖章。下面我们来看下Spring是如何使用模板模式的。


Spring提供的数据库访问的模板类JdbcTemplate,它就是使用了模板的设计模式。它对核心思想就是将业务流程固定化,比如数据库连接的获取,数据库连接的关闭等,然后将变化的部分交由子类或者回调函数实现。

public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
...
 @Nullable
    public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException {
        Assert.notNull(psc, "PreparedStatementCreator must not be null");
        Assert.notNull(action, "Callback object must not be null");
        if (this.logger.isDebugEnabled()) {
            String sql = getSql(psc);
            this.logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));
        }
    //固化流程1:获取connection
        Connection con = DataSourceUtils.getConnection(this.obtainDataSource());
        PreparedStatement ps = null;
        Object var13;
        try {
          //固化流程2:获取PrepareStatement
            ps = psc.createPreparedStatement(con);
            this.applyStatementSettings(ps);
            T result = action.doInPreparedStatement(ps);
            this.handleWarnings((Statement)ps);
            var13 = result;
        } catch (SQLException var10) {
            if (psc instanceof ParameterDisposer) {
                ((ParameterDisposer)psc).cleanupParameters();
            }
            String sql = getSql(psc);
            psc = null;
            //固化流程3:关闭Statement
            JdbcUtils.closeStatement(ps);
            ps = null;
            //固化流程4:关闭Connection
            DataSourceUtils.releaseConnection(con, this.getDataSource());
            con = null;
            throw this.translateException("PreparedStatementCallback", sql, var10);
        } finally {
            if (psc instanceof ParameterDisposer) {
                ((ParameterDisposer)psc).cleanupParameters();
            }
            JdbcUtils.closeStatement(ps);
            DataSourceUtils.releaseConnection(con, this.getDataSource());
        }
        return var13;
    }
...
}

观察者模式

我们都知道观察者模式在实际都工作中属于比较常用都设计模式。简单来说就是当一个对象当状态发生变化时,监视该对象的主体改变其行为的设计模式就是观察者模式。举个日常生活中的例子,比如你女朋友下班回家,我们就要观察女朋友的心情是怎样的。如果心情很好,那么我们可以放轻松各种开玩笑。如果女朋友心情不好,那就要谨言慎行,避免女朋友把上班的火撒在你自已身上。四个字来说就是要察言观色。

image.png

那么在Spring中框架中是如何实现观察这模式的呢?我们来一起看下。在Spring 中观察者模式主要包含了三部分:Event 事件、Listener 监听者、Publisher 发送者。他们之间的关系可以参考下图来看,Event 事件对应女朋友的心情,Publisher 发送者对应你女朋友,Listener 监听者对应弱小的你。

image.png

有了以上对于观察者模式的理解,我们可以看下代码:

// Event事件
public class GFMoodEvent extends ApplicationEvent 
{ 
  private String message; 
  public GFMoodEvent(Object source, String message) 
  { 
    super(source); 
  }
  public String getMessage() { 
    return this.message; 
  }
 }
 // Listener监听者
 @Component
 public class GFMoodListener implements ApplicationListener 
 { 
  @Override 
  public void onApplicationEvent(GFMoodEvent gFMoodEvent) 
  { 
    String message = gFMoodEvent.getMessage();  
    System.out.println(message); 
    }}
 // Publisher发送者
 @Component
 public class GFMoodPublisher { 
  @Autowired 
  private ApplicationContext applicationContext; 
  public void publishEvent(GFMoodEvent gFMoodEvent) { 
    this.applicationContext.publishEvent(gFMoodEvent); 
    }
  }

在传统的设计模式之中,观察者需要注册到被被观察者当中,这样才可以真正实现状态变化感知。那么在上述Spring的观察者模式中,我们好像没有看到,观察者注册到哪里。那么实际上,我们的观察者是注册到了ApplicationContext应用上下文中。ApplicationContext是Spring的顶级接口,负责提供应用启动、运行时的上下文信息。AbstractApplicationContext是其具体的实现,对应的发布事件相关的代码如下所示:

public abstract class AbstractApplicationContext extends DefaultResourceLoader
    implements ConfigurableApplicationContext {
    ...
  @Override
  public void publishEvent(ApplicationEvent event) {
    publishEvent(event, null);
  }
  @Override
  public void publishEvent(Object event) {
    publishEvent(event, null);
  }
  protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");
    // Decorate event as an ApplicationEvent if necessary
    ApplicationEvent applicationEvent;
    if (event instanceof ApplicationEvent) {
      applicationEvent = (ApplicationEvent) event;
    }
    else {
      applicationEvent = new PayloadApplicationEvent<>(this, event);
      if (eventType == null) {
        eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
      }
    }
    // Multicast right now if possible - or lazily once the multicaster is initialized
    if (this.earlyApplicationEvents != null) {
      this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
      getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }
    // Publish event via parent context as well...
    if (this.parent != null) {
      if (this.parent instanceof AbstractApplicationContext) {
        ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
      }
      else {
        this.parent.publishEvent(event);
      }
    }
  }
    ...
}

适配器模式

所谓适配器模式,按照我的理解其实就是一种转换接口,将两种并不兼容的接口能够实现协调工作。如下图所示,充电插座上面的点并不能直接给手机充电,但是如果我们在手机与充电插座之间通过充电器进行一层转换,那么充电插座的电就可以被转化为为手机充电的电流大小以及电压大小了。

image.png

我们再看下Spring框架中是如何使用适配器模式的。我们都知道SpringMVC是用来处理用户请求的,在SpringMVC框架中,有各种各样的Controller,如果没有HandlerAdapter会怎么样。每当有个新的类型的Controller就需要hard code来进行编码添加新的Controller处理方法来应对。但是这样的处理方式实是不容易维护。因此需要引入适配器模式,对扩展开放。

public interface HandlerAdapter {
    boolean supports(Object var1);
    @Nullable
    ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
    long getLastModified(HttpServletRequest var1, Object var2);
}

实现该接口的适配器每一个Controller都有一个适配器与之对应,这样就算有对应新增类型的Controller,我们只要新增对应的adpeter就可以了,大大增强了代码对扩展性。

image.png

总结

实际上Spring框架中涉及到的设计模式还有很多,本文只是拣出来比较常见的几种设计模式进行阐述。我们在阅读Spring框架源码的过程中,一方面需要学习下框架的设计思想,另一方面就需要看看框架中是如何使用各种设计模式来满足对扩展开放、对修改关闭的设计原则的。

相关文章
|
1月前
|
XML 安全 Java
|
2月前
|
缓存 NoSQL Java
什么是缓存?如何在 Spring Boot 中使用缓存框架
什么是缓存?如何在 Spring Boot 中使用缓存框架
52 0
|
2月前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
3月前
|
Java API 数据库
Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐
本文通过在线图书管理系统案例,详细介绍如何使用Spring Boot构建RESTful API。从项目基础环境搭建、实体类与数据访问层定义,到业务逻辑实现和控制器编写,逐步展示了Spring Boot的简洁配置和强大功能。最后,通过Postman测试API,并介绍了如何添加安全性和异常处理,确保API的稳定性和安全性。
57 0
|
9天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
4天前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
28 13
|
16天前
|
IDE Java 测试技术
互联网应用主流框架整合之Spring Boot开发
通过本文的介绍,我们详细探讨了Spring Boot开发的核心概念和实践方法,包括项目结构、数据访问层、服务层、控制层、配置管理、单元测试以及部署与运行。Spring Boot通过简化配置和强大的生态系统,使得互联网应用的开发更加高效和可靠。希望本文能够帮助开发者快速掌握Spring Boot,并在实际项目中灵活应用。
34 5
|
27天前
|
缓存 Java 数据库连接
Spring框架中的事件机制:深入理解与实践
Spring框架是一个广泛使用的Java企业级应用框架,提供了依赖注入、面向切面编程(AOP)、事务管理、Web应用程序开发等一系列功能。在Spring框架中,事件机制是一种重要的通信方式,它允许不同组件之间进行松耦合的通信,提高了应用程序的可维护性和可扩展性。本文将深入探讨Spring框架中的事件机制,包括不同类型的事件、底层原理、应用实践以及优缺点。
62 8
|
2月前
|
存储 Java 关系型数据库
在Spring Boot中整合Seata框架实现分布式事务
可以在 Spring Boot 中成功整合 Seata 框架,实现分布式事务的管理和处理。在实际应用中,还需要根据具体的业务需求和技术架构进行进一步的优化和调整。同时,要注意处理各种可能出现的问题,以保障分布式事务的顺利执行。
74 6
|
2月前
|
Java 数据库连接 数据库
不可不知道的Spring 框架七大模块
Spring框架是一个全面的Java企业级应用开发框架,其核心容器模块为其他模块提供基础支持,包括Beans、Core、Context和SpEL四大子模块;数据访问及集成模块支持数据库操作,涵盖JDBC、ORM、OXM、JMS和Transactions;Web模块则专注于Web应用,提供Servlet、WebSocket等功能;此外,还包括AOP、Aspects、Instrumentation、Messaging和Test等辅助模块,共同构建强大的企业级应用解决方案。
102 2