Spring中用到的设计模式

  • Post author:
  • Post category:其他



目录


​编辑


0.Spring中用到的设计模式:


1.模板模式


1.JDK->AQS,基于AQS创建锁


2.Spring IOC容器的初始化


3.Spring 依赖注入(IOC 控制反转):


4.Spring AOP:


5.SpringMVC:


6.SpringSecurity:


7.观察者模式


8.发布订阅模式


9策略模式


10.建造者模式


11.装饰器模式:



0.Spring中用到的设计模式:



其实只要答出下面的几种就行了:

1.模板模式


1.JDK->AQS,基于AQS创建锁

AbstractQueuedSynchronizer:抽象类,AQS框架核心类,其内部以虚拟队列的方式管理线程的锁获取与锁释放,其中获取锁(tryAcquire方法)和释放锁(tryRelease方法)并没有提供默认实现,需要子类重写这两个方法实现具体逻辑,目的是使开发人员可以自由定义获取锁以及释放锁的方式。

这个抽象类提供了两个钩子方法tryAcquire(int arg)与tryRelease(int arg), 需要子类去实现。 从设计模式角度来看,AQS采用的

模板模式

的方式构建的,其内部除了提供并发操作核心方法以及同步队列操作外,还提供了一些

模板方法

让子类自己实现,如

加锁操作

以及

解锁操作

,为什么这么做?这是因为AQS作为基础组件,封装的是核心并发操作,但是实现上分为两种模式,即

共享模式



独占模式

,而这两种模式的加锁与解锁实现方式是

不一样

的,但AQS只关注内部公共方法实现并不关心外部不同模式的实现,所以提供了模板方法给子类使用,也就是说实现独占锁,如

ReentrantLock需要自己实现tryAcquire()方法和tryRelease()方法

,而实现共享模式的

Semaphore,则需要实现tryAcquireShared()方法和tryReleaseShared()方法

,这样做的好处是显而易见的,无论是共享模式还是独占模式,其基础的实现都是同一套组件(AQS),只不过是加锁解锁的逻辑不同罢了,更重要的是如果我们需要自定义锁的话,也变得非常简单,只需要

选择不同的模式实现不同的加锁和解锁的模板方法

即可


2.Spring IOC容器的初始化

Spring IOC容器的初始化过程->AbstractApplicationContext.java抽象类 -> refresh()方法,就是一个模板方法。

AbstractApplicationContext.java抽象类 -> refresh()方法 -> postProcessBeanFactory(beanFactory),是一个钩子方法,一个空方法,没有实现任何功能,由子类根据情况去实现。

AbstractApplicationContext.java抽象类 -> refresh()方法 -> onRefresh(),也是一个钩子方法,一个空方法,没有实现任何功能,由子类根据情况去实现。

子类的实现:

ConfigurableApplicationContext.java(接口) -> AbstractApplicationContext(实现了ConfigurableApplicationContext.java) -> GenericApplicationContext.java(继承了AbstractApplicationContext)

  1. 抽象模板类 -> 模板方法 -> 模板方法调用普通方法,抽象方法,钩子方法。
  2. 子类继承抽象模板类 -> 实现抽象方法,钩子方法

我们常用的创建IOC容器的

AnnotationConfigWebApplicationContext



ClassPathXmlApplicationContext

类,最终都是继承于AbstractApplicationContext.java抽象类


还有jdbcTemplate:


3.Spring 依赖注入(IOC 控制反转):

Spring依赖注入有两种方式,单例和prototype,分别用到了

单例模式



原型模式


原型模式:

使用原型模式创建对象比直接new一个对象在性能上好得多,因为Object类的clone()方法是一个native方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显,但是Object.clone()不能够深拷贝,只能浅拷贝,所以如果一个对象中有引用类型的属性,那么就需要用序列化,反序列化的方式去完成(字节流???)


简单工厂

:Spring中BeanFactory就是工厂模式的提现,根据传入一个唯一的标识来获得Bean对象;


模板模式:

在各种BeanFactory以及ApplicationContext实现中用到了;


4.Spring AOP:

AOP具体是由动态代理实现的,

动态代理模式

。动态代理底层用到了反射。

JDK动态代理与CGlib的区别:JDK动态代理只能代理实现了接口的类,动态代理会实现该接口的方法,在该方法中调用被代理对象的相同方法(会将该对象赋值给其对应的接口(父类引用指向子类实现))。而Cglib类似于继承,动态代理类作为一个子类,重写了父类(被代理类)的方法,别重写的方法中,调用了父类的相同方法。

5.SpringMVC:

责任链模式和适配器模式

java8中的stream流式编程也类似于责任链模式。

springMVC中定义的拦截器,多个

拦截器

组成一个拦截器链,责任链模式

6.SpringSecurity:


深入理解Spring Security之过滤器责任链模式分析_李永志的博客-CSDN博客

责任链模式:

Spring Security 中的过滤器链就是一种责任链模式。一个请求到达后,被过滤器链中的过滤器逐个进行处理,过滤器链中的过滤器每个都具有不同的职能并且互不相扰,我们还可以通过 HttpSecurity 来动态配置过滤器链中的过滤器(即添加/删除过滤器链中的过滤器)。

  @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                ....
                //在这里添加了过滤器,这里指定了配置过滤器并且配置的位置
               .addFilterBefore(singleSignOutFilter, CasAuthenticationFilter.class)
    }

SpringCloud gateway中的

过滤器链

,也是

责任链模式

,过滤器链中的每个过滤器都可以对http request做处理,例如登录验证、对http header,parameter,path,response等的处理。

参考文章:

springCloud-13 gateWay过滤器:概述_vegetari的博客-CSDN博客_springcloud过滤器

7.观察者模式

springboot启动过程(run方法)中的监听器 ,在SpringApplication的构造方法中,会从spring.factories文件中加载所有的监听器(共有11个,使用反射生产监听器对象)。构造完成后会调用run方法,会再次从spring.factories文件中加载监听器的事件发布器(监听器是观察者,事件发布器是被观察者),事件发布器会获取之前加载的11个监听器,然后放到自己的集合里,然后这个事件发布器会在springboot启动过程中,发布各种事件,例如starting,环境变量prepared,before refreshcontext,启动结束事件,发布给监听器去处理,比如回收资源等。


总之:


监听器会监听springboot启动过程中,所有的事件

如果在自己的工程中,自定义监听器,则需要将自定义的监听器加入到本工程 resources  \META-INF/spring.factories 文件中

运行结果:



关于监听器,请看文章:



Spring之事件监听(观察者模型)_波波烤鸭的博客-CSDN博客_spring 观察者

8.发布订阅模式

MQ, 注册中心,发布订阅模式与观察者模式类似,但是不同之处在于,发布订阅模式实现了观察者与被观察者(时间发布者)的解耦,二者不产生直接联系。但是观察者模式,观察者要注册到被观察者中。

9策略模式

1.AnnotationConfigWebApplicationContext, ClassPathXmlApplicationContext等根据xml或者注解进行处理的spring容器

2.XmlBeanDefinitionReader, PropertiesBeanDefinitionReader等根据不同情况加载bean配置的类。

BeanDefinitionReader 是 Spring 容器中提供的 BeanDefinition 读取器,用于将 Spring 的配置信息,转换为 BeanDefinition 。提供了4个实现类:


  • AbstractBeanDefinitionReader

    :是一个抽象类,同时实现了 EnvironmentCapable 接口,提供环境的get和set方法。它实现了BeanDefinitionReader 的一些通用方法,比如按照路径来读取 Bean 定义信息的方法→int loadBeanDefinitions(String location)。对于更为具体的方法,比如根据资源来读取 Bean 定义信息的方法→int loadBeanDefinitions(Resource resource), 则交由子类来实现。

  • PropertiesBeanDefinitionReader

    :是一个具体实现类,可以从properties文件读取Bean定义信息。

  • XmlBeanDefinitionReader

    :具体实现类,可以从XML文件读取Bean定义信息。

  • GroovyBeanDefinitionReader

    :具体实现类,可以读取Groovy 语言写的Bean的定义信息。

这些 BeanDefinitionReader 在我们使用 Spring 开的时候较少使用,在 Spring 源码中使用的比较多,相当于是 Spring 内部的基础设施。

3.其它策略模式:Java要求如果定义的复合对象要有排序的功能,就自行实现Comparable接口或Comparator接口;

10.建造者模式

mybatis的sqlSessionFactory,要得到这个对象,需要解析属性文件和映射文件,非常复杂,而mybatis给我们提供了建造者模式,屏蔽了构建这个对象的复杂操作,用户可以直接通过new得到这个对象。当然了这个对象还是一个工厂模式。

11.装饰器模式:

1. 文件IO涉及到的各种输入输出流,最基本的输入输出流,可以被简单包装一下,生成别种类型的输入输出流。

public class ContextHolder {

	try (ZipInputStream zip = new ZipInputStream(new FileInputStream(...))) {
		ZipEntry entry = null;
		while ((entry = zip.getNextEntry()) != null) {
			String name = entry.getName();
			if (!entry.isDirectory()) {
				int n;
				while ((n = zip.read()) != -1) {
					...
				}
			}
		}
	}
}



版权声明:本文为wdquan19851029原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。