[Professor麦]总结Spring的设计模式

哈哈哈,今天又水一篇文章了,主要是最近再刷算法和基础,一时半会文章未能写完

总结Spring框架用到的设计模式

适配器模式在 Spring 中的应用

适配器其中一个作用是“统一多个类的接口设计

如果不了解Spring-MVC的可以先看看这个图img

不了解的可以先看这篇博客

我们看到上面那个HandlerAdapter,通过HandlerAdapter拿到不同的Hander然后调用不同的Hander来执行不同的handle逻辑从而返回结果给前端(前后端分离的情况是不用解析视图的)

那这个要怎么实现呢?

// 因为不同的Controller实现方式要调用不同的实现方式
Handler handler = handlerMapping.get(URL);
if (handler instanceof Controller) {
((Controller)handler).handleRequest(...);
} else if (handler instanceof Servlet) {
((Servlet)handler).service(...);
} else if (hanlder 对应通过注解来定义的Controller) {
反射调用方法...
}

上面这种方式如果要添加其他Controller就要不断修改代码,而且有这个if-else逻辑,看起来也不好阅读!

Spring怎么实现

Spring有一个HandlerAdapter,是一个统一接口image-20200718121727653

再来看看它的实现类image-20200718121831035

可以看看具体源码了

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
   if (this.handlerAdapters != null) {
       // 遍历所有HandlerAdapter,看哪个支持实现就拿出这个HandlerAdapter
      for (HandlerAdapter adapter : this.handlerAdapters) {
         if (adapter.supports(handler)) {
            return adapter;
         }
      }
   }
   throw new ServletException("No adapter for handler [" + handler +
         "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

image-20200718122100115

总结:这样就没有烦人的 if-else 逻辑,并且不需要区分对待不同的 Controller 对象了,统一调用HandlerAdapter 的 handle() 函数就可以了

策略模式在 Spring 中的应用

谈谈策略模式

其实,策略模式跟工厂模式是非常像的。我们一般是利用策略模式来避免冗长的 if-else 或 switch 分支判断。下面就看个例子把

public interface Strategy {
    void algorithmInterface();
}
public class ConcreteStrategyA implements Strategy{
    public void algorithmInterface() {
        // 具体的算法
    }
}
public class ConcreteStrategyB implements Strategy{
    public void algorithmInterface() {
        // 具体的算法
    }
}
// 这个就是策略工厂方法啦
public class StrategyFactory {
    private static final Map<String, Strategy> strategies = new HashMap<String, Strategy>();

    static {
        strategies.put("A", new ConcreteStrategyA());
        strategies.put("B", new ConcreteStrategyB());
    }

    public static Strategy getStrategies(String type) {

        return strategies.get(type);
    }
}

在工厂类中,我们用 Map 来缓存策略,根据 type 直接从 Map 中获取对应的策略,从而避免 ifelse分支判断逻辑。本质上都是借助“查表法”,根据 type 查表(代码中的strategies 就是表)替代根据 type 分支判断。

回到正题

我们一起来看看Spring-AOP。

// 这是策略接口
public interface AopProxy {
    Object getProxy();

    Object getProxy(@Nullable ClassLoader var1);
}

看看他的实现类

image-20200718145005049

看看策略工厂类image-20200718145129645

策略模式的典型应用场景,一般是通过环境变量、状态值、计算结果等动态地决定使用哪个策略。对应到 Spring 源码中,我们可以参看刚刚给出的 DefaultAopProxyFactory类中的createAopProxy() 函数的代码实现。

观察者模式在 Spring 中的应用

谈谈观察者模式

在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。

直接上代码

// 这个其实跟监听器模式也很像
// 被观察者
public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObserver(Message message);

}
public class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<Observer>();
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    public void notifyObserver(Message message) {
        for (Observer observer : observers ) {
            observer.update(message);

        }
    }
}
// 观察者
public interface Observer {
    void update(Message message);
}
public class ConcreteObserverTwo implements Observer{
    public void update(Message message) {
        System.out.println("ConcreteObserverTwo is notified.");
    }
}
public class ConcreteObserverOne implements Observer{
    public void update(Message message) {
        System.out.println("ConcreteObserverOne is notified.");
    }
}
// 测试
public class Demo {
    public static void main(String[] args) {
        ConcreteSubject concreteSubject = new ConcreteSubject();
        // 将被观察者注册到观察者上
        concreteSubject.registerObserver(new ConcreteObserverOne());
        concreteSubject.registerObserver(new ConcreteObserverTwo());
        // 有消息进来就通知被观察者
        concreteSubject.notifyObserver(new Message());
    }
}

现在再回想一下,这个观察者模式也很想我们的NIO编程,也是注册感兴趣的key,当该事件到的时候,就会用一个线程去处理该事件!

回到正题

这里举我实际项目中用到的例子吧!我曾有一个项目是要集成这个netty和spring boot的,这里,netty的启动就要用到的Spring的观察者模式,我们来看看具体怎么用的。

先介绍一下Spring的事件监听机制

Spring的事件驱动模型由三部分组成:

  1. 事件:ApplicationEvent,继承自JDK的EventObject,所有事件将继承它,并通过source得到事件源。

  2. 事件发布者:ApplicationEventPublisher及ApplicationEventMulticaster接口,使用这个接口,我们的Service就拥有了发布事件的能力。

  3. 事件订阅者:ApplicationListener,继承自JDK的EventListener,所有监听器将继承它。

Spring事件驱动过程

事件(相当于消息)

Spring 默认对 ApplicationEvent 事件提供了如下实现:

  • ContextStoppedEvent:ApplicationContext停止后触发的事件;
  • ContextRefreshedEvent:ApplicationContext初始化或刷新完成后触发的事件;
  • ContextClosedEvent:ApplicationContext关闭后触发的事件。如web容器关闭时自动会触发Spring容器的关闭,如果是普通java应用,需要调用ctx.registerShutdownHook()注册虚拟机关闭时的钩子才行;
  • ContextStartedEvent:ApplicationContext启动后触发的事件;

eventobject

事件监听者(相当于观察者)

ApplicationListener

ApplicationListener继承自JDK的EventListener,JDK要求所有监听器将继承它。提供了onApplicationEvent方法,用以处理ApplicationEvent,不过对于具体事件的处理需要进行判断。而GenericApplicationListenerSmartApplicationListener提供了关于事件更多的元数据信息。

Spring Context加载初始化完成(refresh)后会再次检测应用中的 ApplicationListener,并且注册,此时会将我们实现的 ApplicationListener 就会加入到 SimpleApplicationEventMulticaster 维护的 Listener 集合中。

事件发布者(相当于被观察者)

下图红框就是时间发布者,被ApplicationContext接口实现。

image-20200626231431583

image-20200627082943692

ApplicationContext接口继承了ApplicationEventPublisher,并在AbstractApplicationContext实现了具体代码,实际执行是委托给ApplicationEventMulticaster

我们可以看看这个调用栈,方便我们理解这个流程:image-20200718164136087

可以看看这个本质方法:

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
       // 调用一个线程池,可以支持异步非阻塞,当然也支持同步阻塞
      Executor executor = getTaskExecutor();
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
         invokeListener(listener, event);
      }
   }
}

借助 Spring 提供的观察者模式的骨架代码,如果我们要在 Spring 下实现某个事件的发送和监听,只需要做很少的工作,定义事件、定义监听器、往 ApplicationContext 中发送事件就可以了,剩下的工作都由 Spring 框架来完成。实际上,这也体现了 Spring 框架的扩展性,也就是在不需要修改任何代码的情况下,扩展新的事件和监听。

在项目中的实际使用

事件源我选择了ContextRefreshedEvent类,表示在ApplicationContext初始化或刷新完成后,就会启动该netty。事件的监听者用到了,ApplicationListener,当监听者监听到事件触发时便会执行我在onApplicationEvent方法中自定义的逻辑(启动netty)。注意:此自定义的监听者类和改事件都要在bean容器中才能触发。image-20200627084139218

模板模式在 Spring 中的应用

模板模式主要是用来解决复用和扩展两个问题

像这个AbstractApplicationContext就是用的模板模式,实现了ApplicationContext接口,提供了默认实现,让有其他功能的ApplicationContext可以继承AbstractApplicationContext从而起到复用和扩展功能

个人唠叨

嗯,今天大家大概都能猜到我要说什么吧!没错,我们又来聊聊高考了,之前在高考开始的时候,我写过一点东西(文末),是关于我的高考的!

再聊我的高考

为什么会再聊高考呢?主要是今天是出分的日子,还有是我爸妈今晚吃饭也在讨论这个分数的问题,好像不管是我高考还是不是我高考,家长们都会拿自己孩子的成绩来作比较,这真的好吗?哈哈哈哈,其实我爸妈也是随便讨论讨论而已!最主要是希望正处于高三的你或者还处于迷茫的你能看到我的文章之后会有所启发!我先谈谈,以我现在的角度来看高考,高考是什么?其实只不过是你人生的一个选择罢了!相信有的同学,今天的心情也像两年前的我一样,因为各种原因没有进入到自己理想的大学,不过也没关系的,因为只是一次选择的失利,你慢慢会发现,我上了大学之后,我开始要面临很多的选择,比如:选择要不要当一个班长(嗯,现在的我有点后悔选择了这个,因为我慢慢发现,这个职位跟我想象中的样子有太大的偏差了),要不要加入社团、组织,选择一个什么方向去深入研究,未来的职业方向要怎么选择等等问题!所以,不管你考得怎么样,你没必要去为之而喜怒哀乐,不要太纠结这一次的成败,一次的失败并不能代表你所有的未来,请继续努力向上,你一定会成功

但我发现,现在的我比高考时的我多了一份沉稳,多了一份坚持!!我敢说,比起现在进入重本同专业的同学,我根本不比他们差(迷之自信)!!!

话不多说了,最后还是分享一句话来鼓励鼓励自己,

星光不负赶路人,时光不负有心人!不管处境如何,我们都要努力!

今天的分享就到这了,欢迎关注点赞转发,我每篇文章文末都有自己的一些个人思考,感兴趣的朋友可以看看!谢谢!

​ --做一个不至于技术的博主

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值