目录
一)SpringMVC
1、SpringMVC的基本结构/SpringMVC有哪些组件?
2、SpringMVC的程序流程
3、springMVC的常用注解有哪些?/springMVC用过哪些注解?
二)Spring
1、Spring的特性/ Spring有哪些很好的特性?/为什么要使用Spring?
2、IoC和aop的作用、原理/说一下Spring的两个核心/AOP主要用到Java的哪些技术呢?/AOP底层通过什么机制来实现的
3、Spring 有哪些主要模块?
4、说一下Springbean的生命周期?
5、Spring bean的加载步骤
6、bean什么时候会被销毁呢?
7、Spring注入的几种方式
8、通常如何获取bean?
9、Spring 自动装配 bean 有哪些方式?
10、注入 Bean 的注解有哪些?/除了@Autowired其他获取bean的注解的方法
11、@Autowired 和@Resource 的区别是什么?
12、Bean 的作用域有哪些?
13、bean的扫描路径
14、单例 Bean 的线程安全问题了解吗?
15、Spring 内部具体有哪几种代理的方式呢?
16、Spring 哪里运用到了反射?
17、Spring 管理事务的方式有几种?
18、Spring 事务中哪几种事务传播行为?
19、说一下 Spring 的事务隔离?
20、Spring 事务中的隔离级别有哪几种?
21、@Transactional(rollbackFor = Exception.class)注解了解吗?
三)SpringBoot
1、Spring,Spring MVC,Spring Boot 之间是什么关系?/Spring,Spring MVC,Spring Boot 之间有什么区别?/Spring和 Spring Boot的区别?/Spring和Spring Boot的关系,为什么要有Spring Boot?
2、Spring boot 相对 Spring有什么优势?/Spring boot 主要特性是什么
3、SpringBoot 是如何实现自动装配的?
4、SpringBoot使用了哪些设计模式?
Spring MVC的核心组件:
DispatcherServlet:中央控制器,把请求给转发到具体的控制类
Controller:具体处理请求的控制器
HandlerMapping:映射处理器,负责映射中央处理器转发给controller时的映射策略
ModelAndView:服务层返回的数据和视图层的封装类
ViewResolver:视图解析器,解析具体的视图
Interceptors:拦截器,负责拦截我们定义的请求然后做处理工作
客户端(浏览器)发送请求,直接请求到DispatcherServlet。
DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler。
解析到对应的Handler(也就是我们平常说的Controller控制器)后,开始由HandlerAdapter适配器处理。
HandlerAdapter会根据Handler来调用真正的处理器处理请求,并处理相应的业务逻辑。
处理器处理完业务后,会返回一个ModelAndView对象,Model是返回的数据对象,View是个逻辑上的View。
ViewResolver会根据逻辑View查找实际的View。
DispaterServlet把返回的Model传给View(视图渲染)。
把View返回给请求者(浏览器)
@Controller:定义了一个控制器类
@RequestMapping:是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
@ResquestParam:把请求中指定名称的参数给控制器中的形参赋值
@ResquestBody:用于获取请求体内容
@PathVariable:用于绑定URL中的占位符
@RequestHeader:用于获取请求消息头
@CookieValue:用于把指定cookie名称的值传入控制器方法参数
@ModelAttribute:可以修饰方法和参数。出现在方法上,表示当前方法会在控制器的方法执行之前执行,先执行。出现在参数上,获取指定的数据给参数赋值
@SessionAttributes:用于多次执行控制器方法间的参数共享
轻量:从大小与开销两方面而言Spring都是轻量的
控制反转:Spring通过控制反转IOC的技术促进了低耦合。
面向切面:Spring提供了面向切面编程的支持。
容器:Spring作为一个容器,可以管理对象的生命周期、对象与对象之间的依赖关系。
框架:Spring可以将简单的组件配置、组合成为复杂的应用。
IoC(InverseofControl:控制反转)是一种设计思想,而不是一个具体的技术实现。IoC的思想就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理。
为什么叫控制反转?
控制:指的是对象创建(实例化、管理)的权力
反转:控制权交给外部环境(Spring框架、IoC容器)
将对象之间的相互依赖关系交给IoC容器来管理,并由IoC容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。IoC容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件或注解即可,完全不用考虑对象是如何被创建出来的。
IoC底层原理:xml解析、工厂模式、反射
AOP(Aspect-OrientedProgramming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,有利于未来的可拓展性和可维护性。
AOP底层原理:SpringAOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么SpringAOP会使用JDKProxy,去创建代理对象,而对于没有实现接口的对象,SpringAOP会使用Cglib生成一个被代理对象的子类来作为代理。
Spring Core
核心模块, Spring 其他所有的功能基本都需要依赖于该模块,主要提供 IoC 依赖注入功能的支持。
Spring Aspects
该模块为与 AspectJ 的集成提供支持。
Spring AOP
提供了面向切面的编程实现。
Spring Data Access/Integration :
Spring Data Access/Integration 由5 个模块组成:
spring-jdbc : 提供了对数据库访问的抽象 JDBC。不同的数据库都有自己独立的 API 用于操作数据库,而 Java 程序只需要和 JDBC API 交互,这样就屏蔽了数据库的影响。
spring-tx : 提供对事务的支持。
spring-orm : 提供对 Hibernate 等 ORM 框架的支持。
spring-oxm :提供对 Castor 等 OXM 框架的支持。
spring-jms : Java 消息服务。
Spring Web
Spring Web 由4 个模块组成:
spring-web :对 Web 功能的实现提供一些最基础的支持。
spring-webmvc :提供对 Spring MVC 的实现。
spring-websocket :提供了对 WebSocket 的支持,WebSocket 可以让客户端和服务端进行双向通信。
spring-webflux :提供对 WebFlux 的支持。WebFlux 是 Spring Framework 5.0 中引入的新的响应式框架。与 Spring MVC 不同,它不需要 Servlet API,是完全异步.
Spring Test
Spring 团队提倡测试驱动开发(TDD)。有了控制反转(IoC)的帮助,单元测试和集成测试变得更简单。
Spring 的测试模块对 JUnit(单元测试框架)、TestNG(类似 JUnit)、Mockito(主要用来 Mock 对象)、PowerMock(解决 Mockito 的问题比如无法模拟 final, static, private 方法)等等常用的测试框架支持的都比较好。
通过构造器创建bean实例(无参数构造)
为bean的属性设置值和对其他bean引用(调用set方法)
把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
调用bean的初始化的方法(需要进行配置初始化的方法)
把bean实例传递bean后置处理器的方法 postProcessAfterInitialization
bean可以使用了(对象获取到了)
当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
Bean容器找到配置文件中SpringBean的定义。
Bean容器利用JavaReflectionAPI创建一个Bean的实例。
如果涉及到一些属性值利用set()
方法设置一些属性值。
如果Bean实现了BeanNameAware
、BeanClassLoaderAware
、BeanFactoryAware
接口等*.Aware
接口,调用相应的方法,传入相应的对象实例。
如果有和加载这个Bean的Spring容器相关的BeanPostProcessor
对象,执行postProcessBeforeInitialization()
方法
如果Bean实现了InitializingBean
接口,执行afterPropertiesSet()
方法。
如果Bean在配置文件中的定义包含init-method属性,执行指定的方法。
如果有和加载这个Bean的Spring容器相关的BeanPostProcessor
对象,执行postProcessAfterInitialization()
方法
当要销毁Bean的时候,如果Bean实现了DisposableBean
接口,执行destroy()
方法。
当要销毁Bean的时候,如果Bean在配置文件中的定义包含destroy-method属性,执行指定的方法。
实例化⼀个applicationContext的对象,创建⼀个beanFactory⼯⼚对象
beanFactory的后置处理器对当前的所有类进⾏扫描
使⽤for循环将所有的类通过⼀个beanDefintion对象进⾏解析和初始化默认参数,并且将实例化后的对象缓存到beanDefintionMap中
再次调⽤beanFactory的后置处理器对beanDefintion对象进⾏⼀些额外的扩展,⽐⽅说⽤户⾃定义实现的⼀些参数属性⽅法
Spring⾸先从singletonObjects (⼀级缓存)中尝试获取,如果获取到了直接return
如果获取不到并且对象在创建中,则尝试从earlySingletonObjects(⼆级缓存)中获取,如果获取到了直接return
如果还是获取不到并且允许从singletonFactories通过getObject获取,则通过 singletonFactory.getObject()(三级缓存)获取,如果获取到了就从singletonFactories中移除,并且放进earlySingletonObjects (⼆级缓存)中
如果三个缓存中都拿不到对象, spring会经过⼀系列的验证并且确定类的构造⽅法后,调⽤类的构造⽅法通过反射实例化⼀个对象,也就是createBean
中间会经过⾮常多的判断,其中最关键的两个点是是否需要注⼊属性,是否需要⽣成代理对象
spring将创建好的bean存⼊到⼀级缓存singletonObject中,此时⼀个bean的初始化完成,随时可以被引⽤,根据⽤户业务做⼀些相关的操作
最后是销毁,在上下⽂初始化失败时,所有已经创建好的bean会销毁,或者当⽤户关闭容器时,bean也会被销毁。除此之外,⽤户也可以⾃⾏调⽤destroy-类的⽅法⼿动销毁⼀个bean
需要看Spring中bean的生命周期,Spring中的生命周期有:singleton,prototype,session,request等。
Spring中的Bean默认是singleton(全局的),随着Spring的存亡而存亡,当bean的引用没有指向任何地方的时候,它就会被回收
prototype又叫多例模式,用的时候就new一下,用完就没有了。
session存在这一次会话session中,session没有过期它就一直存在,session过期后它就没了。
request存在这一次请求中,请求结束了它就结束。
构造方法注入
在配置文件中,通过constructor-arg 标签注入到对应的bean 中。
setter注入
Spring会将property中name值的每个单词首字母转换成大写,然后再在前面拼接上"set"构成一个方法名,然后去对应的类中查找该方法,通过反射调用,实现注入。
如果通过set方法注入属性,那么Spring会通过默认的空参构造方法来实例化对象,所以如果在类中写了一个带有参数的构造方法,一定要把空参数的构造方法写上,否则Spring没有办法实例化对象,导致报错。
基于注解的注入
@Component 可以用于注册所有bean
@Controller 可以用于注册控制层的bean
@Service 可以用于注册服务层的bean
@Repository 可以用于注册持久层(dao层)的bean
通过注解
通过上下文获取:实现ApplicationContextAware类来获取容器中的bean
隐式的bean发现机制和自动装配
在java代码或者XML中进行显示配置
Spring 内置的@Autowired 以及 JDK 内置的@Resource 和@Inject 都可以用于注入 Bean。
@Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。
Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。
当一个接口存在多个实现类的情况下,@Autowired 和@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过@Qualifier 注解来显示指定名称,@Resource可以通过 name 属性来显示指定名称。
singleton: 唯一 bean 实例,Spring 中的 bean 默认都是单例的,对单例设计模式的应用。
prototype: 每次请求都会创建一个新的 bean 实例。
request: 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
session: 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
global-session:全局 session 作用域,仅仅在基于 portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。
默认扫描启动类所在路径下所有的bean
可以在启动类中添加注解,手动指定扫描路径:
@ComponentScan(basePackages = {"com.xxx.service1.*","com.xxx.service2.**"})
单例 Bean 存在线程问题,主要是因为当多个线程操作同一个对象的时候是存在资源竞争的。
常见的有两种解决办法:
在 Bean 中尽量避免定义可变的成员变量。
在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。
不过,大部分 Bean 实际都是无状态(没有实例变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。
静态代理
优点:不改变核心代码的情况下,代理被代理对象执行方法,对方法增强
缺点:
只能代理一个类
创建代理对象需要手写
动态代理
如果要代理的对象,实现了某个接口,那么SpringAOP会使用JDKProxy,去创建代理对象
而对于没有实现接口的对象,SpringAOP会使用Cglib生成一个被代理对象的子类来作为代理。
AOP:AOP底层是基于动态代理
IoC:Spring 通过 XML 配置模式装载 Bean 的过程
数据库的连接:通过Class.forName()加载数据库的驱动程序
编程式事务:在代码中硬编码(不推荐使用): 通过 TransactionTemplate或者 TransactionManager 手动管理事务,实际应用中很少使用。
声明式事务:在 XML 配置文件中配置或者直接基于注解(推荐使用): 实际是通过 AOP 实现(基于@Transactional 的全注解方式使用最多)
事务传播行为是为了解决业务层方法之间互相调用的事务问题。当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
Spring定义了7种事务传播行为:
REQUIRED
使用的最多的一个事务传播行为,经常使用的@Transactional注解默认使用就是这个事务传播行为。如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
REQUIRES_NEW
创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
NESTED
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于REQUIRED。
MANDATORY
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)
这个使用的很少。
若是错误的配置以下3 种事务传播行为,事务将不会发生回滚:
SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
事务隔离级别指的是一个事务对数据的修改与另一个并行的事务的隔离程度,当多个事务同时访问相同数据时,如果没有采取必要的隔离机制,就可能发生以下问题:
脏读:一个未提交事务读到另一个未提交事务修改的数据
不可重复读:一个未提交事务读取到另一个提交事务修改的数据
幻读:一个未提交事务读取到另一个提交事务添加的数据
DEFAULT:使用后端数据库默认的隔离级别,MySQL 默认采用的 REPEATABLE_READ 隔离级别。
READ_UNCOMMITTED**(读未提交):最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读**
READ_COMMITTED**(读已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读**仍有可能发生
REPEATABLE_READ (可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
SERIALIZABLE(串行化): 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
Exception 分为运行时异常 RuntimeException 和非运行时异常。
当@Transactional 注解作用于类上时,该类的所有 public 方法都将具有该类型的事务属性,同时,我们也可以在方法级别上使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。
@Transactional 注解中如果不配置rollbackFor属性,那么事务只会在遇到RuntimeException的时候才会回滚,加上 rollbackFor=Exception.class,可以让事务在遇到非运行时异常时也回滚。
Spring是一款开源的轻量级 Java 开发框架,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。其中最重要的是 Spring-Core 模块,主要提供 IoC 依赖注入功能的支持, Spring 中的其他模块(比如 Spring MVC)的功能实现基本都需要依赖于该模块。
Spring MVC是 Spring 中的一个很重要的模块,主要赋予 Spring 快速构建 MVC 架构的 Web 程序的能力。MVC 是模型(Model)、视图(View)、控制器(Controller)的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代码。
Spring Boot框架是对Spring框架的补充,它消除了Spring框架配置XML的麻烦事,完善了Spring框架的开发环境,使我们可以更加高效的完成编程,并且为我们提供了 spring-boot-starter-web 依赖,这个依赖包含了Tomcat和springmvc等一系列的web依赖(无需部署war文件)。
Spring 是简化 J2EE 企业应用程序开发。Spring Boot 是简化 Spring 开发。
Spring Boot 只是简化了配置,如果需要构建 MVC 架构的 Web 程序,还是需要使用 Spring MVC 作为 MVC 框架,只是说 Spring Boot 简化了 Spring MVC 的很多配置,真正做到开箱即用!
可快速构建独立的Spring应用
Spring Boot主要是通过注解和自动化配置的方式推出的全新框架,旨在快速、敏捷的开发新一代基于Spring框架的应用程序。在构建Spring Boot项目时,只要根据需求选择对应的场景依赖,Spring Boot会自动添加该场景所需要的全部依赖并提供自动化配置,在无需额外手动添加配置的情况下可以快速构建出一个独立的Spring应用程序。
直接嵌入Tomcat、Jetty和Undertow服务器(无需部署WAR文件)
提供依赖启动器简化构建配置
极大程度的自动化配置Spring和第三方库
提供生产就绪功能
极少的代码生成和XML配置
主要是通过SpringBoot 的核心注解 SpringBootApplication,可以把@SpringBootApplication看作是@Configuration、@EnableAutoConfiguration、@ComponentScan 注解的集合。这三个注解的作用分别是:
@EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
@Configuration:允许在上下文中注册额外的 bean 或导入其他配置类
@ComponentScan:扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类,可以自定义不扫描某些 bean。
而在这三个注解中@EnableAutoConfiguration 是实现自动装配的重要注解,但EnableAutoConfiguration 只是一个简单的注解,自动装配核心功能的实现是通过 AutoConfigurationImportSelector类(加载自动装配类)来实现的。
因为AutoConfigurationImportSelector 类实现了 ImportSelector接口,也就实现了这个接口中的 selectImports方法,这个方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中。其中getAutoConfigurationEntry()这个方法是主要负责加载自动配置类的。
这个方法会先判断自动装配开关是否打开。默认spring.boot.enableautoconfiguration=true,可在 application.properties 或 application.yml 中设置
然后获取EnableAutoConfiguration注解中的 exclude 和 excludeName。
接着读取META-INF/spring.factories,获取需要自动装配的所有配置类
总的来说就是:Spring Boot 通过@EnableAutoConfiguration开启自动装配,通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配,自动配置类其实就是通过@Conditional按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖
简单工厂模式
工厂方法模式
单例模式
代理模式
模板方法模式
观察者模式
适配器模式
装饰器模式