创建型:

单例模式:
单例模式可以通过懒汉式、饿汉式和枚举来实现。
其中懒汉式有线程安全的问题,为了解决这个问题,我们需要使用双重校验锁来保证线程安全(多校验一次是为了提高效率),因为给对象赋值的操作有可能被进行指令重排,所以还要使用volatile来保证原子性。
Spring中就默认开启了单例模式,创建的都是一个对象。

工厂模式:
把创建对象交给工厂,以此降低代码的耦合。
Spring中的BeanFactory和ApplicationContext就是使用了工厂模式去创建对象

建造者模式:
将一个复杂的对象拆分成不同的简单的对象,根据需要进行组装,方便开发者创建复杂对象,一般都以XXXBuilder结尾。
之前我们在项目中使用ES的时候,有做高亮的功能,就用到了一个HighLightBuilder的类,它就是使用到了建造者模式。

结构型:

代理模式:
代理模式可分为静态代理和动态代理
静态代理是编译时增强,需要我们自己实现就定义好代理类。适用于事先就知道有哪些固定操作的场景下。
动态代理是运行时增强,这也是我们常用的一种,AOP就是使用了动态代理,可以自己定义要给哪些类添加某些功能。
而动态代理又可分为JDK实现和CGLib实现,Spring默认开启的是JDK实现,需要注意的是,在SpringBoot2.0以后,SpringBoot默认开启的是CGLib实现,原因是因为方便开发者,如果开发人员注入对象时注入了实现类JDK会报错,而CGLib是通过继承实现,不管是接口还是实现类都可以代理。
JDK实现是调用Proxy类下的newProxyInstance方法,通过类加载器和相应接口去创建代理对象。通过InvocationHandler这个类,通过反射的方式去调用具体要执行哪个方法。所以JDK只能作用于接口。
而CGLib是通过ASM的方式,对字节码进行操作,通过继承这个类来创建代理类。所以CGLib可以作用于所有类,只要不是final修饰的。

装饰器模式:
在开发中我们经常会遇到需要在原有的类的基础上进行增强的场景,就可以使用装饰器模式。
其实JDK的InputStream家族就是使用了装饰器模式。它下面提供了FileInputStream、BufferedInputStream等,都是在不修改原本类的情况下,对它就行包装,增强它的某个功能。
而Spring中的DataSource也是这么使用的。spring并不知道我们具体会使用哪个数据库,所以DataSource只是提供基本功能,具体要根据我们引入了哪个包来决定具体的实现类。

适配器模式:
顾名思义,就是将两个不兼容的东西进行相互的转换,这就需要使用到一个中间类Adapter
在SpringAOP中我们有前置通知,后置通知,返回通知这几种通知,它们分别有其对应的类,而我们需要将其转换为拦截器添加到容器中,这里就要使用到DefaultAdvisorAdapterRegistey这个类,这个类就是起到适配器的作用。

组合模式:
在一个类中引用了另一个类作为字段,就是组合模式。这种模式非常常见,比如部门类中包含员工类。

行为型:

策略模式:
策略模式就是定义好一组算法,在使用时候根据需要来选用具体的策略算法。
比如Spring中Resource类,它规定了其子类具有哪些方法,具体实现交给各个子类。它的子类有UrlResource、ClassPathResource、PathRourse、ServletContextResource等,分别使用了不同的算法来实现getInputStream这个方法。我们在使用的时候就可以根据需要,用多态的方式随便传哪一个都可以。

模板方法模式:

观察者模式:
就是让一个监听器去监听一个时间,当一个对象发生改变,这个对象依赖的对象也会做出相应反应。这个很多时候可以用来做我们的代码解耦,比如添加商品的时候要去刷新商品的索引,就可以通过观察者模式来做到。
Spring中有一个类ApplicationEvent,这是一个事件,它下面有很多的实现类,是Spring给我们提供的一些默认事件,我们也可以通过去继承他来做到自定义事件。
首先,我们写一个类去继承ApplicationEvent,然后再写一个类去继承ApplicationListener<>把刚才的事件类作为泛型传进去。
然后我们就可以通过ApplicationContext中的publishEvent方法去触发事件。