前言

前几天,一位读者面阿里被问到一个问题:Spring框架用到了哪些设计模式?,答的不是很好,于是打算写篇文章讲讲这个!

最近几天肝文章都到凌晨3,4点,因为最近工作的事件比拟多,只能早晨写文章(为了放弃日更,也是拼了),也收到一些读者的关怀,谢谢大家~

感觉不错,心愿点赞,再看,转发反对一下,谢谢

代理模式

所谓代理,是指它与被代理对象实现了雷同的接口,客户端必须通过代理能力与被代理的指标类进行交互,而代理个别在交互的过程中(交互前后),进行某些特定的解决,比方在调用这个办法前做前置解决,调用这个办法后做后置解决。

代理又分为动态代理和动静代理两种形式,Spring的AOP采纳的是动静代理的形式

Spring通过动静代理对类进行办法级别的切面加强,动静生成指标对象的代理类,并在代理类的办法中设置拦截器,通过执行拦截器中的逻辑加强了代理办法的性能,从而实现AOP。

策略模式

咱们后面讲到,Spring AOP是通过动静代理来实现的。

具体到代码实现,Spring反对两种动静代理实现形式,一种是JDK提供的动静代理实现形式,另一种是Cglib提供的动静代理实现形式。

Spring会在运行时动静地抉择不同的动静代理实现形式。这个利用场景实际上就是策略模式的典型利用场景。

咱们只须要定义一个策略接口,让不同的策略类都实现这一个策略接口。对应到Spring源码,AopProxy是策略接口,JdkDynamicAopProxy、CglibAopProxy是两个实现了AopProxy接口的策略类。

其中,AopProxy接口的定义如下所示:

在策略模式中,策略的创立个别通过工厂办法来实现。对应到Spring源码,AopProxyFactory是一个工厂类接口,DefaultAopProxyFactory是一个默认的工厂类,用来创立AopProxy对象。

源码如下所示:

策略模式的典型利用场景,个别是通过环境变量、状态值、计算结果等动静地决定应用哪个策略。

对应到Spring源码中,咱们能够参看刚刚给出的DefaultAopProxyFactory类中的createAopProxy()函数的代码实现。

其中,第10行代码是动静抉择哪种策略的判断条件。

装璜器模式

咱们晓得,缓存个别都是配合数据库来应用的。如果写缓存胜利,但数据库事务回滚了,那缓存中就会有脏数据。

为了解决这个问题,咱们须要将缓存的写操作和数据库的写操作,放到同一个事务中,要么都胜利,要么都失败。

实现这样一个性能,Spring应用到了装璜器模式。

TransactionAwareCacheDecorator减少了对事务的反对,在事务提交、回滚的时候别离对Cache的数据进行解决。

TransactionAwareCacheDecorator实现Cache接口,并且将所有的操作都委托给targetCache来实现,对其中的写操作增加了事务性能。这是典型的装璜器模式的利用场景和代码实现。

单例模式

单例模式是指一个类在整个零碎运行过程中,只容许产生一个实例

在Spring中,Bean能够被定义为两种模式:Prototype(多例)和Singleton(单例),Spring Bean默认是单例模式。

那Spring是如何实现单例模式的呢?

答案是通过单例注册表的形式,具体来说就是应用了HashMap。简化代码如下:

public class DefaultSingletonBeanRegistry {    //应用了线程平安容器ConcurrentHashMap,保留各种单实例对象    private final Map singletonObjects = new ConcurrentHashMap;    protected Object getSingleton(String beanName) {    //先到HashMap中拿Object    Object singletonObject = singletonObjects.get(beanName);    //如果没拿到通过反射创立一个对象实例,并增加到HashMap中    if (singletonObject == null) {      singletonObjects.put(beanName,                           Class.forName(beanName).newInstance());   }   //返回对象实例   return singletonObjects.get(beanName);  }}

下面的代码逻辑比拟清晰,先到HashMap去拿单实例对象,没拿到就创立一个增加到HashMap。

简略工厂模式

有这样一个场景:

当A对象须要调用B对象的办法时,咱们须要在A中new一个B的实例,它的毛病是一旦需要发生变化,比方须要应用C类来代替B时,就要改写A类的办法。

如果利用中有100个类以的形式耦合了B,那改起来就吃力了。

应用简略工厂模式:

简略工厂模式又叫动态工厂办法,其实质是由一个工厂类依据传入的参数,动静决定应该创立哪一个产品类。

其中Spring中的BeanFactory就是简略工厂模式的体现,BeanFactory是Spring IOC容器中的一个外围接口,它的定义如下:

咱们能够通过它的具体实现类(比方ClassPathXmlApplicationContext)来获取Bean:

BeanFactory bf = new ClassPathXmlApplicationContext("spring.xml");FlyFish flyFishBean = (FlyFish) bf.getBean("flyfishBean");

从下面代码能够看到,使用者不须要本人来new对象,而是通过工厂类的办法getBean来获取对象实例,这是典型的简略工厂模式,只不过Spring是用反射机制来创立Bean的。

工厂办法模式

在简略工厂中,由工厂类进行所有的逻辑判断、实例创立;如果不想在工厂类中进行判断,能够为不同的产品提供不同的工厂,不同的工厂生产不同的产品,每一个工厂都只对应一个相应的对象,这就是工厂办法模式。

Spring中的FactoryBean就是这种思维的体现,FactoryBean能够了解为工厂Bean,先来看看它的定义:

咱们定义一个类FlyFishFactoryBean来实现FactoryBean接口,次要是在getObject办法里new一个FlyFish对象。这样咱们通过getBean(id) 取得的是该工厂所产生的FlyFish的实例,而不是FlyFishFactoryBean自身的实例,像上面这样:

BeanFactory bf = new ClassPathXmlApplicationContext("spring.xml");FlyFish flyFishBean = (FlyFish) bf.getBean("flyfishBean");

观察者模式

Spring中实现的观察者模式蕴含三局部:Event事件(相当于音讯)、Listener监听者(相当于观察者)、Publisher发送者(相当于被观察者)

咱们通过一个例子来看下Spring提供的观察者模式是怎么应用的

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

从代码中,咱们能够看出,次要蕴含三局部工作:

  • 定义一个继承ApplicationEvent的事件(DemoEvent);
  • 定义一个实现了ApplicationListener的监听器(DemoListener);
  • 定义一个发送者(DemoPublisher),发送者调用ApplicationContext来发送事件音讯。

在Spring的实现中,观察者注册到了哪里呢?又是如何注册的呢?

Spring把观察者注册到了ApplicationContext对象中。

实际上,具体到源码来说,ApplicationContext只是一个接口,具体的代码实现蕴含在它的实现类AbstractApplicationContext中。我把跟观察者模式相干的代码,如下。你只须要关注它是如何发送事件和注册监听者就好。

从下面的代码中,咱们发现,真正的音讯发送,实际上是通过ApplicationEventMulticaster这个类来实现的。

上面这个类的源码我只摘抄了最要害的一部分,也就是multicastEvent()这个音讯发送函数,它通过线程池,反对异步非阻塞、同步阻塞这两种类型的观察者模式。

借助Spring提供的观察者模式的骨架代码,如果咱们要在Spring下实现某个事件的发送和监听,只须要做很少的工作,定义事件、定义监听器、往ApplicationContext中发送事件就能够了,剩下的工作都由Spring框架来实现。

实际上,这也体现了Spring框架的扩展性,也就是在不须要批改任何代码的状况下,扩大新的事件和监听。

模板模式

咱们常常在面试中被问到的一个问题:

请你说下Spring Bean的创立过程蕴含哪些次要的步骤。

这其中就波及模板模式。它也体现了Spring的扩展性。利用模板模式,Spring能让用户定制Bean的创立过程。

上面是Spring Bean的整个生命周期,一张图,清晰明了:

如果你认真看过源码会发现,实际上,这里的模板模式的实现,并不是规范的抽象类的实现形式,而是有点相似Callback回调的实现形式,也就是将要执行的函数封装成对象(比方,初始化办法封装成InitializingBean对象),传递给模板(BeanFactory)来执行。

观察者模式和模板模式,这两种模式可能帮忙咱们创立扩大点,让框架的使用者在不批改源码的状况下,基于扩大点定制化框架性能。

适配器模式

在Spring MVC中,定义一个Controller最罕用的形式是,通过@Controller注解来标记某个类是Controller类,通过@RequesMapping注解来标记函数对应的URL

不过,咱们还能够通过让类实现Controller接口或者Servlet接口,来定义一个Controller。

针对这三种定义形式,我写了三段示例代码,如下所示:

// 办法一:通过@Controller、@RequestMapping来定义@Controllerpublic class DemoController {    @RequestMapping("/FlyFish")    public ModelAndView getEmployeeName() {        ModelAndView model = new ModelAndView("FlyFish");                model.addObject("message", "FlyFish");               return model;     }  }// 办法二:实现Controller接口 + xml配置文件:配置DemoController与URL的对应关系public class DemoController implements Controller {    @Override    public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {        ModelAndView model = new ModelAndView("FlyFish");        model.addObject("message", "FlyFish");        return model;    }}// 办法三:实现Servlet接口 + xml配置文件:配置DemoController类与URL的对应关系public class DemoServlet extends HttpServlet {  @Override  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {    this.doPost(req, resp);  }  @Override  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {    resp.getWriter().write("Hello World.");  }}

在利用启动的时候,Spring容器会加载这些Controller类,并且解析出URL对应的处理函数,封装成Handler对象,存储到HandlerMapping对象中。当有申请到来的时候,DispatcherServlet从HanderMapping中,查找申请URL对应的Handler,而后调用执行Handler对应的函数代码,最初将执行后果返回给客户端。

然而,不同形式定义的Controller,其函数的定义(函数名、入参、返回值等)是不对立的。

DispatcherServlet调用的是service()办法,DispatcherServlet须要依据不同类型的Controller,调用不同的函数。

Spring利用适配器模式,咱们将不同形式定义的Controller类中的函数,适配为对立的函数定义。

咱们再具体看下Spring的代码实现。

Spring定义了对立的接口HandlerAdapter,并且对每种Controller定义了对应的适配器类。

这些适配器类包含:AnnotationMethodHandlerAdapter、SimpleControllerHandlerAdapter、SimpleServletHandlerAdapter等。

在DispatcherServlet类中,咱们就不须要辨别看待不同的Controller对象了,对立调用HandlerAdapter的handle()函数就能够了

最初

感觉有播种,心愿帮忙点赞,转发下哈,谢谢,谢谢