设计模式—Spring中的设计模式

  • 工厂
  • 代理
  • 单例
  • 适配器
  • 模板
  • 包装器
  • 观察者

  • IoC(Inversion of Control,控制反转)
    • 是一种设计思想,主要借助第三方容器,实现具有具有依赖关系的对象之间的解耦(Ioc容易管理对象,我么你只需要用对象)降低耦合度。
    • Ioc时一个原则而不是一个模式。一下模式实现了IoC

Spring中的设计模式 - 图1
- Spring Ioc容器就像一个工厂,当我们需要创建一个对象,只需配置,交给容器创建,并从创建中处理这些对象的整个声明周期,直到他们完全销毁。
- 若一个类依赖于很多其他类,我们如果想要修改这个类,就要修改他的所有底层相关代码。若用IoC,只需要配置好,在用的地方引用。
- 控制反转:a对象依赖于b,当a需要b时必须a自己创建。但是引入IoC后,对象a和对象b之间失去了直接联系,a需要b时,容器自己去创建b然后把b注入到a中。
- DI(Dependecy Inject,依赖注入)是实现控制反转思想的一种实现,就是将实例变量传到需要它的对象中。
详见
- 高层依赖底层
Spring中的设计模式 - 图2

  • 底层注入高层
    Spring中的设计模式 - 图3

工厂模式
  • Spring使用工厂模式可通过BeanFactory或ApplicationContext创建bean对象。
  • 对比:
    • BeanFactory:延迟注入(使用到某个bean的时候才会注入),相比于BeanFactory来说占用更少的内存,启动更快。
    • ApplicationContext:容器启动的时候,不管有没有用到,一次性创建所有bean。
    • BeanFactory只提供了基本的依赖注入支持,ApplicationContext扩展了BeanFactory,一般开发ApplicationContext用更多。
  • ApplicationContext的三个实现类:

    • ClassPathXmlApplication:把上下文文件当成类路径资源
    • FileSystemXmlApplication:从文件系统中的XML文件载入上下文定义信息。
    • XmlWebApplicationContext:从Web系统中的XML文件载入上下文定义信息。
      BeanFactory 与 FactoryBean的区别?
  • BeanFactory: 以Factory结尾,表示它是一个工厂类,是用于管理Bean的一个工厂。

  • FactoryBean:以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean接口的Bean,根据该Bean的Id从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身, 如果要获取FactoryBean对象,可以在id前面加一个&符号来获取。

    单例
  • 系统中有些对象只需要一个如:线程池、缓存、注册表、日志对象等。

  • Spring中Bean的默认作用域就是单例的。除此之外还有原型、request、session、global-session。

    代理
  • AOP能将与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务、日志、权限等)封装起来,便于减少系统的重复代码,降低模块间的耦合,利于扩展维护。

  • 使用AOP后可把通用功能抽象处理,在需要的地方直接使用,简化代码,扩展方便。日志事务等场景都用的AOP。
  • SpringAOP基于动态代理,若要代理的对象,实现了某个接口,那么SpringAOP会使用JDKProxy,创建代理对象,而对于没有实现接口的对象,无法使用JDK动态代理,AOP会选择cglib代理,cglib生成一个被代理对象的子类作为代理类。
  • JDK动态代理实现
    • 新建接口
    • 为接口创建实现类
    • 创建代理类实现java.lang.reflect.InvocationHandler接口重新invoke方法。
    • 参考
  • 也可以使用AspectJ,SpringAOP集成了AspectJ,AspectJ算是java中最完整的AOP框架了。

Spring中的设计模式 - 图4

Spring AOP 与AspectJ AOP区别
  • Spring AOP属于运行时增强,AspectJ AOP是编译时增强。
  • Spring AOP基于代理(Proxying),AspectJ AOP基于字节码。
  • AspectJ AOP相比更强大,但是Spring AOP更简单。
  • 切面少,性能差异不大。当切面太多AspectJ AOP快很多。

    模板
  • 模板是一种行为设计模式,它定义一个操作中的算法的股价,将一些步骤延迟到子类中。模板方法使得子类可不改变一个算法结构即可重新定义该算法的某些特定步骤的实现方式。

模板UML图
Spring中的设计模式 - 图5

  1. public abstract class Template{
  2. //模板方法
  3. public final void TemplateMethod(){
  4. PrimitiveOperation1();
  5. PrimitiveOperation2();
  6. PrimitiveOperation3();
  7. }
  8. protected void PrimitiveOperation1(){
  9. //当前实现类
  10. }
  11. //被子类实现的方法
  12. protected abstract void PrimitiveOperation2();
  13. protected abstract void PrimitiveOperation3();
  14. }
  15. public class TemplateImpl extends Template{
  16. @Override
  17. public void PrimitiveOperation2(){
  18. //当前实现类
  19. }
  20. @Override
  21. public void PrimitiveOperation3(){
  22. //当前实现类
  23. }
  24. }
  • Spring 中jdbcTemplate、 hibernateTemplate、RedisTemplate等Template结尾的对数据库操作的类,用到了模板模式,一般情况下都是使用集成的方式实现模板模式,但是Spring并没有使用这种方式,而是使用Callback模式与模板方法配合,既达到了代码复用,同事增加了灵活度。

    观察者
  • 观察者模式是一种对象行为模式,标识的是一种对象元对象间具有某种依赖关系,当一个对象发生改变的时候,个对象所依赖的对象也会做出反应。Spring事件驱动模型就是观察者模式的应用。Spring事件驱动模型在很多场景都可解耦我们的代码。

    Spring事件驱动模型的三种角色
  • 事件角色

    • ApplicationEvent充当事件的角色,是一个抽象类,集成了java.util.EventObject实现了java.io.Serializable接口。
    • Spring中默认存在一下事件,他们都是对ApplicationContextEvent的实现(继承自ApplicationContextEvent);
      • ContextStartedEvent:ApplicationContext启动后触发的事件;
      • ContextStoppedEvent:ApplicationContext停止后触发的事件;
      • ContextRefreshedEvent:ApplicationContext初始化或刷新完成后触发的事件;
      • ContextClisedEvent:ApplicationContext关闭后触发的事件。
  • 事件监听角色
    • ApplicationListener充当了事件监听者角色,他是一个接口,定义了onApplicationEvent()方法来处理ApplicationEvent。
    • 在Spring中只要实现ApplicationListener接口重写onApplicationEvent()方法即可完成监听事件。
  • 事件发布者角色
    • ApplicationEventPublisher充当了事件的发布者,是一个接口。
    • ApplicationEventPublisher接口的publishEvent()方法在AbstractApplicationContext类中被实现,实际上事件真正是通过ApplicationEventMuticaster广播出去的
  • Spring的事件流程总结

    • 定义一个事件:实现一个继承自ApplicationEvent,并写相应的构造函数;
    • 定义一个事件监听者:实现ApplicationListener接口,重写onApplicationEvent()方法。
    • 使用事件发布者发布消息:可通过ApplicationEventPublisher的publisherEvent()方法发布消息。
      1. /**
      2. * @author Skiray
      3. * @date 2021/6/29 12:42
      4. */
      5. //定义一个事件,继承自ApplicationEvent
      6. public class DemoEvent extends ApplicationEvent {
      7. private static final long seriaVersionUID = 1L;
      8. private String message;
      9. public DemoEvent(Object source, String message) {
      10. super(source);
      11. this.message = message;
      12. }
      13. public String getMessage(){
      14. return message;
      15. }
      16. //定义一个事件监听者,实现ApplicationListener接口,重写onApplicationEvent方法
      17. @Component
      18. public class DemoListener implements ApplicationListener<DemoEvent>{
      19. //onApplicationEvent接收消息
      20. @Override
      21. public void onApplicationEvent(DemoEvent demoEvent) {
      22. String msg = demoEvent.getMessage();
      23. System.out.println("接收的消息是:" + msg);
      24. }
      25. }
      26. //发布事件,可通过publishEvent方法
      27. @Component
      28. public class DemoPublisher{
      29. @Autowired
      30. ApplicationContext applicationContext;
      31. public void publisher(String message){
      32. //发布事件
      33. applicationContext.publishEvent(new DemoEvent(this,message));
      34. }
      35. }
      36. }
      适配器模式
  • 适配器模(Adapter Pattern)式将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的哪些类可一起工作,其别名为包装器(Wrapper)。

  • Spring AOP中的适配器模式
  • 我们知道Spring AOP的实现是基于代理模式,但是增强或通知(Advice)使用到了适配器模式,与之相关的接口是AdvisorAdapter。
  • Advice常用的类型有:
    • BeforeAdvice(目标方法调用钱,前置通知)
    • AfterAdvice(后置通知)
    • AfterReturnningAdvice(目标方法执行结束,return之前)
  • 每个类型Advice(通知)都有对应的拦截器
    • MethodBeforeAdviceInterceptor、
    • AfterReturningAdviceAdapter、
    • AfterReturningAdviceInterceptor
      Spring预定义的通知要通过对应的适配器,适配成 MethodInterceptor接口(方法拦截器)类型的对象(如:MethodBeforeAdviceInterceptor 负责适配 MethodBeforeAdvice)。
  • 包装器