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

实现形式:

BeanFactory。Spring中的 BeanFactory 就是简略工厂模式的体现,依据传入一个惟一的标识来取得Bean对象,但是否是在传入参数后创立还是传入参数前创立这个要依据具体情况来定。

本质:

由一个工厂类依据传入的参数,动静决定应该创立哪一个产品类。

实现原理:

bean容器的启动阶段:

  • 读取bean的xml配置文件,将bean元素别离转换成一个 BeanDefinition 对象。
  • 而后通过 BeanDefinitionRegistry 将这些bean注册到beanFactory中,保留在它的一个 ConcurrentHashMap 中。
  • BeanDefinition 注册到了 beanFactory 之后,在这里Spring为咱们提供了一个扩大的切口,容许咱们通过实现接口 BeanFactoryPostProcessor  在此处来插入咱们定义的代码。
    典型的例子就是: PropertyPlaceholderConfigurer ,咱们个别在配置数据库的 dataSource 时应用到的占位符的值,就是它注入进去的。

容器中bean的实例化阶段:

实例化阶段次要是通过反射或者CGLIB对bean进行实例化,在这个阶段Spring又给咱们裸露了很多的扩大点:

  • 各种的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);  }  

getSingleton()过程图

ps:spring依赖注入时,应用了 双重判断加锁 的单例模式

图片

总结

单例模式定义:保障一个类仅有一个实例,并提供一个拜访它的全局拜访点。

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

扩大: 设计模式是什么鬼(单例)

4.适配器模式

实现形式:

SpringMVC中的适配器 HandlerAdatper

实现原理:

HandlerAdatper 依据Handler规定执行不同的Handler。

实现过程:

DispatcherServlet 依据 HandlerMapping 返回的handler,向 HandlerAdatper 发动申请,解决Handler。

HandlerAdapter 依据规定找到对应的Handler并让其执行,执行结束后Handler会向 HandlerAdapter 返回一个 ModelAndView ,最初由 HandlerAdapterDispatchServelet 返回一个 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);  }

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 execute(String sql){            Connection cnotallow=null;            Statement stmt=null;            try{                cnotallow=getConnection();                stmt=con.createStatement();                Object retValue=executeWithStatement(stmt,sql);                return retValue;            }catch(SQLException e){                 ...            }finally{                closeStatement(stmt);                releaseConnection(con);            }        }         protected abstract Object executeWithStatement(Statement   stmt, String sql);    }

引入回调起因:

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

回调代码

public interface StatementCallback{        Object doWithStatement(Statement stmt);    }

利用回调办法重写 JdbcTemplate 办法

public class JdbcTemplate {        public final Object execute(StatementCallback callback){            Connection cnotallow=null;            Statement stmt=null;            try{                cnotallow=getConnection();                stmt=con.createStatement();                Object retValue=callback.doWithStatement(stmt);                return retValue;            }catch(SQLException e){                ...            }finally{                closeStatement(stmt);                releaseConnection(con);            }        }        ...//其它办法定义 }

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 ,从而实现了调用。