启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:
(1)@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
(2)@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能。
(3)@ComponentScan:Spring组件扫描。
Spring Boot 核心配置文件bootstrap.properties 和 application.properties 有何区别 ?bootstrap (. yml 或者 . properties):boostrap 由父 ApplicationContext 加载的,比 applicaton 优先加载,配置在应用程序上下文的引导阶段生效。一般来说我们在 Spring Cloud Config 或者 Nacos 中会用到它。且 boostrap 里面的属性不能被覆盖;
application (. yml 或者 . properties): 由ApplicatonContext 加载,用于 spring boot 项目的自动化配置。
在 Spring Boot 里面,可以主要使用以下几种方式来加载配置。
(1)properties文件;
(2)YAML文件;
(3)系统环境变量;
(4)命令行参数;
Spring Boot 是否可以使用 XML 配置 ?Spring Boot 推荐使用 Java 配置而非 XML 配置,但是 Spring Boot 中也可以使用 XML 配置,通过 @importResource 注解可以引入一个 XML 配置。
SpringBoot自动装配原理(1)通过@import(AutoConfigurationimportSelector)实现配置类的导入;
(2)AutoConfigurationimportSelector类实现了importSelector接口,重写了方法selectimport,用于实现选择性批量配置类的装配;
(3)通过Spring提供的SpringFactoriesLoader机制,扫描classpath路径下的meta-INF/spring.factories,读取需要实现自动装配的配置类;
(4)通过条件筛选的方式,把不符合条件的配置类移除,最终完成自动装配。
Spring Boot 中的 starter 到底是什么 ?首先,这个 Starter 并非什么新的技术点,基本上还是基于 Spring 已有功能来实现的。首先它提供了一个自动化配置类,一般命名为 XXXAutoConfiguration ,在这个配置类中通过条件注解来决定一个配置是否生效(条件注解就是 Spring 中原本就有的),然后它还会提供一系列的默认配置,也允许开发者根据实际情况自定义相关配置,然后通过类型安全的属性注入将这些配置属性注入进来,新注入的属性会代替掉默认属性。正因为如此,很多第三方框架,我们只需要引入依赖就可以直接使用了。当然,开发者也可以自定义 Starter
spring-boot-starter-parent 有什么用 ?我们都知道,新创建一个 Spring Boot 项目,默认都是有 parent 的,这个 parent 就是 spring-boot-starter-parent ,spring-boot-starter-parent 主要有如下作用:
- 定义了 Java 编译版本为 1.8 。
- 使用 UTF-8 格式编码。
- 继承自 spring-boot-dependencies,这个里边定义了依赖的版本,也正是因为继承了这个依赖,所以我们在写依赖时才不需要写版本号。
- 执行打包操作的配置。
- 自动化的资源过滤。
- 自动化的插件配置。
- 针对 application.properties 和 application.yml 的资源过滤,包括通过 profile 定义的不同环境的配置文件,例如 application-dev.properties 和 application-dev.yml。
Spring Boot 项目最终打包成的 jar 是可执行 jar ,这种 jar 可以直接通过 java -jar xxx.jar 命令来运行,这种 jar 不可以作为普通的 jar 被其他项目依赖,即使依赖了也无法使用其中的类。
Spring Boot 的 jar 无法被其他项目依赖,主要还是他和普通 jar 的结构不同。普通的 jar 包,解压后直接就是包名,包里就是我们的代码,而 Spring Boot 打包成的可执行 jar 解压后,在 BOOT-INFclasses 目录下才是我们的代码,因此无法被直接引用。如果非要引用,可以在 pom.xml 文件中增加配置,将 Spring Boot 项目打包成两个 jar ,一个可执行,一个可引用。
运行 Spring Boot 有哪几种方式?打包用命令或者放到容器中运行
用 Maven/ Gradle 插件运行
直接执行 main 方法运行
可以不需要,内置了 Tomcat/ Jetty 等容器。
开启 Spring Boot 特性有哪几种方式?继承spring-boot-starter-parent项目
导入spring-boot-dependencies项目依赖
为了在自定义端口上运行 Spring Boot 应用程序,您可以在application.properties 中指定端口。server.port = 8090
SpringBoot中各层的作用DAO层(Mapper层): 持久层,主要与数据库进行交互,同时提供增删改查操作。
Entity层(domain层):实体层,数据库在项目中的类。
Service层(biz(应用)业务层):(基础)业务层,接收Controller传来的数据,进行业务逻辑的处理。
Controller层:(action层) 控制层,负责处理用户请求,接收和校验数据。
Model(模型):模型包含业务模型和数据模型,数据模型⽤于封装数据,业务模型⽤于处理业务。
View(视图): 通常指的就是我们的 jsp 或者 html。作⽤⼀般就是展示数据的。通常视图是依据模型数据创建的。
二、Spring IoC IoC和DI总结:在具体的项目中,其流程为:Controller层调用Service层接口的方法,Service层的实现调用Dao层中的方法,其中调用的参数是使用Entity层进行传递的。
IoC(控制反转):把对象的生命周期托管到Spring容器中,反转是指对象的获取方式被反转了。
DI(依赖注入):IoC容器在运行期间,动态地把某种依赖关系注入到组件中。
三、Spring AOP 四、Spring-MyBatis 五、数据库事务 Spring声明式数据库事务Spring利用其AOP为我们提供了一个数据库事务的约定流程。对于声明式事务,是使用@Transactional进行标注,代表被标注类所有公共非静态的方法都将启用事务功能,@Transactional允许配置的属性有用于配置Spring事务管理器的value和transactionManager,定义事务为只读事务的readOnly,指定异常回滚行为的rollbackFor、rollbackForClassName、noRollbackFor、noRollbackForClassName,传播行为propagation,隔离级别isolation。
事务的隔离级别未提交读:是最低的隔离级别,允许一个事务读取另外一个事务没有提交的数据。
读写提交:一个事务只能读取另外一个事务已经提交的数据,不能读取未提交的数据。
可重复读:克服了读写提交中出现的不可重复读现象。
串行化:数据库最高隔离级别,要求所有的SQL都会按照顺序执行,能够完全保证数据的一致性。
| 项目类型 | 脏读 | 不可重复读 | 幻读 |
| 未提交读 | √ | √ | √ |
| 读写提交 | × | √ | √ |
| 可重复读 | × | × | √ |
| 串行化 | × | × | × |
脏读:事务A、B交替执行,事务A被事务B干扰到了,因为事务A读取到事务B未提交的数据。
不可重复读:在一个事务范围内,两个相同的查询,读取同一条记录,却返回了不同的数据。
幻读:事务A查询一个范围的结果集,另一个并发事务B往这个范围中插入/删除了数据,并静悄悄地提交,然后事务A再次查询相同的范围,两次读取得到的结果集却不一样。
Oracle只能支持读写提交和串行化,默认级别是读写提交。
MySQL能够支持四种,默认级别是可重复读。
事务的传播行为传播行为是指事务方法之间的调用行为。
Spring事务机制通过Propagation枚举类中定义了7中传播行为:
- REQUIRED:需要事务(默认传播行为)。当前存在事务,就沿用当前事务,否则新建一个事务运行子方法。
- SUPPORTS:支持事务。如果当前存在事务,就沿用当前事务,否则继续采用无事务的方式运行子方法。
- MANDATORY:必须使用事务。如果当前存在事务,就沿用当前事务,否则会抛出异常。
- REQUIRES_NEW:无论当前事务是否存在,都会创建新事务运行方法,新事务拥有新的锁和隔离级别等特性。
- NOT_SUPPORTED:不支持事务。当前存在事务时,将挂起事务,运行方法。
- NEVER:不支持事务。如果当前方法存在事务,则抛出异常,否则继续使用无事务机制运行。
- NESTED:当前方法调用子方法时,如果子方法发生异常,回滚子方法执行过的SQL,而不回滚当前方法的事务。
Spring数据库事务的实现原理是AOP,而AOP的原理是动态代理,在自调用的过程中,是类自身的调用,而不是代理对象去调用,那么就不会产生AOP,这样Spring就不能把代码植入到约定流程中,继而@Transactional自调失效用。
解决办法:使用代理对象执行插入用户,克服自调用问题。
六、Spring-Redis 七、Spring-MangoDB 八、Spring MVC Spring MVC流程- 第一步:发起请求到前端控制器(DispatcherServlet)
- 第二步:前端控制器请求HandlerMapping查找 Handler (可以根据xml配置、注解进行查找)
- 第三步:处理器映射器HandlerMapping向前端控制器返回Handler,HandlerMapping会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象,多个HandlerInterceptor拦截器对象),通过这种策略模式,很容易添加新的映射策略
- 第四步:前端控制器调用处理器适配器去执行Handler
- 第五步:处理器适配器HandlerAdapter将会根据适配的结果去执行Handler
- 第六步:Handler执行完成给适配器返回ModelAndView
- 第七步:处理器适配器向前端控制器返回ModelAndView (ModelAndView是springmvc框架的一个底层对象,包括 Model和view)
- 第八步:前端控制器请求视图解析器去进行视图解析 (根据逻辑视图名解析成真正的视图(jsp)),通过这种策略很容易更换其他视图技术,只需要更改视图解析器即可
- 第九步:视图解析器向前端控制器返回View
- 第十步:前端控制器进行视图渲染 (视图渲染将模型数据(在ModelAndView对象中)填充到request域)
- 第十一步:前端控制器向用户响应结果
@Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。
@RequestMapping@RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
@RequestMapping注解有六个属性:
- value:指定请求的实际地址;
- method: 指定请求的method类型, GET、POST、PUT、DELETE等
- consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
- produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
- params: 指定request中必须包含某些参数值是,才让该方法处理。
- headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。
@RequestParam注解,该注解类型用于将指定的请求参数赋值给方法中的形参。
@RequestParam注解有4种属性:
- name属性:该属性的类型是String类型,它可以指定请求头绑定的名称;
- value属性:该属性的类型是String类型,它可以设置是name属性的别名;
- required属性:该属性的类型是boolean类型,它可以设置指定参数是否必须绑定;
- defalutValue属性:该属性的类型是String类型,它可以设置如果没有传递参数可以使用默认值。
@PathVaribale注解可以获得请求url中的动态参数。
@PathVaribale注解只支持一个属性value,类型String,表示绑定的名称,如果省略则默认绑定同名参数。
@RequestHeader@RequestHeader注解用于将请求的头的信息区域数据映射到功能处理方法的参数上。
@RequestHeader注解有4种属性,分别如下:
- name属性:该属性的类型是String类型,它可以指定请求头绑定的名称;
- value属性:该属性的类型是String类型,它可以设置是name属性的别名;
- required属性:该属性的类型是boolean类型,它可以设置指定参数是否必须绑定;
- defalutValue属性:该属性的类型是String类型,它可以设置如果没有传递参数可以使用默认值。
@cookievalue注解用于将请求的cookie数据映射到功能处理方法的参数上。
同样,它和@RequestHeader,还有@RequestParam注解一样,有相同的4种属性,分别如下:
- name属性:该属性的类型是String类型,它可以指定请求头绑定的名称;
- value属性:该属性的类型是String类型,它可以设置是name属性的别名;
- required属性:该属性的类型是boolean类型,它可以设置指定参数是否必须绑定;
- defalutValue属性:该属性的类型是String类型,它可以设置如果没有传递参数可以使用默认值。
@SessionAttributes注解允许我们有选择地指定Model中的哪些属性需要转存到HttpSession对象当中。
@SessionAttributes注解有三个属性,分别如下:
- names属性:该属性的类型是String[],它可以指定Model中属性的名称,即存储在HttpSession当中的属性名称;
- value属性:该属性的类型是String[],它可以设置names属性的别名;
- types属性:该属性的类型是Class>[] ,它可以指定参数是否必须绑定。
注意:@SessionAttributes只能声明在类似,而不能声明在方法上。
@ModelAttribute@ModelAttribute注解将请求参数绑定到Model对象。
@ModelAttribute注解只支持一个属性value,类型为String,表示绑定的属性名称。
其他注解@RequestBody:请求体参数转换
@ReponseBody:返回结果会转为JSON数据集
【JSR303数据验证】
@NotNull:验证规则不能为空
@Valid:启动验证
@InitBinder:可以用来绑定自定义验证器
九、Spring Security Spring Boot 中如何解决跨域问题 ?在后端通过 跨域资源共享(CORS,Cross-origin resource sharing) 来解决跨域问题。要求先发送一个”预检”请求,待服务器批准后才能真正发起跨域访问请求。
- 方式1:返回新的CorsFilter(全局CORS配置)
- 方式2:重写WebMvcConfigurer(全局CORS配置)
- 方式3:使用注解(@CrossOrigin)(局部CORS配置)
- 方式4:手工设置响应头(HttpServletResponse )(局部CORS配置)
通过实现WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。(Interceptor拦截器在servlet之后执行)
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
}
项目中前后端分离部署,所以需要解决跨域的问题。
我们使用cookie存放用户登录的信息,在spring拦截器进行权限控制,当权限不符合时,直接返回给用户固定的json结果。
当用户登录以后,正常使用;当用户退出登录状态时或者token过期时,由于拦截器和跨域的顺序有问题,出现了跨域的现象。
一个http请求,先走filter过滤器,到达servlet后才进行Interceptor拦截器的处理。
返回新的CorsFilter(filter过滤器先于servlet执行)
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowCredentials(true);
UrlbasedCorsConfigurationSource urlbasedCorsConfigurationSource = new UrlbasedCorsConfigurationSource();
urlbasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlbasedCorsConfigurationSource);
}
}



