1.Spring的优点2.Spring用了哪些设计模式3.什么是ioc4.ioc容器初始化过程5.Bean的生命周期6.Bean的作用域7.BeanFactory和FactoryBean的区别8.什么是aop9.aop有哪些实现方式10.aop相关术语11.aop原理(源码分析)12.Spring通知有哪些类型13.Spring事务14.什么是SpringMVC15.SpringMVC的主要组件16.请描述一下SpringMVC的工作流程,描述一下DispatcherServlet的工作流程17.拦截器Interceptor和过滤器Filter的区别18.SpringBoot自动装配19.SpringBoot启动流程1.Spring的优点轻量,基本版本大约2MB。 通过控制反转和依赖注入实现松耦合。 支持面向切面的编程,并且把应用业务逻辑和系统服务分开。 通过切面和模板减少样板式代码。 方便集成各种优秀框架。内部提供了对各种优秀框架的直接支持(如:Hibernate、MyBatis等)。方便程序的测试。Spring支持Junit4,添加注解便可以测试Spring程序。Spring的两大核心ioc(控制反转):他就是不会直接创建对象,而是把对象声明出来,把创建对象的权力交给容器,这么做的目的主要是为了解耦ioc原理:工厂模式 + 反射ioc初始化的时候,先去加载配置文件,然后解析配置文件,Spring就知道扫哪些路径(类)了,Spring就把这些类加载成BeanDefinition(定义Bean的配置元信息接口),生成Spring Bean。然后通过反射进行装配(就知道哪些字段需要注入哪些Bean了)aop(面向切面):将公共逻辑封装成切面,跟业务代码进行分离,可以减少系统的重复代码和降低模块之间的耦合。比如日志处理aop原理:动态代理2.Spring用了哪些设计模式简单工厂模式:BeanFactory,跟据传入的唯一一个标识来获取Bean对象工厂方法模式:FactoryBean3.什么是ioc控制反转,把创建对象的权力交给容器,松耦4.ioc容器初始化过程Spring IOC容器初始化的关键环节就在AbstractApplicationContext#refresh()方法,主要方法都是在refresh()方法中完成@Override(992988)public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) {   // 第⼀步:刷新前的预处理   prepareRefresh();   /*   第⼆步:   获取BeanFactory;默认实现是DefaultListableBeanFactory   加载BeanDefition 并注册到 BeanDefitionRegistry   */   ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();   // 第三步:BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加载器等)   prepareBeanFactory(beanFactory);   try {    // 第四步:BeanFactory准备⼯作完成后进⾏的后置处理⼯作    postProcessBeanFactory(beanFactory);    // 第五步:实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean    invokeBeanFactoryPostProcessors(beanFactory);    // 第六步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执⾏    registerBeanPostProcessors(beanFactory);    // 第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);    initMessageSource();    // 第⼋步:初始化事件派发器    initApplicationEventMulticaster();    // 第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑    onRefresh();    // 第⼗步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器bean    registerListeners();    /*    第⼗⼀步:    初始化所有剩下的⾮懒加载的单例bean    初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)    填充属性    初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、init-method⽅法)    调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处    */    finishBeanFactoryInitialization(beanFactory);    /*    第⼗⼆步:    完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事件 (ContextRefreshedEvent)    */    finishRefresh(); }}5.Bean的生命周期 1)Spring对bean进行实例化 2)Spring将值和bean的引用注入到bean对应的属性中 3)如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name()方法; 4)如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入; 5)如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来 6)如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessBeforeInitialization()方法 7)如果bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet()方法,进行属性设置。类似地,如果bean使用initmethod声明了初始化方法,该方法也会被调用 8)如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessAfterInitialization()方法 9)此时bean已经准备就绪,可以被应用程序使用了,他们将一直驻留在应用上下文中,直到该应用上下文被销毁 10)如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用6.Bean的作用域1)singleton(单例):Spring中的bean默认都是单例的。2)prototype(原型):每次请求都会创建一个新的bean实例。3)request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。4)session:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP session内有效。5)global-session:全局session作用域。Bean是否为线程安全的?原型:线程安全的单例:分为无状态bean和有状态bean有状态的bean在多线程的环境下不安全(业务逻辑对单例的成员属性有修改),一般用prototype模式或者使用threadlocal解决线程安全问题。7.循环依赖怎么解决通过三层缓存第一层:初始化后的Bean第二层:创建好了,但没有初始化的Bean第三层:创建Bean的工厂对象A和BA创建过程中,发现需要B,A就先将自己放到了三级缓存,然后去实例化B了B实例化的时候发现没有A,先查一级缓存,没有,再去查二级缓存,没有,查三级缓存,找到了A然后把三级缓存里面的A放到二级缓存里面,并删除三级缓存里面的AB顺利初始化后,将自己放到一级缓存,此时B已经创建完成,然后继续创建A,A现在可以从一级缓存里拿到B了,A也就可以创建完成了7.BeanFactory和FactoryBean的区别BeanFactory:管理Bean的容器,Spring生成Bean都是由这个接口的实现来管理的FactoryBean:通常是用来创建比较复杂的bean,一般的bean 直接用xml配置即可,但如果一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,直接用xml配置比较麻烦,这时可以考虑用FactoryBean,可以隐藏实例化复杂Bean的细节。8.什么是aop面向切面编程,作为面向对象的一种补充,讲公共逻辑(事务管理,日志,缓存)封装成切面,跟业务代码进行分离,可以减少系统的重复代码和降低模块之间的耦合度。9.aop有哪些实现方式静态代理和动态代理静态代理:代理类在编译阶段生成,在编译阶段将通知织入Java字节码中,也称编译时增强。AspectJ使用的是静态代理。动态代理:代理类在程序运行时创建,AOP框架不会去修改字节码,而是在内存中临时生成一个代理对象,在运行期间对业务方法进行增强,不会生成新类。10.aop相关术语切面(Aspect):切面是通知和切点的结合。通知和切点共同定义了切面的全部内容连接点(join point):指方法,在Spring AOP中,一个连接点总是代表一个方法的执行。连接点是在应用执行过程中能够插入切面的一个点。通知(Advice):切面的工作被称为通知织入(weaving):织入是把切面应用到目标对象并创建新的代理对象的过程。在目标对象的生命周期里有以下时间点可以进行织入:1)编译器:切面在目标类编译时被织入。AspectJ的织入编译器是以这种方式织入切面的。2)类加载期:切面在目标类加载到JVM时被织入。需要特殊的类加载器,它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入就支持以这种方式织入切面。 3)运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。SpringAOP就是以这种方式织入切面。11.aop原理(源码分析)如果我们为spring的某个bean配置了切面,那么spring在创建这个bean的时候,实际上创建的是这个bean的代理对象,我们后续对bean中方法的调用,实际上调用的是代理类重写的代理方法。12.Spring通知有哪些类型通知实际上是程序运行时要通过Spring AOP框架来触发的代码段Spring切面可以应用5种类型的通知:前置通知(Before):在目标方法被调用之前调用通知功能; 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么; 返回通知(After-returning ):在目标方法成功执行之后调用通知; 异常通知(After-throwing):在目标方法抛出异常后调用通知; 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的逻辑。13.Spring事务spring支持的事务管理类型有两种:编程式事务管理:通过编程的方式管理事务,灵活性好,但是难维护声明式事务管理(常用):将业务代码和事务管理隔离,只需用注解和XML配置来管理事务(主要是通过注解@Transactional)其实事务操作就是AOP的一个核心体验,当一个方法添加@Transactional注解之后,spring会基于这个类生成一个代理对象,会将这个代理对象作为bean,当使用这个代理对象的方法的时候,如果有事务处理,那么会先把事务的自动提交给业务,然后就执行具体逻辑,如果没有异常就直接提交,出现异常就进行回滚。spring事务传播行为解决 多个事务方法相互调用时,事务如何在在这方法中传播14.什么是SpringMVCSpringMVC是一个基于Java,实现了MVC设计模式的请求驱动类型的轻量级Web框架。通过把模型(Model)-视图(View)-控制器(Controller)分离,将web层进行解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合它解决了WEB开发中常见的问题(参数接收,文件上传,表单校验,国际化),支持Restful风格的url请求15.SpringMVC的主要组件1).HandlerMapping(处理器映射器)是用来查找Handler的,标注了@RequestMapping的每个方法都可以看成一个Handler,Handler负责具体实际的请求处理,在请求达到后,HandlerMapping的作用便是找到请求相应的处理器Handler和Interceptor2).HandlerAdapter(处理器适配器)要让固定的Servlet处理方法调用Handler来进行处理当HandlerMapping获取了定位请求处理器Handler,DispatcherServlet会将得到的Handler告知HandlerAdapter,HandlerAdapter再根据请求去定位请求的具体处理方法是哪一个3).HandlerExceptionResolver用于处理Handler产生的异常清空。它的作用是跟据异常设置ModelAndView,之后交给渲染方法进行渲染,渲染方法会将ModelAndView渲染成页面4).ViewResolver(视图解析器)找到渲染的模板(第一件大事)和所用的技术(第二件大事,其实就是找到视图的类型,如jsp)5).RequestToViewNameTranslatorRequestToViewNameTranslator 组件的作⽤是从请求中获取 ViewName.因为 ViewResolver 根据ViewName 查找 View,但有的 Handler 处理完成之后,没有设置 View,也没有设置 ViewName,便要通过这个组件从请求中查找 ViewName。6).LocaleResolverViewResolver 组件的 resolveViewName ⽅法需要两个参数,⼀个是视图名,⼀个是 Locale。LocaleResolver ⽤于从请求中解析出 Locale,⽐如中国 Locale 是 zh-CN,⽤来表示⼀个区域。这个组件也是 i18n 的基础。7).ThemeResolver是⽤来解析主题的。主题是样式、图⽚及它们所形成的显示效果的集合。8).MultipartResolverMultipartResolver ⽤于上传请求,通过将普通的请求包装成 MultipartHttpServletRequest 来实现。MultipartHttpServletRequest 可以通过 getFile() ⽅法 直接获得⽂件。如果上传多个⽂件,还可以调⽤ getFileMap()⽅法得到Map<FileName,File>这样的结构,MultipartResolver 的作⽤就是封装普通的请求,使其拥有⽂件上传的功能。9).FlashMapManagerFlashMap ⽤于重定向时的参数传递,⽐如在处理⽤户订单时候,为了避免重复提交,可以处理完post请求之后重定向到⼀个get请求,这个get请求可以⽤来显示订单详情之类的信息。16.请描述一下SpringMVC的工作流程,描述一下DispatcherServlet的工作流程(1)用户发送请求至前端控制器DispatcherServlet;(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handler;(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;(4)DispatcherServlet 调用 HandlerAdapter处理器适配器;(5)HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);-------这里才去了controller的handler(6)Handler执行完成返回ModelAndView;-------handler执行完毕,要把数据返回给前端了(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;VIewResolver的作用:找到渲染的模板(第一件大事)和所用的技术(第二件大事,其实就是找到视图的类型,如jsp)(9)ViewResolver解析后返回具体View;(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)(11)DispatcherServlet响应用户。17.拦截器Interceptor和过滤器Filter的区别过滤器是servlet中的接口,主要可以用于在请求进入servlet之前拦截请求HttpServletRequest并跟据需要进行一些检查等逻辑操作,也可以在HttpServletResponse返回客户端之前进行一些逻辑操作。作用是用于对传入的request和响应的response进行进行一些处理,比如对请求参数进行校验,或者设置,检验头部信息,再或者进行一些非法行为校验拦截器是Servlet中的接口,所以它可以获取到spring中的一些bean和其他资源,在面向切面编程中应用比较广,拦截其实就是一种AOP思想18.SpringBoot自动装配1)@SpringBootApplication2)@EnableAutoConfiguration //启动自动配置功能,其实就是借助@Import来收集所有符合自动配置条件的bean定义,并加载到ioc容器3)上面这个是一个组合注解,包含两个注解如下:@AutoConfigurationPackage   //自动配置包里面包含了@Import({Registrar.Class}),它就是将Registrar这个组件导入到容器中,可查看Registrar类中的registerBeanDefinitions就是导入组件类的具体实现@Import({AutoConfigurationImportSelector.class})    //自动配置类扫描导入AutoConfigurationImportSelector可以帮助springboot应用将所有符合条件的@Configuration配置到加载到当前springboot创建并使用的ioc容器如果继续研究这个方法,追踪过去,可以看到AutoConfigurationImportSelector类是通过selectImports方法执行,使用内部工具类SpringFactoriesLoader,查找classpath上所有jar包中的/META-INF/spring.factories进行加载,19.SpringBoot启动流程通过run方法,做两件事情1)SpringApplication实例的初始化创建2)调用run()启动项目详细可看源码:SpringApplication初始化:我们逐步分析:第一步:用于判断当前webApplicationType应用的类型。deduceFromClasspath()方法用于查看Classpath类路径下是否存在某个特征类,从而判断当前webApplicationType类型是servlet应用(spring5之前的传统MVC应用)还是reactive应用(spring5开始出现的WebFlux交互式应用)第二步:在初始化器设置过程中,会使用Spring类加载器SpringFactoriesLoader从META-INF/spring.factories类路径下的spring.factories文件中获取所有的可用初始化器ApplicationContextInitializer第三步:类似上一步,从spring.factories文件中获取所有可用的监听器类ApplicationListener第四步:设置项目启动类run()启动运行:public ConfigurableApplicationContext run(String... args) {     StopWatch stopWatch = new StopWatch(); stopWatch.start();     ConfigurableApplicationContext context = null;     Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();                 this.configureHeadlessProperty();     // 第一步:获取并启动监听器     SpringApplicationRunListeners listeners = this.getRunListeners(args);     listeners.starting();     Collection exceptionReporters;     try {        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);         // 第二步:根据SpringApplicationRunListeners以及参数来准备环境         ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment);         // 准备Banner打印器 - 就是启动Spring Boot的时候打印在console上的ASCII艺术字体         Banner printedBanner = this.printBanner(environment);         // 第三步:创建Spring容器         context = this.createApplicationContext();         exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, new Object[]{context});         // 第四步:Spring容器前置处理         this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);         // 第五步:刷新容器         this.refreshContext(context);         // 第六步:Spring容器后置处理         this.afterRefresh(context, applicationArguments);         stopWatch.stop();         if(this.logStartupInfo) {             (new StartupInfoLogger(this.mainApplicationClass)) .logStarted(this.getApplicationLog(), stopWatch); }         // 第七步:发出结束执行的事件         listeners.started(context);         // 返回容器         this.callRunners(context, applicationArguments);     } catch (Throwable var10) {         this.handleRunFailure(context, var10, exceptionReporters, listeners);         throw new IllegalStateException(var10);     }    try {        listeners.running(context);         return context;    } catch (Throwable var9) {         this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);         throw new IllegalStateException(var9);     } }20.Starerstarer相当于模块,它能将模块所需的依赖整合起来并对模块内的bean跟据环境进行自动配置。使用者只需要依赖相应功能的starer。原理:主要还是基于它提供的起步依赖和自动配置起步依赖:其实就是将具备某种功能的坐标打包到一起,可以简化依赖导入的过程。自动配置:就是无须手动配置xml,自动配置并管理bean,可以简化开发过程。
点赞 13
评论 2
全部评论

相关推荐

机械岗~感谢tp
小花的沉默:广工拿到的我直接开吃
点赞 评论 收藏
分享
07-28 00:10
已编辑
门头沟学院 算法工程师
码农索隆:这哥们库库在我帖子下评论
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务