965845131
0164-21666816
导航

您的位置:主页 > 摄影业务 >

面试官:“谈谈Spring中都用到了那些设计模式?”。

本文摘要:我自己总结的Java学习的系统知识点以及面试问题,已经开源,现在已经 41k+ Star。会一直完善下去,接待建议和指导,同时也接待Star: GitHub - Snailclimb/JavaGuide: 【Java学习+面试指南】 一份涵盖大部门Java法式员所需要掌握的焦点知识。JDK 中用到了那些设计模式?Spring 中用到了那些设计模式?这两个问题,在面试中比力常见。 我在网上搜索了一下关于 Spring 中设计模式的解说险些都是千篇一律,而且大部门都年月久远。

yobo体育全站app

我自己总结的Java学习的系统知识点以及面试问题,已经开源,现在已经 41k+ Star。会一直完善下去,接待建议和指导,同时也接待Star: GitHub - Snailclimb/JavaGuide: 【Java学习+面试指南】 一份涵盖大部门Java法式员所需要掌握的焦点知识。JDK 中用到了那些设计模式?Spring 中用到了那些设计模式?这两个问题,在面试中比力常见。

我在网上搜索了一下关于 Spring 中设计模式的解说险些都是千篇一律,而且大部门都年月久远。所以,花了几天时间自己总结了一下,由于我的小我私家能力有限,文中如有任何错误列位都可以指出。另外,文章篇幅有限,对于设计模式以及一些源码的解读我只是一笔带过,这篇文章的主要目的是回首一下 Spring 中的常见的设计模式。

Design Patterns(设计模式) 表现面向工具软件开发中最好的盘算机编程实践。Spring 框架中广泛使用了差别类型的设计模式,下面我们来看看到底有哪些设计模式?控制反转(IoC)和依赖注入(DI)IoC(Inversion of Control,控制翻转) 是Spring 中一个很是很是重要的观点,它不是什么技术,而是一种解耦的设计思想。它的主要目的是借助于“第三方”(Spring 中的 IOC 容器) 实现具有依赖关系的工具之间的解耦(IOC容易治理工具,你只管使用即可),从而降低代码之间的耦合度。

IOC 是一个原则,而不是一个模式,以下模式(但不限于)实现了IoC原则。ioc-patternsSpring IOC 容器就像是一个工厂一样,当我们需要建立一个工具的时候,只需要设置好设置文件/注解即可,完全不用思量工具是如何被建立出来的。IOC 容器卖力建立工具,将工具毗连在一起,设置这些工具,并从建立中处置惩罚这些工具的整个生命周期,直到它们被完全销毁。

在实际项目中一个 Service 类如果有几百甚至上千个类作为它的底层,我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的结构函数,这可能会把人逼疯。如果使用 IOC 的话,你只需要设置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开举事度。关于Spring IOC 的明白,推荐看这一下知乎的一个回覆:https://www.zhihu.com/question/23277575/answer/169698662 ,很是不错。

控制翻转怎么明白呢? 举个例子:"工具a 依赖了工具 b,当工具 a 需要使用 工具 b的时候必须自己去建立。可是当系统引入了 IOC 容器后, 工具a 和工具 b 之前就失去了直接的联系。这个时候,当工具 a 需要使用 工具 b的时候, 我们可以指定 IOC 容器去建立一个工具b注入到工具 a 中"。工具 a 获得依赖工具 b 的历程,由主动行为变为了被动行为,控制权翻转,这就是控制反转名字的由来。

DI(Dependecy Inject,依赖注入)是实现控制反转的一种设计模式,依赖注入就是将实例变量传入到一个工具中去。工厂设计模式Spring使用工厂模式可以通过 BeanFactory 或 ApplicationContext 建立 bean 工具。

两者对比:BeanFactory :延迟注入(使用到某个 bean 的时候才会注入),相比于BeanFactory来说会占用更少的内存,法式启动速度更快。ApplicationContext :容器启动的时候,不管你用没用到,一次性建立所有 bean。BeanFactory 仅提供了最基本的依赖注入支持,ApplicationContext 扩展了 BeanFactory ,除了有BeanFactory的功效另有分外更多功效,所以一般开发人员使用ApplicationContext会更多。

ApplicationContext的三个实现类:ClassPathXmlApplication:把上下文文件当成类路径资源。FileSystemXmlApplication:从文件系统中的 XML 文件载入上下文界说信息。

XmlWebApplicationContext:从Web系统中的XML文件载入上下文界说信息。Example:import org.springframework.context.ApplicationContext;import org.springframework.context.support.FileSystemXmlApplicationContext;public class App { public static void main(String[] args) { ApplicationContext context = new FileSystemXmlApplicationContext( "C:/work/IOC Containers/springframework.applicationcontext/src/main/resources/bean-factory-config.xml"); HelloApplicationContext obj = (HelloApplicationContext) context.getBean("helloApplicationContext"); obj.getMsg(); }}单例设计模式在我们的系统中,有一些工具其实我们只需要一个,好比说:线程池、缓存、对话框、注册表、日志工具、充当打印机、显卡等设备驱动法式的工具。

事实上,这一类工具只能有一个实例,如果制造出多个实例就可能会导致一些问题的发生,好比:法式的行为异常、资源使用过量、或者纷歧致性的效果。使用单例模式的利益:对于频繁使用的工具,可以省略建立工具所花费的时间,这对于那些重量级工具而言,是很是可观的一笔系统开销;由于 new 操作的次数淘汰,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停马上间。Spring 中 bean 的默认作用域就是 singleton(单例)的。除了 singleton 作用域,Spring 中 bean 另有下面几种作用域:prototype : 每次请求都市建立一个新的 bean 实例。

request : 每一次HTTP请求都市发生一个新的bean,该bean仅在当前HTTP request内有效。session : 每一次HTTP请求都市发生一个新的 bean,该bean仅在当前 HTTP session 内有效。

global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码(例如:HTML)片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处置惩罚HTTP请求。

可是,与 servlet 差别,每个 portlet 都有差别的会话Spring 实现单例的方式:xml:<bean id="userService" class="top.snailclimb.UserService" scope="singleton"/>注解:@Scope(value = "singleton")Spring 通过 ConcurrentHashMap 实现单例注册表的特殊方式实现单例模式。Spring 实现单例的焦点代码如下:// 通过 ConcurrentHashMap(线程宁静) 实现单例注册表private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "'beanName' must not be null"); synchronized (this.singletonObjects) { // 检查缓存中是否存在实例 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { //...省略了许多代码 try { singletonObject = singletonFactory.getObject(); } //...省略了许多代码 // 如果实例工具在不存在,我们注册到单例注册表中。

addSingleton(beanName, singletonObject); } return (singletonObject != NULL_OBJECT ? singletonObject : null); } } //将工具添加到单例注册表 protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT)); } }}署理设计模式署理模式在 AOP 中的应用AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所配合挪用的逻辑或责任(例如事务处置惩罚、日志治理、权限控制等)封装起来,便于淘汰系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。Spring AOP 就是基于动态署理的,如果要署理的工具,实现了某个接口,那么Spring AOP会使用JDK Proxy,去建立署理工具,而对于没有实现接口的工具,就无法使用 JDK Proxy 去举行署理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被署理工具的子类来作为署理,如下图所示:SpringAOPProcess固然你也可以使用 AspectJ ,Spring AOP 已经集成了AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。使用 AOP 之后我们可以把一些通用功效抽象出来,在需要用到的地方直接使用即可,这样大大简化了代码量。我们需要增加新功效时也利便,这样也提高了系统扩展性。

日志功效、事务治理等等场景都用到了 AOP。Spring AOP 和 AspectJ AOP 有什么区别?Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。Spring AOP 基于署理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。

Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功效越发强大,可是 Spring AOP 相对来说更简朴,如果我们的切面比力少,那么两者性能差异不大。

可是,当切面太多的话,最好选择 AspectJ ,它比Spring AOP 快许多。模板方法模板方法模式是一种行为设计模式,它界说一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重界说该算法的某些特定步骤的实现方式。

模板方法UML图public abstract class Template { //这是我们的模板方法 public final void TemplateMethod(){ PrimitiveOperation1(); PrimitiveOperation2(); PrimitiveOperation3(); } protected void PrimitiveOperation1(){ //当前类实现 } //被子类实现的方法 protected abstract void PrimitiveOperation2(); protected abstract void PrimitiveOperation3();}public class TemplateImpl extends Template { @Override public void PrimitiveOperation2() { //当前类实现 } @Override public void PrimitiveOperation3() { //当前类实现 }}Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 末端的对数据库操作的类,它们就使用到了模板模式。一般情况下,我们都是使用继续的方式来实现模板模式,可是 Spring 并没有使用这种方式,而是使用Callback 模式与模板方法模式配合,既到达了代码复用的效果,同时增加了灵活性。

视察者模式视察者模式是一种工具行为型模式。它表现的是一种工具与工具之间具有依赖关系,当一个工具发生改变的时候,这个工具所依赖的工具也会做出反映。

Spring 事件驱动模型就是视察者模式很经典的一个应用。Spring 事件驱动模型很是有用,在许多场景都可以解耦我们的代码。好比我们每次添加商品的时候都需要重新更新商品索引,这个时候就可以使用视察者模式来解决这个问题。

Spring 事件驱动模型中的三种角色事件角色ApplicationEvent (org.springframework.context包下)充当事件的角色,这是一个抽象类,它继续了java.util.EventObject并实现了 java.io.Serializable接口。Spring 中默认存在以下事件,他们都是对 ApplicationContextEvent 的实现(继续自ApplicationContextEvent):ContextStartedEvent:ApplicationContext 启动后触发的事件;ContextStoppedEvent:ApplicationContext 停止后触发的事件;ContextRefreshedEvent:ApplicationContext 初始化或刷新完成后触发的事件;ContextClosedEvent:ApplicationContext 关闭后触发的事件。

ApplicationEvent-Subclass事件监听者角色ApplicationListener 充当了事件监听者角色,它是一个接口,内里只界说了一个 onApplicationEvent()方法来处置惩罚ApplicationEvent。ApplicationListener接口类源码如下,可以看出接口界说看出接口中的事件只要实现了 ApplicationEvent就可以了。所以,在 Spring中我们只要实现 ApplicationListener 接口实现 onApplicationEvent() 方法即可完成监听事件package org.springframework.context;import java.util.EventListener;@FunctionalInterfacepublic interface ApplicationListener<E extends ApplicationEvent> extends EventListener { void onApplicationEvent(E var1);}事件公布者角色ApplicationEventPublisher 充当了事件的公布者,它也是一个接口。

@FunctionalInterfacepublic interface ApplicationEventPublisher { default void publishEvent(ApplicationEvent event) { this.publishEvent((Object)event); } void publishEvent(Object var1);}ApplicationEventPublisher 接口的publishEvent()这个方法在AbstractApplicationContext类中被实现,阅读这个方法的实现,你会发现实际上事件真正是通过ApplicationEventMulticaster来广播出去的。详细内容过多,就不在这里分析了,后面可能会单独写一篇文章提到。Spring 的事件流程总结界说一个事件: 实现一个继续自 ApplicationEvent,而且写相应的结构函数;界说一个事件监听者:实现 ApplicationListener 接口,重写 onApplicationEvent() 方法;使用事件公布者公布消息: 可以通过 ApplicationEventPublisher 的 publishEvent() 方法公布消息。

Example:// 界说一个事件,继续自ApplicationEvent而且写相应的结构函数public class DemoEvent extends ApplicationEvent{ private static final long serialVersionUID = 1L; private String message; public DemoEvent(Object source,String message){ super(source); this.message = message; } public String getMessage() { return message; }// 界说一个事件监听者,实现ApplicationListener接口,重写 onApplicationEvent() 方法;@Componentpublic class DemoListener implements ApplicationListener<DemoEvent>{ //使用onApplicationEvent吸收消息 @Override public void onApplicationEvent(DemoEvent event) { String msg = event.getMessage(); System.out.println("吸收到的信息是:"+msg); }}// 公布事件,可以通过ApplicationEventPublisher 的 publishEvent() 方法公布消息。@Componentpublic class DemoPublisher { @Autowired ApplicationContext applicationContext; public void publish(String message){ //公布事件 applicationContext.publishEvent(new DemoEvent(this, message)); }}当挪用 DemoPublisher 的 publish() 方法的时候,好比 demoPublisher.publish("你好") ,控制台就会打印出:吸收到的信息是:你好。

适配器模式适配器模式(Adapter Pattern) 将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起事情,其别名为包装器(Wrapper)。spring AOP中的适配器模式我们知道 Spring AOP 的实现是基于署理模式,可是 Spring AOP 的增强或通知(Advice)使用到了适配器模式,与之相关的接口是AdvisorAdapter。Advice 常用的类型有:BeforeAdvice(目的方法挪用前,前置通知)、AfterAdvice(目的方法挪用后,后置通知)、AfterReturningAdvice(目的方法执行竣事后,return之前)等等。

每个类型Advice(通知)都有对应的拦截器:MethodBeforeAdviceInterceptor、AfterReturningAdviceAdapter、AfterReturningAdviceInterceptor。Spring预界说的通知要通过对应的适配器,适配成 MethodInterceptor接口(方法拦截器)类型的工具(如:MethodBeforeAdviceInterceptor 卖力适配 MethodBeforeAdvice)。

spring MVC中的适配器模式在Spring MVC中,DispatcherServlet 凭据请求信息挪用 HandlerMapping,剖析请求对应的 Handler。剖析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由HandlerAdapter 适配器处置惩罚。

HandlerAdapter 作为期望接口,详细的适配器实现类用于对目的类举行适配,Controller 作为需要适配的类。为什么要在 Spring MVC 中使用适配器模式? Spring MVC 中的 Controller 种类众多,差别类型的 Controller 通过差别的方法来对请求举行处置惩罚。

如果倒霉用适配器模式的话,DispatcherServlet 直接获取对应类型的 Controller,需要的自行来判断,像下面这段代码一样:if(mappedHandler.getHandler() instanceof MultiActionController){ ((MultiActionController)mappedHandler.getHandler()).xxx }else if(mappedHandler.getHandler() instanceof XXX){ ... }else if(...){ ... } 如果我们再增加一个 Controller类型就要在上面代码中再加入一行 判断语句,这种形式就使得法式难以维护,也违反了设计模式中的开闭原则 – 对扩展开放,对修改关闭。装饰者模式装饰者模式可以动态地给工具添加一些分外的属性或行为。相比于使用继续,装饰者模式越发灵活。

简朴点儿说就是当我们需要修改原有的功效,但我们又不愿直接去修改原有的代码时,设计一个Decorator套在原有代码外面。其实在 JDK 中就有许多地方用到了装饰者模式,好比 InputStream家族,InputStream 类下有 FileInputStream (读取文件)、BufferedInputStream (增加缓存,使读取文件速度大大提升)等子类都在不修改InputStream 代码的情况下扩展了它的功效。

装饰者模式示意图Spring 中设置 DataSource 的时候,DataSource 可能是差别的数据库和数据源。我们能否凭据客户的需求在少修改原有类的代码下动态切换差别的数据源?这个时候就要用到装饰者模式(这一点我自己还没太明白详细原理)。Spring 中用到的包装器模式在类名上含有 Wrapper或者 Decorator。这些类基本上都是动态地给一个工具添加一些分外的职责总结Spring 框架中用到了哪些设计模式:工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 建立 bean 工具。

署理设计模式 : Spring AOP 功效的实现。单例设计模式 : Spring 中的 Bean 默认都是单例的。

模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 末端的对数据库操作的类,它们就使用到了模板模式。包装器设计模式 : 我们的项目需要毗连多个数据库,而且差别的客户在每次会见中凭据需要会去会见差别的数据库。这种模式让我们可以凭据客户的需求能够动态切换差别的数据源。

视察者模式: Spring 事件驱动模型就是视察者模式很经典的一个应用。适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。

……参考《Spring技术内幕》https://blog.eduonix.com/java-programming-2/learn-design-patterns-used-spring-framework/http://blog.yeamin.top/2018/03/27/单例模式-Spring单例实现原理分析/https://www.tutorialsteacher.com/ioc/inversion-of-controlhttps://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/observer.htmlhttps://juejin.im/post/5a8eb261f265da4e9e307230https://juejin.im/post/5ba28986f265da0abc2b6084。


本文关键词:yobo体育官网下载,面试,官,“,谈谈,Spring,中,都用,到了,那些

本文来源:yobo体育全站app-www.hbxyschem.com