目录
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)
- 抽象模板类 -> 模板方法 -> 模板方法调用普通方法,抽象方法,钩子方法。
- 子类继承抽象模板类 -> 实现抽象方法,钩子方法
我们常用的创建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) {
...
}
}
}
}
}