什么是 Spring Boot?
Spring Boot 是 Spring 开源组织下的子项目,其设计目的是专注于Spring应用的开发,开发人员可以把更多的精力放在业务代码上,而无需过多关注XML的配置,从而简化Spring应用开发,提高开发效率
Spring Boot 有哪些优点/Spring boot 相对 Spring有什么优势 ?
1.可快速构建独立的Spring应用
Spring Boot主要是通过注解和自动化配置的方式推出的全新框架,旨在快速、敏捷的开发新一代基于Spring框架的应用程序。在构建Spring Boot项目时,只要根据需求选择对应的场景依赖,Spring Boot会自动添加该场景所需要的全部依赖并提供自动化配置,在无需额外手动添加配置的情况下可以快速构建出一个独立的Spring应用程序。
2.直接嵌入Tomcat、Jetty和Undertow服务器(无需部署WAR文件)
Spring Boot项目不需要像传统的Spring应用一样打成WAR包的形式部署到Tomcat、Jetty或Undertow服务器中,运行一个Spring Boot项目,可以直接将项目打成JAR包的形式,并通过命令“java -jar xx.jar”运行。这是因为,Spring Boot项目内嵌了Tomcat、Jetty和Undertow服务器,因此在部署过程中减少了对第三方插件的依赖和管理。
3.提供依赖启动器简化构建配置
在Spring Boot项目构建过程中,无需准备各种独立的JAR文件,只需在构建项目时根据开发场景需求选择对应的依赖启动器“starter”即可,在引入的依赖启动器“starter”内部已经包含了对应开发场景所需的依赖,并会自动下载和拉取相关JAR包。例如,在Web开发时,只需在构建项目时选择对应的Web场景依赖启动器spring-boot-starter-web,Spring Boot项目便会自动导入spring-webmvc、spring-web、spring-boot-starter-tomcat等子依赖,并自动下载和拉取Web开发需要的相关JAR包。
4.极大程度的自动化配置Spring和第三方库
Spring Boot充分考虑到了与传统Spring框架以及其他第三方库融合的场景,在提供了各种场景依赖启动器的基础上,内部还默认提供了大量的各种自动化配置类(例如RedisAutoConfiguration)。使用Spring Boot开发项目时,一旦引入了某个场景的依赖启动器,Spring Boot内部提供的默认自动化配置类就会生效,开发者无需再手动进行配置文件的配置(除非开发者修改了相关默认配置,例如Redis地址、密码等),从而极大减少了开发人员的工作量,提高了程序的开发效率。
5.提供监控应用
Spring Boot提供了一些用于生产环境运行时的特性,例如指标、健康检查和外部化配置。其中,指标和监控检查可以很方便的帮助运维人员在运维期间监控项目运行情况;外部化配置可以很方便的让运维人员快速、方便的外部化配置和部署工作。
6.极少的代码生成和XML配置
Spring Boot框架内部已经实现了与Spring以及其他常用第三方库的整合连接,并提供了默认最优化的整合配置,使用时基本上不需要额外生成配置代码和XML配置文件。在需要自定义配置的情况下,Spring Boot更加提倡使用Java config(Java配置类)替换传统的XML配置方式,这样更加方便查看和管理。
Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?
启动类上面的注解是@SpringBootApplication,它是 Spring Boot 的核心注解
主要组合包含了以下 3 个注解:
1、@SpringBootConfiguration
@SpringBootConfiguration里面就只有一个@Configuration主要注解,也就是把该类变成一个配置类所以@SpringBootConfiguration就相当于@Configuration。实现配置文件的功能
2、@EnableAutoConfiguration
@EnableAutoConfiguration是由 @AutoConfigurationPackage和@Import(EnableAutoConfigurationImportSelector.class)这两个组成的
打开自动配置的功能,帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot,并创建对应配置类的Bean,并把该Bean实体交给IoC容器进行管理。
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
如上所示可以关闭某个自动配置的选项,如关闭数据源自动配置功能
3、@ComponentScan
@ComponentScan注解是Spring组件扫描注解,默认就会装配标识了@Controller,@Service,@Repository,@Component注解的类到spring容器中
什么是 JavaConfig?JavaConfig 的优点?
JavaConfig就是使用注解来配置Bean,为 Spring IoC 容器的配置提供了纯Java 方法。它有助于避免使用 XML 配置。
使用 JavaConfig 的优点
1、面向对象的配置。javaConfig使用纯java代码的方式,可以充分利用复用、继承、多态等特性,例如一个配置类可以继承另一个,重写它的@Bean 方法等。
2、减少或消除 XML 配置
3、类型安全和重构友好
Spring Boot 自动配置原理是什么?
我们知道SpringBoot可以帮我们减少很多的配置,也肯定听过“约定大于配置”这么一句话,那SpringBoot是怎么做的呢?其实靠的就是@EnableAutoConfiguration注解。
简单来说,这个注解可以帮助我们自动载入应用程序所需要的所有默认配置。
发现有两个比较重要的注解
- @AutoConfigurationPackage:自动配置包
- @Import:给IOC容器导入组件
@AutoConfigurationPackage
我们可以发现,依靠的还是@Import注解
@AutoConfigurationPackage注解就是在默认的情况下就是将主配置类(@SpringBootApplication这个注解所在包及其子包里边的组件)扫描到Spring容器中
看起来跟@ComponentScan注解一样的作用,但是扫描的对象不一样,比如说,你用了Spring Data JPA,可能会在实体类上写@Entity注解。这个@Entity注解由 @AutoConfigurationPackage扫描并加载,而我们平时开发用的@Controller/@Service/@Component/@Repository这些注解是由@ComponentScan来扫描并加载的。
简单理解:这二者扫描的对象是不一样的。
@Import(AutoConfigurationImportSelector.class)
AutoConfigurationImportSelector这个类中有个selectImports方法,其中getCandidateConfigurations方法可以获取很多的配置信息
那这些配置信息哪里来的呢?
这里包装了一层,我们看到的只是通过SpringFactoriesLoader来加载获取到的配置信息,还没看到关键信息,继续进去:
解析
FACTORIES_RESOURCE_LOCATION(工厂资源加载路径)的值是META-INF/spring.factories
Spring启动的时候会扫描所有jar路径下的META-INF/spring.factories,将其文件包装成Properties对象
从Properties对象获取到key值为EnableAutoConfiguration的数据,然后添加到容器里边。
最后我们会默认加载113个默认的配置类:
Spring Boot 自动配置原理是什么?
其中@EnableAutoConfiguration是关键(启用自动配置),这个注解里的
@Import(AutoConfigurationImportSelector.class)(auto 啊4 tou3)注解起核心作用,Spring启动的时候会扫描所有jar路径下的META-INF/spring.factories,将其文件包装成Properties对象,从Properties对象获取到key值为EnableAutoConfiguration的数据(这些数据都是SpringBoot默认配置好了的配置文件数据,例如Redis常用配置的数据,这样就不需要我们配置了,我们只要简单配置几个核心的数据就可以用Redis了,从而简化了配置),加载到IOC容器中,实现自动配置功能!
SpringBoot 常用的配置形式,按照配置生效的优先级从高到低排列?
1. 命令行参数
2. 操作系统环境变量
3. 配置文件(YAML 文件、Properties 文件)
4.@Configuration 注解类上的@PropertySource 指定的配置文件
什么是 YAML?
YAML 是一种易读的数据序列化语言。它通常用于配置文件。与properties文件相比,YAML 文件具有结构化、有序、不容易混淆、分层、简洁的优点。
YAML 配置的优缺点?
优点
- 简洁、分层、结构化、有序
- 支持数组,数组中的元素可以是基本数据类型也可以是对象
yml中数组对象的写法
yml中数组的写法
缺点
不支持 @PropertySource 注解导入自定义的 YAML 配置。
补充:新建一个 person.properties 配置文件,用来存放 Person 类的配置信息。接下来使用 @ PropertySource 注解,来实现通过读取该配置,实现配置文件与 Java Bean 类的注入操作。
//person.properties person.id=111 person.name=扛麻袋的少年 person.age=18 person.manager=true person.birthday=2020/03/27 person.map.k1=v1 person.map.k2=v2 person.list=basketball,tennis,swim person.address.province=山西省 person.address.distinct=晋中市 person.address.county=祁县
添加 @PropertySource(value = {“classpath:person.properties”})注解,通过 value 属性让它去加载指定路径配置文件。代码如下:
@Component @ConfigurationProperties(prefix = "person") @PropertySource(value = "classpath:person.properties",encoding = "UTF-8") //读取指定路径配置文件 public class Person { private String id; private String name; private int age; private boolean isManager; private Date birthday; private Map<String, Object> map; private List<String> list; private Address address; /** * 省略get/set/toString() 方法 */ }
Spring Boot 是否可以使用 XML 配置 ?
Spring Boot 推荐使用 Java 配置而非 XML 配置,但是 Spring Boot 中也可以使用 XML 配置,通过@ImportResource 注解可以引入一个 XML 配置。
spring boot 核心配置文件是什么?bootstrap.properties 和application.properties 有何区别 ?
spring boot 核心配置文件是什么?
spring boot 核心的两个配置文件bootstrap(不 t s 抓 p) . yml和application . yml
bootstrap.properties 和application.properties 有何区别 ?
两者主要区别是加载顺序不同,bootstrap.yml(bootstrap.properties)先加载,application.yml(application.properties)后加载,bootstrap 由父 ApplicationContext 加载,比 application 优先加载
bootstrap 里面的属性不能被覆盖,一旦 bootStrap 被加载,则内容不会被覆盖,即便后期加载的 application 的内容标签与 bootstrap 的标签一致,application 也不会覆盖 bootstrap, 而 application 里面的内容可以动态替换。
应用场景不一样,application.yml主要用于spring boot 项目的自动化配置,bootstrap 配置文件有以下几个应用场景。
使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;
一些固定的不能被覆盖的属性
一些加密/解密的场景;
补充
启动上下文时,Spring Cloud会创建一个BootStrap Context,作为Spring应用的Application Context的父上下文。初始化的时候,Bootstrap Context负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的Environment。Bootstrap属性有高优先级,默认情况下,他们不会被本地配置覆盖。
Bootstrap Context和Application Context有着不同的约定,所以新增了一个bootstrap.properties,而不是使用application.properties。保证Bootstrap Context和Application Context配置的分离。
什么是 Spring Profiles?
实际开发中会同时存在dev、uat、prod等多套环境,这些环境共用一套代码逻辑,但却需要不同的配置。例如dev环境要连接测试数据库,而prod则需要连接生产数据库等等。profile最主要的目的就是可以区分不同的环境,进而对不同环境进行配置
当profile为default时,只使用application.yaml,SpringBoot默认Server端口为8080。将当前profile激活为dev时, SpringBoot就会额外加载application-dev.yaml 后合并到application.yaml中,若其中有相同的配置则覆盖掉。
如何在自定义端口上运行 Spring Boot 应用程序?
为了在自定义端口上运行 Spring Boot 应用程序,您可以在application.properties 中指定端口。server.port = 8090
如何实现 Spring Boot 应用程序的安全性?
为了实现 Spring Boot 的安全性,我们使用 spring-boot-starter-security 依赖项,并且必须添加安全配置。它只需要很少的代码。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
由于springboot对starter依赖进行了自动化的配置,即约定大于配置,也就是带有starter的依赖在整合springboot时,在我们不做任何配置时,默认使用starter约定的配置,只有当我们进行自定义配置时,springboot才会使用我们的配置
通过配置类的方式实现security的自定义配置
通过配置类的方式实现security的自定义配置,配置类将必须扩展WebSecurityConfigurerAdapter 并覆盖其configure方法。
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { //自定义配置URL资源的权限控制 @Override protected void configure(HttpSecurity http) throws Exception { http. //对所有请求进行权限认证 authorizeRequests() //自定义配置请求地址权限 .mvcMatchers("/test/security").permitAll() // permitAll() 对所有请求放行 .mvcMatchers("/admin/security").hasRole("admin") .mvcMatchers("/user/security").hasRole("user") .mvcMatchers("/tUser/selectAll").anonymous() // anonymous() 允许匿名访问,登陆状态不能访问 .anyRequest().authenticated() //所有请求都需要进行认证 .and() .formLogin() //.loginPage("login") 自定义登陆页面 .permitAll() //所有用户都可以访问 .and() .logout() //.logoutUrl("logout") 自定义配置退出登陆页面 .permitAll(); } //自定义配置认证规则 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //spring内置了两种UserDetailManager实现,一种基于内存的InMemoryUserDetailsManager,另一种是基于数据库的JdbcUserDetailsManager auth. //使用内存中的InMemoryUserDetailsManager(内存用户管理器) inMemoryAuthentication() //不使用passwordEncoder密码加密 .passwordEncoder(NoOpPasswordEncoder.getInstance()) //在内存中给配置user用户 .withUser("admin").password("admin").roles("admin") .and() //在内存中配置admin用户 .withUser("user").password("user").roles("user"); } }
security配置类搞定之后,我们新建UserController和AdminController两个接口测试类,具体如下
1. @RestControlle@RestController @RequestMapping("/user") public class UserController { @GetMapping("/security") public String security(){ return "user-spring-security登陆成功"; } } @RestController @RequestMapping("/admin") public class AdminController { @GetMapping("/security") public String security(){ return "admin-spring-security登陆成功"; } }
重新启动应用,并分别访问http://localhost/test/security、http://localhost/user/security、http://localhost/admin/security三个地址,我们会发现第一个地址不用登陆就能直接访问,第二个地址需要user角色权限,第三个地址需要admin角色权限;需要注意的是,当我们访问第二个地址并使用user角色登录之后,我们访问第三个地址会报403错误,其原因是浏览器在我们使用user登录时缓存了user的登录会话信息即session状态,所以当我们登录第三个地址时浏览器会以user的登录状态去访问admin角色下的接口,显然这是访问不到的。
基于注解的方式实现对接口中方法的权限认证
首先在SecurityConfig配置类中添加@EnableGlobalMethodSecurity(prePostEnabled = true) 注解开启该功能
@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) //开启基于方法的注解权限认证,默认为false public class SecurityConfig extends WebSecurityConfigurerAdapter {
然后我们就可以在想要进行权限校验的方法上使用@PreAuthorize("hasAuthority('ROLE_user')")或者@PreAuthorize("hasRole('user')")进行相应的权限校验了。
特别说明:hasRole和hasAuthority基本上没有区别,主要差异在于hasRole会在我们添加的角色名称前添加ROLE_前缀,所以在数据库中的权限字符串需要加上 ROLE_ 前缀。即数据库中存储的用户角色如果是 ROLE_admin,这里就是 admin。hasAuthority和数据库一样就行
Spring Boot 中如何解决跨域问题 ?
跨域问题现象
been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource
上面的意思就是 你访问一个什么地址被CORS 协议阻止, 没有 在Hearder 里面发现 Access-Control-Allow-Origin 的参数的资源
跨域问题的原因
浏览器出于安全考虑,限制访问本站点以外的资源。
比如你有一个 网站 127.0.0.1:8080/ , 并且上面挂了一个页面 ,那么在这个页面中 ,你只访问本站点的资源不会受到限制,但是你如果访问其他站点,比如 127.0.0.1:8081 的资源就会受到限制。
什么是源和跨域
源(origin)就是协议、域名和端口号。
URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口全部相同,则表示他们同源。否则,只要协议、域名、端口有任何一个不同就是跨域。
对https://www.baidu.com/index.html进行跨域比较:
什么是同源策略?
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
同源策略又分为以下两种
- DOM同源策略:禁止对不同源页面DOM 进行操作。这里主要场景是iframe跨域的情况,不同域名的iframe是限制互相访问的。
- XMLHttpRequest同源策略:禁止使用XHR对象向不同源的服务器地址发起HTTP请求。
Spring Boot跨域问题解决方案
1. 创建一个filter解决跨域
项目中前后端分离部署,页面和接口一般不是一个程序,所以需要解决跨域的问题。 我们使用cookie存放用户登录的信息,在spring拦截器进行权限控制,当权限不符合时,直接返回给用户固定的json结果。 当用户登录以后,正常使用;当用户退出登录状态时或者token过期时,由于拦截器和跨域的顺序有问题,出现了跨域的现象。 我们知道一个http请求,先走filter,到达servlet后才进行拦截器的处理,如果我们把cors放在filter里,就可以优先于权限拦截器执行。
@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); } }
2. 基于WebMvcConfigurer配置加入Cors的跨域
跨域可以在前端通过 JSONP 来解决,但是 JSONP 只可以发送 GET 请求,无法发送其他类型的请求,在 RESTful 风格的应用中,就显得非常鸡肋,因此我们推荐在后端通过 (CORS,Cross-origin resource sharing) 来解决跨域问题。这种解决方案并非 Spring Boot 特有的,在传统的 SSM 框架中,就可以通过 CORS 来解决跨域问题,只不过之前我们是在 XML 文件中配置 CORS ,现在可以通过实现WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。
@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); } }
3. controller配置CORS
controller方法的CORS配置,您可以向@RequestMapping注解处理程序方法添加一个@CrossOrigin注解,以便启用CORS(默认情况下,@CrossOrigin允许在@RequestMapping注解中指定的所有源和HTTP方法):
@RestController @RequestMapping("/account") public class AccountController { @CrossOrigin @GetMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ... } @DeleteMapping("/{id}") public void remove(@PathVariable Long id) { // ... } }
@CrossOrigin中的参数
@CrossOrigin 表示所有的URL均可访问此资源
@CrossOrigin(origins = “http://127.0.0.1:8080”)//表示只允许这一个url可以跨域访问这个controller
代码说明:@CrossOrigin这个注解用起来很方便,这个可以用在方法上,也可以用在类上。如果你不设置他的value属性,或者是origins属性,就默认是可以允许所有的URL/域访问。
value属性可以设置多个URL。
origins属性也可以设置多个URL。
maxAge属性指定了准备响应前的缓存持续的最大时间。就是探测请求的有效期。
allowCredentials属性表示用户是否可以发送、处理 cookie。默认为false
allowedHeaders 属性表示允许的请求头部有哪些。
methods 属性表示允许请求的方法,默认get,post,head。
@CrossOrigin不起作用的原因
1、是springMVC的版本要在4.2或以上版本才支持@CrossOrigin
2、非@CrossOrigin没有解决跨域请求问题,而是不正确的请求导致无法得到预期的响应,导致浏览器端提示跨域问题。
3、在Controller注解上方添加@CrossOrigin注解后,仍然出现跨域问题,解决方案之一就是:在@RequestMapping注解中没有指定Get、Post方式,具体指定后,问题解决。
@CrossOrigin @RestController public class person{ @RequestMapping(method = RequestMethod.GET) public String add() { // 若干代码 } }