本文主要是介绍【设计模式】一秒让你看懂Spring的设计模式(建议收藏),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 🥰 序言
- 🦅 工厂模式
- 🐢 策略模式
- 🐲 单例模式
- 🐝 代理模式
- 🍄 装饰器模式
- 🐬 观察者模式
- 🦜 适配器模式
- 🦁 模板方法模式
- 🐵 责任链设计模式
- 🍹 总结
🥰 序言
应该说设计模式是我们在写代码时候的一种被承认的较好的模式。好的设计模式就像是给代码造了一个很好的骨架,在这个骨架里,你可以知道心在哪里,肺在哪里,因为大多数人都认识这样的骨架,就有了很好的传播性。这是从易读和易传播来感知设计模式的好处。当然设计模式本身更重要的是设计原则的一种实现,比如开闭原则,依赖倒置原则,这些是在代码的修改和扩展上说事。说到底就是人类和代码发生关系的四种场合:阅读,修改,增加,删除。让每一种场合都比较舒服的话,就需要用设计模式。
设计模式作为近几年软件行业高频面试,spring作为我们经常使用的框架,有必要了解spring相关的设计模式并巩固相关面试的漏洞!
🦅 工厂模式
简单工厂
根据 BeanDefinition 生成相应的 Bean 对象
工厂方法
FactoryBean
通过 getObject 方法来返回一个对象
获取对象时:
如果 beanName 没有加 & 号,则获取的是 泛型 T 的对象。
如果添加了 & 号,获取的是实现了FactoryBean 接口本身的对象,如 EhCacheFactoryBean
而正因为它的小巧,它也被广泛的应用在 Spring 内部,以及 Spring 与第三方框架或组件的整合过程中。
🐢 策略模式
Spring的初始化采用了策略模式,不同类型的类采用不同的初始化策略。
public interface InstantiationStrategy {Object instantiate(RootBeanDefinition var1, String var2, BeanFactory var3) throws BeansException;Object instantiate(RootBeanDefinition var1, String var2, BeanFactory var3, Constructor<?> var4, Object... var5) throws BeansException;Object instantiate(RootBeanDefinition var1, String var2, BeanFactory var3, Object var4, Method var5, Object... var6) throws BeansException;
}
🐲 单例模式
饿汉式单例模式在类加载的时候就立即初始化,并且创建单例对象。它是绝对的线程安全、在线程还没出现以前就实现了,不可能存在访问安全问题,Spring 中IoC容器ApplocationContext本身就是典型的饿汉式单例模式。
spring 中加载单例的过程都是在BeanFactory接口中定义的getBean(…)这个方法中定义的,实现默认是在
AbstractBeanFactory中,主要代码功能两点:
- 从缓存中获取单例bean
- 从bean的实例中获取对象
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {//对传入的beanName稍作修改,防止有一些非法字段,然后提取bean 的Namefinal String beanName = transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons.//直接从缓存中获取单例工厂中的objectFactory获取单例Object sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {if (logger.isDebugEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +"' that is not fully initialized yet - a consequence of a circular reference");}else {logger.debug("Returning cached instance of singleton bean '" + beanName + "'");}}//返回对应的实例,从bean实例中获取对象//有时候存在诸如BeanFactory的情况并不是直接返回实例本身而是返回指定方法返回的实例bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {//创建bean,解决了很多关于循环依赖等等很多的功能
其实getBean()这个方法不仅仅和单例相关,还和prototype相关,毕竟只是获取Bean,Bean的scope也可能为prototype
/*** 单例对象的缓存*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 首先通过名字查找这个单例bean存在不存在Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {//查看缓存中是否存在这个bean实例singletonObject = this.earlySingletonObjects.get(beanName);//如果这个时候的bean实例还是为空并且允许懒加载if (singletonObject == null && allowEarlyReference) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;}
上面这段代码中 synchronized (this.singletonObjects) 是关键,但是前提条件
isSingletonCurrentlyInCreation返回值也是为true,也就是这个单例Bean正在创建,所以基本上第一次调用doGetBean的时候上面这个getSingleton基本上都是返回的null,所以进行doGetBean就接着往下运行
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {....//这个前面省略掉部分代码获取 beanDefinitionfinal RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}registerDependentBean(dep, beanName);try {getBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}}
首先 BeanFactory中已经存储了我们从xml解析出来的相关信息放在BeanDefinitionMap(作用后期会讲)中,然后通过这个map获取到RootBeanDefinition(功能后期也会讲,在此理解为一个有属性值,构造方法和其他相关信息的Bean ) ,然后就有个判断if (mbd.isSingleton()) 如果是单例的就接着getSingleton的重载方法,传入的是mbd。
当从缓存中加载单例对象的时候singletonObjects这个map(用来存放缓存的单例),并且只要创建一个单例对象就会把当前的单例对象存放在这个singletonObjects中,这样一来就保证了在getBean的时候这里面永远就只有一个,实现了我们在获取某个对象过得时候才会给她分配内存。既保证了内存高效利用,又是线程安全的。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(beanName, "Bean name must not be null");synchronized (this.singletonObjects) {
// 直接从缓存中获取单例beanObject singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {if (this.singletonsCurrentlyInDestruction) {throw new BeanCreationNotAllowedException(beanName,"Singleton bean creation not allowed while singletons of this factory are in destruction " +"(Do not request a bean from a BeanFactory in a destroy method implementation!)");}if (logger.isDebugEnabled()) {logger.debug("Creating shared instance of singleton bean '" + beanName + "'");}beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = (this.suppressedExceptions == null);if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {singletonObject = singletonFactory.getObject();newSingleton = true;}catch (IllegalStateException ex) {singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {throw ex;}}catch (BeanCreationException ex) {if (recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {ex.addRelatedCause(suppressedException);}}throw ex;}finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}afterSingletonCreation(beanName);}if (newSingleton) {//在singletonObject中添加我们想要加载的单例addSingleton(beanName, singletonObject);}}return singletonObject;}}
我们就从实例中也获取到了Bean,也创建单例Bean的缓存,当下一次还需要这个单例Bean的时候就直接从缓存中获取了。
🐝 代理模式
SpringAop
AOP(Aspect-Oriented Programming:面向切面编程) AOP代表的是一个横向的关系,剖开对象的内部,并且把影响多个类的共同行为抽取出来,作为公共模块(叫做切面Aspect),然后再通过织入的方式把这个切面放进去。
理解来说:就是能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
底层原理
AOP底层是通过动态代理来实现的,同时有JDK动态代理和CGLIB动态代理两种方式:
① 有接口的情况,使用 JDK 动态代理,即创建接口实现类代理对象,增强类的方法。
② 没有接口的情况,使用 CGLIB 动态代理,即创建子类的代理对象,增强类的方法。
JDK proxy VS CGLIB proxy
语法上:
① JDK动态代理需要目标类有父接口
② JDK动态代理产生的代理对象是目标类的兄弟
③ CGLIB动态代理不需要父接口,但是目标类不能被final修饰
④ CGLIB动态代理产生的代理对象是目标类的子类
性能上:
① JDK产生代理对象的性能较高;CGLIB较低
② JDK动态代理调用方法的性能较低;CGLIB较高
③ 两者的适用场合不同:
JDK动态代理适合于频繁创建的场景;
如果是单例或对象池的场景(无需频繁创建代理对象),但需要频繁调用代理方法,优先考虑CGLIB动态代理。
静态代理示例
/*** 接口*/public interface IUserDao {void save();}
/*** 接口实现* 目标对象*/public class UserDao implements IUserDao {public void save() {System.out.println("----已经保存数据!----");}}
/*** 代理对象,静态代理*/public class UserDaoProxy implements IUserDao{//接收保存目标对象private IUserDao target;public UserDaoProxy(IUserDao target){this.target=target;}public void save() {System.out.println("开始事务...");target.save();//执行目标对象的方法System.out.println("提交事务...");}}
/*** 客户端*/public class MainTest {public static void main(String[] args) {//目标对象UserDao target = new UserDao();//代理对象,把目标对象传给代理对象,建立代理关系UserDaoProxy proxy = new UserDaoProxy(target);proxy.save();//执行的是代理的方法}}
动态代理示例
public interface Star {void skill();
}
public class GeGe implements Star {private String name;public GeGe() {}public GeGe(String name) {this.name = name;}@Overridepublic void skill() {System.out.println(name+"在唱歌");System.out.println(name+"在跳舞");System.out.println(name+"在说唱");}
}
public class StarProxy implements InvocationHandler {private Star star;public StarProxy(Star star) {this.star = star;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("接受预约");Object obj = method.invoke(star, args);System.out.println("表演完给粉丝送Basketball");return obj;}
}
public class Marry {public static void main(String[] args) {GeGe gege = new GeGe("坤坤");//创建代理公司对象StarProxy starProxy = new StarProxy(gege);//真实对象的类加载器ClassLoader classLoader = gege.getClass().getClassLoader();//真实对象实现的接口Class<?>[] interfaces = gege.getClass().getInterfaces();//调用处理器Star star = (Star) Proxy.newProxyInstance(classLoader, interfaces, starProxy);star.skill();}
}
创建代理对象就需要用到Proxy类的静态方法:newProxyInstance()
这个方法需要有三个参数,分别是:
- 参数一:真实对象的类加载器
- 参数二:真实对象实现的接口
- 参数三:代理类
静态代理:
①由程序员创建或者由第三方开发工具自动生成。在程序运行之前,代理类的class文件就已经生成存在了。
②每次更新就需要重新写一个静态代理类。
③静态代理从一开始就知道自己要帮哪个类扩充功能。
动态代理:
①动态代理是通过反射机制动态生成的。
②动态代理可以代理对象接口的所有实现类
③动态代理一开始不知道自己要帮哪个类扩充功能,只有执行的时候调用了才知道
④使用动态代理需要使用Proxy的newProxyInstance() 方法来动态创建代理类。
🍄 装饰器模式
SpringAop装饰者代码示例
public interface Calculator {int add(int a, int b);
}public class CalculatorImpl implements Calculator {@Overridepublic int add(int a, int b) {return a + b;}
}public class LoggingHandler implements InvocationHandler {private Object target;public LoggingHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Entering method " + method.getName());Object result = method.invoke(target, args);System.out.println("Exiting method " + method.getName());return result;}
}public static void main(String[] args) {Calculator target = new CalculatorImpl();LoggingHandler handler = new LoggingHandler(target);Calculator proxy = (Calculator) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler);int result = proxy.add(2, 3);System.out.println(result);
}
在上面的代码中,Calculator 是一个计算器接口,CalculatorImpl 是一个实现了 Calculator 接口的实现类,LoggingHandler 是一个实现了 InvocationHandler 接口的类,它用于在调用 Calculator 的 add 方法时输出日志。在 main 方法中,我们先创建了一个 CalculatorImpl 的实例 target,然后创建了一个 LoggingHandler 的实例 handler,再通过调用 Proxy 的 newProxyInstance 方法来创建代理对象 proxy,将 target 对象和 handler 对象传入,从而生成一个代理对象 proxy,最后通过代理对象来调用 Calculator 的 add 方法。在代理对象中,它通过调用 LoggingHandler 的 invoke 方法来在目标对象的 add 方法的前后输出日志。
这里的 LoggingHandler 类就是一个装饰者,通过动态代理技术来将它包装在目标对象的方法调用前后进行增强,从而实现了装饰者模式的应用。
🐬 观察者模式
spring的事件监听机制
Spring事件机制是观察者模式的实现。ApplicationContext中事件处理是由ApplicationEvent类和ApplicationListener接口来提供的。如果一个Bean实现了ApplicationListener接口,并且已经发布到容器中去,每次ApplicationContext发布一个ApplicationEvent事件,这个Bean就会接到通知。ApplicationEvent 事件的发布需要显示触发,要么 Spring 触发,要么我们编码触发。spring内置事件由spring触发。
事件发布
事件,ApplicationEvent,该抽象类继承了EventObject,EventObject是JDK中的类,并建议所有的事件都应该继承自EventObject。
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {Assert.notNull(event, "Event must not be null");Object applicationEvent;//将事件封装成事件对象ApplicationEventif (event instanceof ApplicationEvent) {applicationEvent = (ApplicationEvent)event;} else {applicationEvent = new PayloadApplicationEvent(this, event);if (eventType == null) {eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();}} 广播事件if (this.earlyApplicationEvents != null) {//earlyApplicationEvents。它是一个set,用来存放一些容器启动时需要发布的事件。//在earlyApplicationEvents中的事件被发布、容器彻底启动后,它将被置空this.earlyApplicationEvents.add(applicationEvent);} else {//我们自定义的事件以及容器启动后发送的事件都会走else分支, 重点是这一行代码!!!this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);} 如果有父容器,则在父容器内也进行广播if (this.parent != null) {if (this.parent instanceof AbstractApplicationContext) {((AbstractApplicationContext)this.parent).publishEvent(event, eventType);} else {this.parent.publishEvent(event);}}}
AbstractApplicationContext中对publishEvent的实现一共分为以下几个步骤
首先将传入的事件封装成ApplicationEvent,如果本身已经是ApplicationEvent,则无需处理。直接到第二步。 这里分为两种情况:
1.如果earlyApplicationEvents不为空,那么将当前事件加入earlyApplicationEvents,第二步结束。 earlyApplicationEvents是AbstractApplicationContext中定义的一个字段,用来存放容器启动时需要发布的事件。它会在容器启动的prepareRefresh环节初始化为一个LinkedHashSet。
放在earlyApplicationEvents事件不会立刻发布,而是在容器启动的registerListeners环节进行发布。并且在预置事件发布后,earlyApplicationEvents会被销毁"(this.earlyApplicationEvents = null;)
protected void registerListeners() {// 省略无关代码//....// 发布earlyApplicationEvents中的时间,并且让earlyApplicationEvents为空Set<ApplicationEvent> earlyEventsToProcess =this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (earlyEventsToProcess != null) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent);}}
}
2.如果earlyApplicationEvents为空,则通过getApplicationEventMulticaster拿到事件广播器,然后将事件广播出去。
如果有父容器,比如springMVC有父容器spring等。那么要再父容器内也将此事件进行广播。
SimpleApplicationEventMulticaster的multicastEvent方法是事件发布的核心逻辑,Spring 中事件发布都是通过SimpleApplicationEventMulticaster来实现的。
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);Executor executor = this.getTaskExecutor();Iterator var5 = this.getApplicationListeners(event, type).iterator();while(var5.hasNext()) {ApplicationListener<?> listener = (ApplicationListener)var5.next();if (executor != null) {executor.execute(() -> {this.invokeListener(listener, event);});} else {this.invokeListener(listener, event);}}}
从上面源码可以看出,如果设置了Executor则异步发送(在我们想要异步执行的事件监听器上添加@Async注解),否则同步; 而且可以看出通过 “resolveDefaultEventType(event)” 对发布的事件类型进行了校验,这就是为什么我们可以直接使用泛型来指定我们想接收的事件对象。
继续深入底层,查看invokeListener()方法的源码:
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {ErrorHandler errorHandler = this.getErrorHandler();if (errorHandler != null) {try {this.doInvokeListener(listener, event);} catch (Throwable var5) {errorHandler.handleError(var5);}} else {this.doInvokeListener(listener, event);}
}
上面这个方法内部主要调用了doInvokeListener方法,我们继续往深入看:
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {//这里就是最终回调我们的事件监听器实现逻辑的地方!!!listener.onApplicationEvent(event);} catch (ClassCastException var6) {String msg = var6.getMessage();if (msg != null && !this.matchesClassCastMessage(msg, event.getClass()) && (!(event instanceof PayloadApplicationEvent) || !this.matchesClassCastMessage(msg, ((PayloadApplicationEvent)event).getPayload().getClass()))) {throw var6;}Log loggerToUse = this.lazyLogger;if (loggerToUse == null) {loggerToUse = LogFactory.getLog(this.getClass());this.lazyLogger = loggerToUse;}if (loggerToUse.isTraceEnabled()) {loggerToUse.trace("Non-matching event type for listener: " + listener, var6);}}
}
最后就是回调了listener.onApplicationEvent(event) ,使用对应的ApplicationListener进行接收和处理,事件的通知到此就完成啦!
事件注册
在Spring容器初始化过程中,执行了context.refresh()方法,refresh方法源码如下:
public void refresh() throws BeansException, IllegalStateException {//...其余代码略// 初始化事件广播器this.initApplicationEventMulticaster();this.onRefresh();// 注册监听器this.registerListeners();//...其余代码略
}
先看看是如何初始化事件广播器的,进入子方法initApplicationEventMulticaster();
protected void initApplicationEventMulticaster() {ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();if (beanFactory.containsLocalBean("applicationEventMulticaster")) {// 如果IOC容器中已经有applicationEventMulticaster这个Bean的话,直接赋值给applicationEventMulticasterthis.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);if (this.logger.isTraceEnabled()) {this.logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");}} else {// 如果容器中没有,那么创建一个SimpleApplicationEventMulticaster,并且注册到IOC容器中this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);if (this.logger.isTraceEnabled()) {this.logger.trace("No 'applicationEventMulticaster' bean, using [" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");}}}
上面的大致意思是:先判断容器中有没有提前配置实例化好的事件广播器ApplicationEventMulticaster,如果没有,默认创建一个子类型SimpleApplicationEventMulticaster并注册到容器中, 这个就是前面介绍事件发布代码逻辑里使用的对象了。
事件广播器初始化好了之后,就是注册所有的监听对象ApplicationListener了,看registerListeners方法的源码:
protected void registerListeners() {// 遍历applicationListeners链表中的事件监听器,因为可能有一部分监听器通过addApplicationListener()方法添加;属于api的方式添加Iterator var1 = this.getApplicationListeners().iterator();while(var1.hasNext()) {// 把所有的事件监听器添加到事件广播器中ApplicationListener<?> listener = (ApplicationListener)var1.next();this.getApplicationEventMulticaster().addApplicationListener(listener);}// 从当前容器中找所有ApplicationListener子类;这一部分属于注解|配置方式添加监听器String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);String[] var7 = listenerBeanNames;int var3 = listenerBeanNames.length;for(int var4 = 0; var4 < var3; ++var4) {// 依次把对应的Bean对象添加到事件广播器中String listenerBeanName = var7[var4];this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}// 把监听器还没注册之前就发布的容器启动相关事件依次调用multicastEvent()方法发布出来.Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {Iterator var9 = earlyEventsToProcess.iterator();while(var9.hasNext()) {ApplicationEvent earlyEvent = (ApplicationEvent)var9.next();this.getApplicationEventMulticaster().multicastEvent(earlyEvent);}}}
1)事件的注册:在容器启动时会找到所有的事件监听器,注册到容器中。
2)事件的发布: AbstractApplicationContext中对publishEvent方法进行了实现,发布事件的核心方法的原理是:获取spring容器中管理的监听器,然后for循环容器中的listener,对应事件的listener实现类onApplication方法会被调用,实现对事件的响应。
🦜 适配器模式
HandlerAdapter在 Spring MVC 中使用了适配器模式。HandlerAdapter 主要用于支持不同类型的处理器(如 Controller、HttpRequestHandler 或者 Servlet 等),让它们能够适配统一的请求处理流程。这样,Spring MVC 可以通过一个统一的接口来处理来自各种处理器的请求。在 Spring MVC 的工作流程中,HandlerAdapter 扮演了一个重要角色。以下是其工作原理的简化版:
- 用户发起一个 HTTP 请求到 Spring MVC 应用。
- DispatcherServlet 接收到请求后,首先会调用 HandlerMapping,寻找合适的处理器(Handler)来处理这个请求。
- 找到合适的处理器后,DispatcherServlet 需要找到一个能够处理这个处理器的 HandlerAdapter。为此,它会遍历所有已注册的 HandlerAdapter,调用它们的 supports 方法,检查它们是否支持当前处理器。
- 找到支持当前处理器的 HandlerAdapter 后,DispatcherServlet 会调用该 HandlerAdapter 的 handle 方法,将请求委托给处理器进行处理。
- 处理器处理完请求后,会返回一个 ModelAndView 对象,DispatcherServlet 会将这个对象传递给适当的 ViewResolver,以解析视图并将响应返回给用户。
Spring中的AOP中AdvisorAdapter类
它有三个实现:MethodBeforAdviceAdapter、AfterReturnningAdviceAdapter、ThrowsAdviceAdapter。
public interface AdvisorAdapter {boolean supportsAdvice(Advice var1);MethodInterceptor getInterceptor(Advisor var1);
}
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {private final MethodBeforeAdvice advice;public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;}public Object invoke(MethodInvocation mi) throws Throwable {this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());return mi.proceed();}
}
其他两个类就不看了。Spring会根据不同的AOP配置来使用对应的“Advice”,与策略模式不同的是,一个方法可以同时拥有多个“Advice”。
🦁 模板方法模式
Spring模板方法模式实质是模板方法模式和回调模式的结合,是Template Method不需要继承的另一种实现方式。Spring几乎所有的外接扩展都采用这种模式。
JDBC的抽象和对Hibernate的集成,都采用了一种理念或者处理方式,那就是模板方法模式与相应的Callback接口相结合。
采用模板方法模式是为了以一种统一而集中的方式来处理资源的获取和释放,以JdbcTempalte为例:
public abstract class JdbcTemplate {public final Object execute(String sql){Connection con=null;Statement stmt=null;try{con=getConnection();stmt=con.createStatement();Object retValue=executeWithStatement(stmt,sql);return retValue;}catch(SQLException e){...}finally{closeStatement(stmt);releaseConnection(con);}}protected abstract Object executeWithStatement(Statement stmt, String sql);
}
引入回调原因:
JdbcTemplate是抽象类,不能够独立使用,我们每次进行数据访问的时候都要给出一个相应的子类实现,这样肯定不方便,所以就引入了回调。
public interface StatementCallback{Object doWithStatement(Statement stmt);
}
利用回调方法重写JdbcTemplate方法
public class JdbcTemplate {public final Object execute(StatementCallback callback){Connection con=null;Statement stmt=null;try{con=getConnection();stmt=con.createStatement();Object retValue=callback.doWithStatement(stmt);return retValue;}catch(SQLException e){...}finally{closeStatement(stmt);releaseConnection(con);}}...//其它方法定义
}
Jdbc使用方法如下:
JdbcTemplate jdbcTemplate=...;final String sql=...;StatementCallback callback=new StatementCallback(){public Object=doWithStatement(Statement stmt){return ...;}
}
jdbcTemplate.execute(callback);
🐵 责任链设计模式
Spring MVC责任链使用
Spring Web 中的 HandlerInterceptor,里面有preHandle()、postHandle()、afterCompletion()三个方法,实现这三个方法可以分别在调用"Controller"方法之前,调用"Controller"方法之后渲染"ModelAndView"之前,以及渲染"ModelAndView"之后执行。
public interface HandlerInterceptor {default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return true;}default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception {}default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable Exception ex) throws Exception {}}
HandlerInterceptor就是角色中的抽象处理者,HandlerExecutionChain相当于上述中的Client,用于调用责任链上的各个环节。
public class HandlerExecutionChain {
...@Nullable
private HandlerInterceptor[] interceptors;private int interceptorIndex = -1;boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for (int i = 0; i < interceptors.length; i++) {HandlerInterceptor interceptor = interceptors[i];if (!interceptor.preHandle(request, response, this.handler)) {triggerAfterCompletion(request, response, null);return false;}this.interceptorIndex = i;}}return true;
}void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for (int i = interceptors.length - 1; i >= 0; i--) {HandlerInterceptor interceptor = interceptors[i];interceptor.postHandle(request, response, this.handler, mv);}}
}void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for (int i = this.interceptorIndex; i >= 0; i--) {HandlerInterceptor interceptor = interceptors[i];try {interceptor.afterCompletion(request, response, this.handler, ex);}catch (Throwable ex2) {logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);}}}
}
}
私有的数组 private HandlerInterceptor[] interceptors 用于存储责任链的每个环节,,然后通过interceptorIndex作为指针去遍历责任链数组按顺序调用处理者。在Servlet的一系列拦截器也是采用的责任链模式,有兴趣的读者可以深入研究一下。
🍹 总结
(1)工厂模式:Spring使用工厂模式,通过BeanFactory和ApplicationContext来创建对象
(2)单例模式:Bean默认为单例模式
(3)策略模式:例如Resource的实现类,针对不同的资源文件,实现了不同方式的资源获取策略
(4)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术
(5)模板方法:可以将相同部分的代码放在父类中,而将不同的代码放入不同的子类中,用来解决代码重复的问题。比如RestTemplate, JmsTemplate, JpaTemplate
(6)适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式,Spring MVC中也是用到了适配器模式适配Controller
(7)观察者模式:Spring事件驱动模型就是观察者模式的一个经典应用。
(8)装饰者模式:springAop对于方法的增强
(9)责任链模式:springmvc中的HandlerInterceptor和拦截器
这篇关于【设计模式】一秒让你看懂Spring的设计模式(建议收藏)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!