Spring中涉及的设计模式总结

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

Spring中涉及的设计模式总结

1.简单工厂(非23种设计模式中的一种)

实例化阶段主要是通过反射或者CGLIB对bean进行实例化在这个阶段Spring又给我们暴露了很多的扩展点

  • 实现方式BeanFactory。Spring中的BeanFactory就是简单工厂模式的体现根据传入一个唯一的标识来获得Bean对象但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。

  • 实质由一个工厂类根据传入的参数动态决定应该创建哪一个产品类。

  • 实现原理

    • bean容器的启动阶段    

      • 读取bean的xml配置文件,将bean元素分别转换成一个BeanDefinition对象。

      • 然后通过BeanDefinitionRegistry将这些bean注册到beanFactory中保存在它的一个ConcurrentHashMap中。

      • 将BeanDefinition注册到了beanFactory之后在这里Spring为我们提供了一个扩展的切口允许我们通过实现接口BeanFactoryPostProcessor 在此处来插入我们定义的代码。典型的例子就是PropertyPlaceholderConfigurer我们一般在配置数据库的dataSource时使用到的占位符的值就是它注入进去的。

    • 容器中bean的实例化阶段

        • 各种的Aware接口比如 BeanFactoryAware对于实现了这些Aware接口的bean在实例化bean时Spring会帮我们注入对应的BeanFactory的实例。

        • BeanPostProcessor接口实现了BeanPostProcessor接口的bean在实例化bean时Spring会帮我们调用接口中的方法。

        • InitializingBean接口实现了InitializingBean接口的bean在实例化bean时Spring会帮我们调用接口中的方法。

        • DisposableBean接口实现了BeanPostProcessor接口的bean在该bean死亡时Spring会帮我们调用接口中的方法。    

    • 设计意义

      • 松耦合。可以将原来硬编码的依赖通过Spring这个beanFactory这个工长来注入依赖也就是说原来只有依赖方和被依赖方现在我们引入了第三方——spring这个beanFactory由它来解决bean之间的依赖问题达到了松耦合的效果.

      • bean的额外处理。通过Spring接口的暴露在实例化bean的阶段我们可以进行一些额外的处理这些额外的处理只需要让bean实现对应的接口即可那么spring就会在bean的生命周期调用我们实现的接口来处理该bean。[非常重要]

    • 2.工厂方法

    • 实现方式FactoryBean接口。

    • 实现原理实现了FactoryBean接口的bean是一类叫做factory的bean。其特点是spring会在使用getBean()调用获得该bean时会自动调用该bean的getObject()方法所以返回的不是factory这个bean而是这个bean.getOjbect()方法的返回值。

    • 例子

      • 典型的例子有spring与mybatis的结合。

      • 代码示例

    • 说明我们看上面该bean因为实现了FactoryBean接口所以返回的不是 SqlSessionFactoryBean 的实例而是她的 SqlSessionFactoryBean.getObject() 的返回值。

    • 3.单例模式

       

    • Spring依赖注入Bean实例默认是单例的。

    • Spring的依赖注入包括lazy-init方式都是发生在AbstractBeanFactory的getBean里。getBean的doGetBean方法调用getSingleton进行bean的创建。

    • 分析getSingleton()方法

      public Object getSingleton(String beanName){
          //参数true设置标识允许早期依赖
          return getSingleton(beanName,true);
      }
      protected Object getSingleton(String beanName, boolean allowEarlyReference) {
          //检查缓存中是否存在实例
          Object singletonObject = this.singletonObjects.get(beanName);
          if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
              //如果为空则锁定全局变量并进行处理。
              synchronized (this.singletonObjects) {
                  //如果此bean正在加载则不处理
                  singletonObject = this.earlySingletonObjects.get(beanName);
                  if (singletonObject == null && allowEarlyReference) {  
                      //当某些方法需要提前初始化的时候则会调用addSingleFactory 方法将对应的ObjectFactory初始化策略存储在singletonFactories
                      ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                      if (singletonFactory != null) {
                          //调用预先设定的getObject方法
                          singletonObject = singletonFactory.getObject();
                          //记录在缓存中earlysingletonObjects和singletonFactories互斥
                          this.earlySingletonObjects.put(beanName, singletonObject);
                          this.singletonFactories.remove(beanName);
                      }
                  }
              }
          }
          return (singletonObject != NULL_OBJECT ? singletonObject : null);
      }
      
      

    • 我以为的周末 vs 实际上的周末

      • 总结

      • 单例模式定义保证一个类仅有一个实例并提供一个访问它的全局访问点。

      • spring对单例的实现spring中的单例模式完成了后半句话即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例这是因为spring管理的是任意的java对象。

        4. 适配器模式

      • 实现方式SpringMVC中的适配器HandlerAdatper。

      • 实现原理HandlerAdatper根据Handler规则执行不同的Handler。

      • 实现过程DispatcherServlet根据HandlerMapping返回的handler向HandlerAdatper发起请求处理Handler。HandlerAdapter根据规则找到对应的Handler并让其执行执行完毕后Handler会向HandlerAdapter返回一个ModelAndView最后由HandlerAdapter向DispatchServelet返回一个ModelAndView。

      • 实现意义HandlerAdatper使得Handler的扩展变得容易只需要增加一个新的Handler和一个对应的HandlerAdapter即可。因此Spring定义了一个适配接口使得每一种Controller有一种对应的适配器实现类让适配器代替controller执行相应的方法。这样在扩展Controller时只需要增加一个适配器类就完成了SpringMVC的扩展了。

      • 5.装饰器模式

      • 实现方式Spring中用到的包装器模式在类名上有两种表现一种是类名中含有Wrapper另一种是类名中含有Decorator。

      • 实质

        • 动态地给一个对象添加一些额外的职责。

        • 就增加功能来说Decorator模式相比生成子类更为灵活。

      • 6.代理模式

      • 实现方式AOP底层就是动态代理模式的实现。

        • 动态代理在内存中构建的不需要手动编写代理类

        • 静态代理需要手工编写代理类代理类引用被代理对象。

      • 实现原理切面在应用运行的时刻被织入。一般情况下在织入切面时AOP容器会为目标对象创建动态的创建一个代理对象。SpringAOP就是以这种方式织入切面的。 织入把切面应用到目标对象并创建新的代理对象的过程。

      • 7.观察者模式

      • 实现方式spring的事件驱动模型使用的是 观察者模式 Spring中Observer模式常用的地方是listener的实现。

      • 具体实现 事件机制的实现需要三个部分,事件源,事件,事件监听器

        • ApplicationEvent抽象类事件

          • 继承自jdk的EventObject,所有的事件都需要继承ApplicationEvent,并且通过构造器参数source得到事件源.

          • 该类的实现类ApplicationContextEvent表示ApplicaitonContext的容器事件.

          • 代码

            public abstract class ApplicationEvent extends EventObject {
                private static final long serialVersionUID = 7099057708183571937L;
                private final long timestamp;
                public ApplicationEvent(Object source) {
                super(source);
                this.timestamp = System.currentTimeMillis();
                }
                public final long getTimestamp() {
                    return this.timestamp;
                }
            }
            
            
        • ApplicationListener接口事件监听器

          • 继承自jdk的EventListener,所有的监听器都要实现这个接口。

          • 这个接口只有一个onApplicationEvent()方法,该方法接受一个ApplicationEvent或其子类对象作为参数,在方法体中,可以通过不同对Event类的判断来进行相应的处理。

          • 当事件触发时所有的监听器都会收到消息。

          • 代码

                public interface ApplicationListener<E extends ApplicationEvent> extends                EventListener {
                             void onApplicationEvent(E event);
            } 
            
            
      •  

    • getSingleton()过程图 psspring依赖注入时使用了 双重判断加锁 的单例模式

      • ApplicationContext接口事件源

        • ApplicationContext是spring中的全局容器,翻译过来是”应用上下文”。

        • 实现了ApplicationEventPublisher接口。

        • 职责负责读取bean的配置文档,管理bean的加载,维护bean之间的依赖关系,可以说是负责bean的整个生命周期,再通俗一点就是我们平时所说的IOC容器。

        • 代码

          public interface ApplicationEventPublisher {
                  void publishEvent(ApplicationEvent event);
          }   
          
          public void publishEvent(ApplicationEvent event) {
              Assert.notNull(event, "Event must not be null");
              if (logger.isTraceEnabled()) {
                   logger.trace("Publishing event in " + getDisplayName() + ": " + event);
              }
              getApplicationEventMulticaster().multicastEvent(event);
              if (this.parent != null) {
              this.parent.publishEvent(event);
              }
          }
          
          
      • ApplicationEventMulticaster抽象类事件源中publishEvent方法需要调用其方法getApplicationEventMulticaster

        • 属于事件广播器,它的作用是把Applicationcontext发布的Event广播给所有的监听器.

        • 代码

          public abstract class AbstractApplicationContext extends DefaultResourceLoader
              implements ConfigurableApplicationContext, DisposableBean {  
              private ApplicationEventMulticaster applicationEventMulticaster;  
              protected void registerListeners() {  
              // Register statically specified listeners first.  
              for (ApplicationListener<?> listener : getApplicationListeners()) {  
              getApplicationEventMulticaster().addApplicationListener(listener);  
              }  
              // Do not initialize FactoryBeans here: We need to leave all regular beans  
              // uninitialized to let post-processors apply to them!  
              String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);  
              for (String lisName : listenerBeanNames) {  
              getApplicationEventMulticaster().addApplicationListenerBean(lisName);  
              }  
            }  
          }
          
          
    • 8.策略模式

    • 实现方式Spring框架的资源访问Resource接口 。该接口提供了更强的资源访问能力Spring 框架本身大量使用了 Resource 接口来访问底层资源。

    • Resource 接口介绍

      • source 接口是具体资源访问策略的抽象也是所有资源访问类所实现的接口。

      • Resource 接口主要提供了如下几个方法:

        • getInputStream()定位并打开资源返回资源对应的输入流。每次调用都返回新的输入流。调用者必须负责关闭输入流。

        • exists()返回 Resource 所指向的资源是否存在。

        • isOpen()返回资源文件是否打开如果资源文件不能多次读取每次读取结束应该显式关闭以防止资源泄漏。

        • getDescription()返回资源的描述信息通常用于资源处理出错时输出该信息通常是全限定文件名或实际 URL。

        • getFile返回资源对应的 File 对象。

        • getURL返回资源对应的 URL 对象。 最后两个方法通常无须使用仅在通过简单方式访问无法实现时Resource 提供传统的资源访问的功能。

      • Resource 接口本身没有提供访问任何底层资源的实现逻辑针对不同的底层资源Spring 将会提供不同的 Resource 实现类不同的实现类负责不同的资源访问逻辑。

      • Spring 为 Resource 接口提供了如下实现类

        • UrlResource访问网络资源的实现类。

        • ClassPathResource访问类加载路径里资源的实现类。

        • FileSystemResource访问文件系统里资源的实现类。

        • ServletContextResource访问相对于 ServletContext 路径里的资源的实现类.

        • InputStreamResource访问输入流资源的实现类。

        • ByteArrayResource访问字节数组资源的实现类。 这些 Resource 实现类针对不同的的底层资源提供了相应的资源访问逻辑并提供便捷的包装以利于客户端程序的资源访问。

    • 9.模版方法模式

    • 经典模板方法定义

      • 父类定义了骨架调用哪些方法及顺序某些特定方法由子类实现

      • 最大的好处代码复用减少重复代码。除了子类要实现的特定方法其他方法及方法调用顺序都在父类中预先写好了。

      • 所以父类模板方法中有两类方法

        • 共同的方法所有子类都会用到的代码

        • 不同的方法子类要覆盖的方法分为两种

          • 抽象方法父类中的是抽象方法子类必须覆盖

          • 钩子方法父类中是一个空方法子类继承了默认也是空的 注为什么叫钩子子类可以通过这个钩子方法控制父类因为这个钩子实际是父类的方法空方法

    • Spring模板方法模式实质 是模板方法模式和回调模式的结合是Template Method不需要继承的另一种实现方式。Spring几乎所有的外接扩展都采用这种模式。

    • 具体实现JDBC的抽象和对Hibernate的集成都采用了一种理念或者处理方式那就是模板方法模式与相应的Callback接口相结合。

    • 采用模板方法模式是为了以一种统一而集中的方式来处理资源的获取和释放以JdbcTempalte为例:

      public abstract class JdbcTemplate {  
           public final Object executeString sql{  
              Connection con=null;  
              Statement stmt=null;  
              try{  
                  con=getConnection;  
                  stmt=con.createStatement;  
                  Object retValue=executeWithStatementstmt,sql;  
                  return retValue;  
              }catchSQLException e{  
                   ...  
              }finally{  
                  closeStatementstmt;  
                  releaseConnectioncon;  
              }  
          }   
          protected abstract Object executeWithStatementStatement   stmt, String sql;  
      }  
      
      
    • 引入回调原因

      • JdbcTemplate是抽象类不能够独立使用我们每次进行数据访问的时候都要给出一个相应的子类实现,这样肯定不方便所以就引入了回调 。

      • 回调代码

        public interface StatementCallback{  
            Object doWithStatementStatement stmt;  
        }   
        
        
      • 利用回调方法重写JdbcTemplate方法

        public class JdbcTemplate {  
            public final Object executeStatementCallback callback{  
                Connection con=null;  
                Statement stmt=null;  
                try{  
                    con=getConnection;  
                    stmt=con.createStatement;  
                    Object retValue=callback.doWithStatementstmt;  
                    return retValue;  
                }catchSQLException e{  
                    ...  
                }finally{  
                    closeStatementstmt;  
                    releaseConnectioncon;  
                }  
            }  
        
            ...//其它方法定义  
        }   
        
        
      • Jdbc使用方法如下

        JdbcTemplate jdbcTemplate=...;  
            final String sql=...;  
            StatementCallback callback=new StatementCallback(){  
            public Object=doWithStatement(Statement stmt){  
                return ...;  
            }  
        }    
        jdbcTemplate.execute(callback);  
        
        
    • 为什么JdbcTemplate没有使用继承因为这个类的方法太多但是我们还是想用到JdbcTemplate已有的稳定的、公用的数据库连接那么我们怎么办呢我们可以把变化的东西抽出来作为一个参数传入JdbcTemplate的方法中。但是变化的东西是一段代码而且这段代码会用到JdbcTemplate中的变量。怎么办那我们就用回调对象吧。在这个回调对象中定义一个操纵JdbcTemplate中变量的方法我们去实现这个方法就把变化的东西集中到这里了。然后我们再传入这个回调对象到JdbcTemplate从而完成了调用。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Spring