读书笔记 - Spring Boot实战
- 第1章 入门
- Spring Boot精要
- 1. 自动配置
- 2. 起步依赖
- 3. 命令行界面
- 4. Actuator
- 使用Spring Initializr初始化Spring Boot项目
- 第2章 运用SpringBoot
- @SpringBootApplication
- 配置应用程序属性
- 指定基于功能的依赖
- 覆盖起步依赖引入的传递依赖
- 使用自动配置
- 第3章 自定义配置
- 覆盖Spring Boot自动配置
- Spring Security例子
- 创建自定义的安全配置
- 掀开自动配置的神秘面纱
- 通过属性文件外置配置
- 第4章 测试
- 集成测试自动配置
- 测试Web应用程序
- 模拟Spring MVC
- 测试运行中的应用程序
- 使用Selenium测试HTML页面
- 第5章 Groovy与Spring Boot CLI
- 第6章 在Spring Boot中使用Grails
- 使用GORM进行数据持久化
- GORM在Spring Boot里的另一个选择
- 第7章 深入Actuator
- SpringBoot中启用actuator
- 引入监控插件
- SecurityConfig关闭鉴权
- yaml配置引入
- 启用应用访问
- 添加自定义度量信息
- 创建自定义跟踪仓库
- 自定义一个Amazon健康指示器
- 保护Actuator端点
- SpringBoot中启用actuator页面监控
- 引入坐标
- 启动类
- yaml配置引入
- 启用应用访问
- Stagemonitor扩展集成
- Spring Boot开发者工具
- devtools
- LiveReload
第1章 入门
Spring Boot精要
Spring Boot有四大神器,分别是auto-configuration、starters、cli、actuator,
Spring Boot将很多魔法带入了Spring应用程序的开发之中,其中最重要的是以下四个核心。
自动配置:针对很多Spring应用程序常见的应用功能,Spring Boot能自动提供相关配置。
起步依赖:告诉Spring Boot需要什么功能,它就能引入需要的库。
命令行界面:这是Spring Boot的可选特性,借此你只需写代码就能完成完整的应用程序,无需传统项目构建。
Actuator:让你能够深入运行中的Spring Boot应用程序,一探究竟。
1. 自动配置
在任何Spring应用程序的源代码里,你都会找到Java配置或XML配置(抑或两者皆有),它们为应用程序开启了特定的特性和功能。举个例子,,如果你写过用JDBC访问关系型数据库的应用程序。
这段非常简单的Bean声明创建了一个JdbcTemplate的实例,注入了一个DataSource依赖。
@Beanpublic JdbcTemplate jdbcTemplate(DataSource dataSource) { return new JdbcTemplate(dataSource);
}
还需要配置一个DataSource的Bean,这样才能满足依赖。假设你将配置一个嵌入式H2数据库作为DataSource Bean
public DataSource dataSource() {return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScripts('schema.sql', 'data.sql') .build();
}
既然它如此常见,那为什么还要你去写呢?
Spring Boot会为这些常见配置场景进行自动配置。如果Spring Boot在应用程序的Classpath里发现H2数据库的库,那么它就自动配置一个嵌入式H2数据库。如果在Classpath里发现JdbcTemplate,那么它还会为你配置一个JdbcTemplate的Bean。你无需操心那些Bean的配置,Spring Boot会做好准备,随时都能将其注入到你的Bean里。
2. 起步依赖
向项目中添加依赖是件富有挑战的事。你需要什么库?它的Group和Artifact是什么?你需要哪个版本?哪个版本不会和项目中的其他依赖发生冲突?
Spring Boot通过起步依赖为项目的依赖管理提供帮助。起步依赖其实就是特殊的Maven依赖和Gradle依赖,利用了传递依赖解析,把常用库聚合在一起,组成了几个为特定功能而定制的依赖,如下。
org.springframework:spring-core
org.springframework:spring-web
org.springframework:spring-webmvc
com.fasterxml.jackson.core:jackson-databind
org.hibernate:hibernate-validator
org.apache.tomcat.embed:tomcat-embed-core
org.apache.tomcat.embed:tomcat-embed-el
org.apache.tomcat.embed:tomcat-embed-logging-juli
应用是个Web应用程序,所以加入了Web起步依赖。与之类似,如果应用程序要用到JPA持久化,那么就可以加入jpa起步依赖。如果需要安全功能,那就加入security起步依赖。简而言之,你不再需要考虑支持某种功能要用什么库了,引入相关起步依赖就行。
org.springframework.boot:spring-boot-starter-web
3. 命令行界面
除了自动配置和起步依赖,Spring Boot还提供了一种很有意思的新方法,可以快速开发Spring应用程序。
Spring Boot CLI利用了起步依赖和自动配置,让你专注于代码本身。
不仅如此,你是否注意到代码清单1-1里没有import?
CLI如何知道RequestMapping和RestController来自哪个包呢?
说到这个问题,那些类最终又是怎么跑到Classpath里的呢?
说得简单一点,CLI能检测到你使用了哪些类,它知道要向Classpath中添加哪些起步依赖才能让它运转起来。一旦那些依赖出现在Classpath中,一系列自动配置就会接踵而来,确保启用DispatcherServlet和Spring MVC,这样控制器就能响应HTTP请求了。
4. Actuator
Actuator则要提供在运行时检视应用程序内部情况的能力。安装了Actuator就能窥探应用程序的内部情况了,包括如下细节:
- Spring应用程序上下文里配置的Bean
- Spring Boot的自动配置做的决策
- 应用程序取到的环境变量、系统属性、配置属性和命令行参数
- 应用程序里线程的当前状态
- 应用程序最近处理过的HTTP请求的追踪情况
- 各种和内存用量、垃圾回收、Web请求以及数据源用量相关的指标
Actuator通过Web端点和shell界面向外界提供信息。如果要借助shell界面,你可以打开SSH(Secure Shell),登入运行中的应用程序,发送指令查看它的情况。
使用Spring Initializr初始化Spring Boot项目
- 使用Spring Initializr的Web界面,最直接的办法就是用浏览器打开http://start.spring.io,你应该能看到一个表单。
- 在Spring Tool Suite里创建Spring Boot项目
- 在IntelliJ IDEA里创建Spring Boot项目
- 在Spring Boot CLI里使用Initializr
第2章 运用SpringBoot
@SpringBootApplication
@SpringBootApplication开启了Spring的组件扫描和Spring Boot的自动配置功能。实际上,@SpringBootApplication将三个有用的注解组合在了一起。
Spring的@Configuration:标明该类使用Spring基于Java的配置。
Spring的@ComponentScan:启用组件扫描,这样你写的Web控制器类和其他组件才能被自动发现并注册为Spring应用程序上下文里的Bean。Spring MVC控制器使用@Controller进行注解,这样组件扫描才能找到它。
Spring Boot的@EnableAutoConfiguration:这个不起眼的小注解也可以称为@Abracadabra,就是这一行配置开启了Spring Boot自动配置的魔力,让你不用再写成篇的配置了。
配置应用程序属性
application.properties文件可以很方便地帮你细粒度地调整Spring Boot的自动配置。
server.port=8000
指定基于功能的依赖
Spring Boot通过提供众多起步依赖降低项目依赖的复杂度。
dependencies {compile "org.springframework.boot:spring-boot-starter-web"compile "org.springframework.boot:spring-boot-starter-thymeleaf"compile "org.springframework.boot:spring-boot-starter-data-jpa"compile "com.h2database:h2"testCompile("org.springframework.boot:spring-boot-starter-test")
}
通过传递依赖,添加这四个依赖就等价于加了一大把独立的库。这些传递依赖涵盖了SpringMVC、Spring Data JPA、Thymeleaf等内容,它们声明的依赖也会被传递依赖进来。
不知道自己所用依赖的版本,你多少会有些不安。
在Gradle里,dependencies任务会显示一个依赖树,其中包含了项目所用的每一个库以及它们的版本:
$ gradle dependencies
在Maven里使用dependency插件的tree目标也能获得相似的依赖树。
$ mvn dependency:tree
覆盖起步依赖引入的传递依赖
以Spring Boot的Web起步依赖为例,它传递依赖了Jackson JSON库。如果你正在构建一个生产或消费JSON资源表述的REST服务,那它会很有用。但是,要构建传统的面向人类用户的Web应用程序,你可能用不上Jackson。虽然把它加进来也不会有什么坏处,但排除掉它的传递依赖,可以为你的项目瘦身。
compile("org.springframework.boot:spring-boot-starter-web") {exclude group: 'com.fasterxml.jackson.core'
}
另一方面,也许项目需要Jackson,但你需要用另一个版本的Jackson来进行构建,而不是Web起步依赖里的那个。假设Web起步依赖引用了Jackson 2.3.4,但你需要使用2.4.3
compile("com.fasterxml.jackson.core:jackson-databind:2.4.3")
使用自动配置
每当应用程序启动的时候,Spring Boot的自动配置都要做将近200个这样的决定,涵盖安全、集成、持久化、Web开发等诸多方面。
Spring的JdbcTemplate是不是在Classpath里?如果是,并且有DataSource的Bean,则自动配置一个JdbcTemplate的Bean。
Thymeleaf是不是在Classpath里?如果是,则配置Thymeleaf的模板解析器、视图解析器以及模板引擎。
Spring Security是不是在Classpath里?如果是,则进行一个非常基本的Web安全设置。
第3章 自定义配置
覆盖Spring Boot自动配置
大多数情况下,自动配置的Bean刚好能满足你的需要,不需要去覆盖它们。但某些情况下,Spring Boot在自动配置时还不能很好地进行推断。
Spring Security例子
当你在应用程序里添加安全特性时,自动配置做得还不够好。安全配置并不是放之四海而皆准的,围绕应用程序安全有很多决策要做,Spring Boot不能替你做决定。想知道如何用显式的配置来覆盖自动配置,我们先从为阅读列表应用程序添加Spring Security入手。
Spring Boot自动配置让应用程序的安全工作变得易如反掌,你要做的只是添加Security起步依赖。
compile(“org.springframework.boot:spring-boot-starter-security”)
这样就搞定了!重新构建应用程序后运行即可,现在这就是一个安全的Web应用程序了!Security起步依赖在应用程序的Classpath里添加了Spring Secuirty(和其他一些东西)。Classpath里有Spring Security后,自动配置就能介入其中创建一个基本的Spring Security配置。
默认的配置不是我们想要的效果,让我们看看如何写出Spring Secuirty配置,覆盖自动配置的安全设置吧。
创建自定义的安全配置
覆盖自动配置很简单,就当自动配置不存在,直接显式地写一段配置。这段显式配置的形式不限,Spring支持的XML和Groovy形式配置都可以。在编写显式配置时,我们会专注于Java形式的配置。在Spring Security的场景下,这意味着写一个扩展了ebSecurityConfigurerAdapter
的配置类。
覆盖自动配置的显式安全配置如下:
package com.cmcc.framework.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.filter.CorsFilter;
/*** spring security配置** @author ruoyi*/
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 自定义用户认证逻辑*/@Autowiredprivate UserDetailsService userDetailsService;/*** 认证失败处理类*/@Autowiredprivate AuthenticationEntryPointImpl unauthorizedHandler;/*** 退出处理类*/@Autowiredprivate LogoutSuccessHandlerImpl logoutSuccessHandler;/*** token认证过滤器*/@Autowiredprivate JwtAuthenticationTokenFilter authenticationTokenFilter;/*** 跨域过滤器*/@Autowiredprivate CorsFilter corsFilter;/*** 允许匿名访问的地址*/@Autowiredprivate PermitAllUrlProperties permitAllUrl;/*** 解决 无法直接注入 AuthenticationManager** @return* @throws Exception*/@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}/*** anyRequest | 匹配所有请求路径* access | SpringEl表达式结果为true时可以访问* anonymous | 匿名可以访问* denyAll | 用户不能访问* fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)* hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问* hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问* hasAuthority | 如果有参数,参数表示权限,则其权限可以访问* hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问* hasRole | 如果有参数,参数表示角色,则其角色可以访问* permitAll | 用户可以任意访问* rememberMe | 允许通过remember-me登录的用户访问* authenticated | 用户登录后可访问*/@Overrideprotected void configure(HttpSecurity httpSecurity) throws Exception {// 注解标记允许匿名访问的urlExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());httpSecurity// CSRF禁用,因为不使用session.csrf().disable()// 禁用HTTP响应标头.headers().cacheControl().disable().and()// 认证失败处理类.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()// 基于token,所以不需要session.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()// 过滤请求.authorizeRequests()// 对于登录login 注册register 验证码captchaImage 允许匿名访问.antMatchers("/login",// 静态资源,可匿名访问.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll().antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs","/v2/*", "/druid/**").permitAll()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated().and().headers().frameOptions().disable();// 添加Logout filterhttpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);// 添加JWT filterhttpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);// 添加CORS filterhttpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);}/*** 强散列哈希加密实现*/@Beanpublic BCryptPasswordEncoder bCryptPasswordEncoder() {return new BCryptPasswordEncoder();}/*** 身份认证接口*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());}
}
SecurityConfig是个非常基础的Spring Security配置,尽管如此,它还是完成了不少安全定制工作。通过这个自定义的安全配置类,我们让Spring Boot跳过了安全自动配置,转而使用我们的安全配置。
掀开自动配置的神秘面纱
想要覆盖Spring Boot的自动配置,你所要做的仅仅是编写一个显式的配置。Spring Boot会发现你的配置,随后降低自动配置的优先级,以你的配置为准。想弄明白这是如何实现的,让我们揭开Spring Boot自动配置的神秘面纱,看看它是如何运作的,以及它是怎么允许自己被覆盖的。
Spring Boot自动配置自带了很多配置类,每一个都能运用在你的应用程序里。它们都使用了Spring 4.0的条件化配置,可以在运行时判断这个配置是该被运用,还是该被忽略。
Spring Boot的DataSourceAutoConfiguration中定义的JdbcTemplate Bean就是一个非常简单的例子,演示了@ConditionalOnMissingBean如何工作:
@Bean
@ConditionalOnMissingBean(JdbcOperations.class)
public JdbcTemplate jdbcTemplate() {return new JdbcTemplate(this.dataSource);
}
关于Spring Security,自动配置会考虑几个配置类。在这里讨论每个配置类的细节是不切实际的,但覆盖Spring Boot自动配置的安全配置时,最重要的一个类是SpringBootWebSecurityConfiguration。以下是其中的一个代码片段:
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass({ EnableWebSecurity.class })
@ConditionalOnMissingBean(WebSecurityConfiguration.class)
@ConditionalOnWebApplication
public class SpringBootWebSecurityConfiguration {...
}
看到@ConditionalOnClass注解后,你就应该知道Classpath里必须要有@EnableWebSecurity注解。
@ConditionalOnMissingBean注解才是我们的安全配置类代替SpringBootWebSecurityConfiguration的关键所在。
@ConditionalOnMissingBean注解要求当下没有WebSecurityConfiguration类型的Bean。虽然表面上我们并没有这么一个Bean,但通过在SecurityConfig上添加@EnableWebSecurity注解,我们实际上间接创建了一个WebSecurityConfiguration Bean。所以在自动配置时,这个Bean就已经存在了,@ConditionalOnMissingBean条件不成立,SpringBootWebSecurityConfiguration提供的配置就被跳过了。
通过属性文件外置配置
在处理应用安全时,你当然会希望完全掌控所有配置。不过,为了微调一些细节,比如改改端口号和日志级别。Spring Boot自动配置的Bean提供了300多个用于微调的属性。
#如果你想禁用这个Banner
spring.main.show-banner=false
#还可以将属性设置为环境变量。举例来说,如果你用的是bash或者zsh,可以用export命令:
$ export spring_main_show_banner=false
实际上,Spring Boot应用程序有多种设置途径。Spring Boot能从多种属性源获得属性,包括如下几处。
(1)命令行参数
(2)java:comp/env里的JNDI属性
(3)JVM系统属性
(4)操作系统环境变量
(5)随机生成的带random.*前缀的属性(在设置其他属性时,可以引用它们,比如${random.long})
(6)应用程序以外的application.properties或者appliaction.yml文件
(7)打包在应用程序内的application.properties或者appliaction.yml文件
(8)通过@PropertySource标注的属性源
(9)默认属性
这个列表按照优先级排序,也就是说,任何在高优先级属性源里设置的属性都会覆盖低优先级的相同属性。例如,命令行参数会覆盖其他属性源里的属性。
例如,命令行参数会覆盖其他属性源里的属性。application.properties和application.yml文件能放在以下四个位置。
(1)外置,在相对于应用程序运行目录的/config子目录里。
(2)外置,在应用程序运行的目录里。
(3)内置,在config包内。
(4)内置,在Classpath根目录。
同样,这个列表按照优先级排序。也就是说,/config子目录里的application.properties会覆盖应用程序Classpath里的application.properties中的相同属性。
此外,如果你在同一优先级位置同时有application.properties和application.yml,那么application.yml里的属性会覆盖application.properties里的属性。
第4章 测试
集成测试自动配置
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes=AddressBookConfiguration.class)
public class AddressServiceTests {...
}
@SpringApplicationConfiguration加载Spring应用程序上下文的方式同SpringApplication
相同,处理方式和生产应用程序中的情况相同。这包括加载外部属性和Spring Boot日志。
测试Web应用程序
@RequestMapping(method=RequestMethod.POST)
public String addToReadingList(Book book) {book.setReader(reader);readingListRepository.save(book);return "redirect:/readingList";
}
save方法的测试,Spring Boot开发者有两个可选的方案能实现这类测试。
Spring Mock MVC:能在一个近似真实的模拟Servlet容器里测试控制器,而不用实际启动应用服务器。
Web集成测试:在嵌入式Servlet容器(比如Tomcat或Jetty)里启动应用程序,在真正的应用服务器里执行测试。
模拟Spring MVC
Spring Framework就有了一套非常实用的Web应用程序测试工具,能模拟Spring MVC,不需要真实的Servlet容器也能对控制器发送HTTP请求。Spring的Mock MVC框架模拟了Spring MVC的很多功能。它几乎和运行在Servlet容器里的应用程序一样,尽管实际情况并非如此。
要在测试里设置Mock MVC,可以使用MockMvcBuilders,该类提供了两个静态方法。
standaloneSetup():构建一个Mock MVC,提供一个或多个手工创建并配置的控制器。
webAppContextSetup():使用Spring应用程序上下文来构建Mock MVC,该上下文里可以包含一个或多个配置好的控制器。
前者同单元测试更加接近,你可能只想让它专注于单一控制器的测试,而后者让Spring加载控制器及其依赖,以便进行完整的集成测试。
测试运行中的应用程序
说到测试Web应用程序,我们还没接触实质内容。在真实的服务器里启动应用程序,用真实的Web浏览器访问它,这样比使用模拟的测试引擎更能展现应用程序在用户端的行为。
Spring Boot找到了解决方案。它支持将Tomcat或Jetty这样的嵌入式Servlet容器作为运行中的应用程序的一部分,可以运用相同的机制,在测试过程中用嵌入式Servlet容器来启动应用程序。Spring Boot的@WebIntegrationTest注解就是这么做的。在测试类上添加@WebIntegrationTest注解,可以声明你不仅希望Spring Boot为测试创建应用程序上下文,还要启动一个嵌入式的Servlet容器。一旦应用程序运行在嵌入式容器里,你就可以发起真实的HTTP请求,断言结果了。
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes=ReadingListApplication.class)
@WebIntegrationTest ←---在服务器里运行测试
public class SimpleWebTest {***
}
使用Selenium测试HTML页面
RestTemplate对于简单的请求而言使用方便,是测试REST端点的理想工具。但是,就算它能对返回HTML页面的URL发起请求,也不方便对页面内容或者页面上执行的操作进行断言。
对于HTML应用程序测试,有一个更好的选择——Selenium(www.seleniumhq.org),它的功能远不止提交请求和获取结果。Selenium的测试是自动的,而且可以重复运行。
首先需要把Selenium作为测试依赖添加到项目里:
testCompile("org.seleniumhq.selenium:selenium-java:2.45.0")
这个测试里最值得注意的是,@WebIntegrationTest可以为我们启动应用程序和服务器,这样Selenium才可以用Web浏览器执行测试。但真正有趣的是你可以使用IDE的测试功能来运行测试,运行几次都行,无需依赖构建过程中的某些插件启动服务器。
要是你觉得使用Selenium进行测试很实用,可以阅读Yujun Liang和Alex Collins的SeleniumWebDriver in Practice(http://manning.com/liang/),该书更深入地讨论了Selenium测试的细节。
第5章 Groovy与Spring Boot CLI
Groovy本身是种优雅的语言。用Groovy编写Book领域类相当简单。如果在阅读列表项目的根目录里创建一个新的文件,名为Book.groovy,那么在这里编写如下Groovy类。
class Book {Long idString readerString isbnString titleString authorString description
}
如你所见,Groovy类与它的Java类相比,大小完全不在一个量级。这里没有setter和getter方法,没有public和private修饰符,也没有分号。Java中常见的代码噪声不复存在,剩下的内容都在描述书的基本信息。
第6章 在Spring Boot中使用Grails
使用GORM进行数据持久化
Grails里最让人着迷的恐怕就是GORM了。GORM将数据库相关工作简化到和声明要持久化的实体一样容易。
package readinglist
import grails.persistence.*@Entity ←---这是一个GORM实体
class Book {Reader readerString isbnString titleString authorString description
}
就和Book的Java版本一样,这个类里有很多描述图书的属性。但又与Java版本不一样,这里没有分号、public或private修饰符、setter和getter方法或其他Java中常见的代码噪声。
要在Spring Boot项目里使用GORM,必须在项目里添加GORM依赖。
compile("org.grails:gorm-hibernate4-spring-boot:1.1.0.RELEASE")
GORM在Spring Boot里的另一个选择
如果你想用MongoDB,那你会对Spring Boot里的MongoDB GORM支持很感兴趣。
compile("org.grails:gorm-mongodb-spring-boot:1.1.0.RELEASE")
GORM的工作原理要求实体类必须用Groovy来编写。
Groovy的ReadingListController
@RequestMapping(method=RequestMethod.POST)def addToReadingList(Reader reader, Book book) {Book.withTransaction {book.setReader(reader)book.save() ←---保存一本书}"redirect:/"}
Grails项目也提供GSP的自动配置。如果你想在Spring Boot应用程序里使用GSP,必须向项目里添加Spring Boot的GSP库:
compile("org.grails:grails-gsp-spring-boot:1.0.0")
第7章 深入Actuator
端点可以分为三大类:配置端点、度量端点和其他端点。让我们分别了解一下这些端点,从提供应用程序配置信息的端点看起。
SpringBoot中启用actuator
引入监控插件
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
SecurityConfig关闭鉴权
.antMatchers("/actuator/*").permitAll()
yaml配置引入
management:endpoints:web:exposure:include: "*"exclude: info
启用应用访问
http://192.168.0.34:8298/cmcc-tenant/actuator
添加自定义度量信息
从/metrics端点获得运行中应用程序的内部度量信息,包括内存、垃圾回收和线程信息。这些都是非常有用且信息量很大的度量值,但你可能还想定义自己的度量,用来捕获应用程序中的特定信息。
比方说,我们想要知道用户往阅读列表里保存了多少次图书,自动配置允许Actuator创建CounterService的实例,并将其注册为Spring的应用程序上下文中的Bean。CounterService
这个接口里定义了三个方法,分别用来增加、减少或重置特定名称的度量值,代码如下:
package org.springframework.boot.actuate.metrics;
public interface CounterService {void increment(String metricName);void decrement(String metricName);void reset(String metricName);
}
创建自定义跟踪仓库
默认情况下,/trace端点报告的跟踪信息都存储在内存仓库里,100个条目封顶。一旦仓库满了,就开始移除老的条目,给新的条目腾出空间。在开发阶段这没什么问题,但在生产环境中,大流量会造成跟踪信息还没来得及看就被丢弃。
为了避免这个问题,你可以声明自己的InMemoryTraceRepository
Bean,将它的容量调整至100以上。如下配置类可以将容量调整至1000个条目:
package readinglist;import org.springframework.boot.actuate.trace.InMemoryTraceRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class ActuatorConfig {@Beanpublic InMemoryTraceRepository traceRepository() {InMemoryTraceRepository traceRepo = new InMemoryTraceRepository();traceRepo.setCapacity(1000);return traceRepo;}
}
除了上述方法,我们还可以将那些跟踪条目存储在其他地方——既不消耗内存,又能长久保存的地方。只需实现Spring Boot的TraceRepository
接口即可:
package org.springframework.boot.actuate.trace;import java.util.List;
import java.util.Map;public interface TraceRepository {List<Trace> findAll();void add(Map<String, Object> traceInfo);
}
如你所见,TraceRepository只要求我们实现两个方法:一个方法查找所有存储的Trace对象,另一个保存了一个Trace,包含跟踪信息的Map对象。
插入自定义健康指示器
Actuator自带了很多健康指示器,能满足常见需求,比如报告应用程序使用的数据库和消息代理的健康情况。但如果你的应用程序需要和一些没有健康指示器的系统交互,那该怎么办呢?
自定义一个Amazon健康指示器
package readinglist;import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;@Component
public class AmazonHealth implements HealthIndicator {@Overridepublic Health health() {try {RestTemplate rest = new RestTemplate();// 向 Amazon 发送请求rest.getForObject("http://www.amazon.com", String.class);return Health.up().build();} catch (Exception e) {// 报告 DOWN 状态
// return Health.down().build();//如果有很多附加信息,可以多次调用withDetail()方法,每次设置一个要放入健康记录的附加字段。return Health.down().withDetail("reason", e.getMessage()).build();}}
}
保护Actuator端点
要保护Actuator的端点,我们需要对SecurityConfig.java的configure()方法做些修改。
保护/shutdown端点,要访问/shutdown端点,必须用一个带ADMIN权限的用户来做身份验证。
@Override
protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/").access("hasRole('READER')").antMatchers("/shutdown").access("hasRole('ADMIN')")// 要求有 ADMIN 权限.antMatchers("/**").permitAll().and().formLogin().loginPage("/login").failureUrl("/login?error=true");
}
添加一个内存里的admin用户,新加的内存身份验证中,用户名定义为admin,密码为s3cr3t,同时被授予ADMIN和READER权限。
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(new UserDetailsService() {// Reader 身份验证@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {UserDetails user = readerRepository.findOne(username);if (user != null) {return user;}throw new UsernameNotFoundException("User '" + username + "' not found.");}}).and().inMemoryAuthentication().withUser("admin").password("s3cr3t").roles("ADMIN", "READER");// Admin 身份验证
}
SpringBoot中启用actuator页面监控
引入坐标
<!-- Spring Boot Admin Server 依赖 -->
<dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-server</artifactId><version>2.6.6</version>
</dependency>
<!-- Spring Boot Admin Client 依赖 -->
<dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-client</artifactId><version>2.6.6</version>
</dependency>
启动类
@SpringBootApplication
@EnableAdminServer
yaml配置引入
spring:boot:admin:client:url: "http://192.168.0.34:${server.port}"
启用应用访问
启动失败
2025-03-08 10:38:43.690 [] [] [registrationTask1] WARN d.c.b.a.c.r.ApplicationRegistrator - [register,91] - Failed to register application as Application(name=spring-boot-application,
managementUrl=http://DESKTOP-082N99E.mshome.net:8298/cmcc-tenant/actuator,
healthUrl=http://DESKTOP-082N99E.mshome.net:8298/cmcc-tenant/actuator/health,
serviceUrl=http://DESKTOP-082N99E.mshome.net:8298/cmcc-tenant) at spring-boot-admin ([http://localhost:8298/admin/instances]): 404 : "<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 – Not Found</h1></body></html>". Further attempts are logged on DEBUG level
Stagemonitor扩展集成
https://blog.csdn.net/qq_16046891/article/details/109206608
Spring Boot开发者工具
自动重启:当Classpath里的文件发生变化时,自动重启运行中的应用程序。
LiveReload支持:对资源的修改自动触发浏览器刷新。
远程开发:远程部署时支持自动重启和LiveReload。
默认的开发时属性值:为一些属性提供有意义的默认开发时属性值。
devtools
compile "org.springframework.boot:spring-boot-devtools"
应用程序的代码则会加载到一个单独的重启类加载器里。检测到变更时,只有重启类加载器重启。有些Classpath里的资源变更后不需要重启应用程序。像Thymeleaf这样的视图模板可以直接编辑,不用重启应用程序。在/static或/public里的静态资源也不用重启应用程序,所以SpringBoot开发者工具会在重启时排除掉如下目录:/META-INF/resources、/resources、/static、/public和/templates。
可以设置spring.devtools.restart.exclude属性来覆盖默认的重启排除目录。例如,你只排除/static和/templates目录,可以像这样设置spring.devtools.restart.exclude:
spring:devtools:restart:exclude: /static/**,/templates/**
还可以设置一个触发文件,必须修改这个文件才能触发重启。例如,在修改名为.trigger的文件前你都不希望执行重启,那么你只需像这样设置spring.devtools.restart.trigger-file属性:
spring:devtools:restart:trigger-file: .trigger
LiveReload
在Web应用程序开发过程中,最常见的步骤大致如下。
(1)修改要呈现的内容(比如图片、样式表、模板)。
(2)点击浏览器里的刷新按钮,查看修改的结果。
(3)回到第1步。
虽然这并不难,但如果能不点刷新就直接看到修改结果,那岂不是更好?
Spring Boot的开发者工具集成了LiveReload(http://livereload.com
),可以消除刷新的步骤。激活开发者工具后,Spring Boot会启动一个内嵌的LiveReload服务器,在资源文件变化时会触发浏览器刷新。你要做的就是在浏览器里安装LiveReload插件。
如果想要禁用内嵌的LiveReload服务器,可以将spring.devtools.livereload.enabled
设置为false:
spring:devtools:livereload:enabled: false