有几种监视分布式系统的方法,而为了简单的配置和可靠性,我很高兴我是Spring Boot Admin。
在本教程中,我们将使用Spring Boot创建两个应用程序,一个是监视服务器,另一个将是应注册以进行监视的客户。
我们还将借此机会使用Spring Security和#Maven实现安全层,我们可以使应用程序的构建单独执行。
使用的版本
- 春季靴子:2.7.10
- Spring Boot Admin服务器:2.7.10
- Spring Boot Admin客户端:2.7.10
配置服务器
使用Spring Initilizr创建一个具有以下依赖性的项目:
- 入门网络
- 入门安全
- 管理启动服务器
检查是否添加了与Spring Boot Admin相关的依赖性:
...
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
</dependency>
...
在某些配置类中添加注释@enableadminserver:
...
@EnableAdminServer
@SpringBootApplication
public class SpringBootAdminServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootAdminServerApplication.class, args);
}
}
使用application.yaml文件配置应用程序行为。当我们添加安全层时,我们必须创建一个用户名和密码才能在服务器上登录,并且对于配置服务器和客户端之间的通信登录也是必要的。
server:
port: 8081
servlet:
context-path: /admin-console
spring:
security:
user:
# Configura o login do servidor.
name: ${SBA_SERVER_USERNAME}
password: ${SBA_SERVER_PASSWORD}
boot:
admin:
client:
# Necessários para que o cliente possa se registrar na api do servidor protegido.
username: ${SBA_SERVER_USERNAME}
password: ${SBA_SERVER_PASSWORD}
instance:
metadata:
user:
# Necessários para que o servidor possa acessar os endpoints protegidos do cliente.
name: ${SBA_CLIENT_USERNAME}
password: ${SBA_CLIENT_PASSWORD}
# LOG
logging:
file:
name: ${user.home}/logs/admin/sba-server.log
level:
root: info
web: info
dev.marksduarte: info
org.springframework: info
charset:
file: utf-8
现在,让我们通过创建类并在@configuration Notes(ProxyBeanMethods = false)上禁用Bean代理来设置Spring Security,因为当我们与@Bean Self -containing一起工作时,我们可以避免处理CGLIB SubClass。< /p。< /p >
我们还将允许访问登录路线和资产和禁用保护 csrf ©all
package dev.marksduarte.springbootadminserver;
import de.codecentric.boot.admin.server.config.AdminServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration(proxyBeanMethods = false)
public class SecurityConfig {
private final AdminServerProperties adminServer;
public SecurityConfig(AdminServerProperties adminServer) {
this.adminServer = adminServer;
}
@Bean
protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(this.adminServer.path("/"));
http.authorizeHttpRequests(authorizeRequests -> authorizeRequests
.requestMatchers(new AntPathRequestMatcher(this.adminServer.path("/assets/**")))
.permitAll()
.requestMatchers(new AntPathRequestMatcher(this.adminServer.path("/login")))
.permitAll()
.anyRequest()
.authenticated())
.formLogin(formLogin -> formLogin.loginPage(this.adminServer.path("/login"))
.successHandler(successHandler))
.logout(logout -> logout.logoutUrl(this.adminServer.path("/logout")))
.httpBasic(Customizer.withDefaults())
.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers(
new AntPathRequestMatcher(this.adminServer.path("/instances"), HttpMethod.POST.toString()),
new AntPathRequestMatcher(this.adminServer.path("/instances/*"), HttpMethod.DELETE.toString()),
new AntPathRequestMatcher(this.adminServer.path("/actuator/**"))));
return http.build();
}
}
好吧,现在您正在运行应用程序,并检查管理服务器是否可以通过http://localhost:8081/admin-console的地址访问,并使用配置中的用户和密码登录。< /p>
配置客户
使用Spring Initilizr创建一个具有以下依赖性的项目:
- 入门网络
- 起动器执行器
- 入门安全
- 管理启动客户端
如果添加了Spring Boot Admin Client和Spring Actor的依赖,请查看您的pom.xml文件:
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.7.10</version>
</dependency>
...
现在让我们配置从application.yaml文件开始的系统:
## INFO ENDPOINT
## Aqui configuramos as informações sobre o sistema, como nome, descrição, versão e etc.
info:
name: Spring Boot Admin Client
description: Sistema Cliente
version: @project.version@
server:
port: 8080
servlet:
context-path: /admin-client
spring:
# Configuração básica do Spring Security.
security:
user:
name: ${SBA_CLIENT_USERNAME}
password: ${SBA_CLIENT_PASSWORD}
boot:
admin:
client:
enabled: true
# URL do servidor que o cliente deve se registrar.
url: http://localhost:8081/admin-console
username: ${SBA_SERVER_USERNAME}
password: ${SBA_SERVER_PASSWORD}
instance:
# URL base para calcular o service-url com o qual se registrar. O caminho é inferido em tempo de execução e anexado à url base.
service-base-url: http://localhost:8080
# Essas informações são passadas ao servidor para que ele possa fazer o acesso aos endpoints do sistema cliente.
metadata:
user:
name: ${SBA_SERVER_USERNAME}
password: ${SBA_SERVER_PASSWORD}
auto-deregistration: true
## APP
app:
cors-origins:
- http://localhost
cors-methods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
cors-headers:
- Authorization
- Content-Type
- Content-Length
- X-Requested-With
## ACTUATOR
management:
info:
env:
# Desde o Spring Boot 2.6, o env info é desabilitado por padrão.
enabled: true
endpoint:
health:
show-details: ALWAYS
enabled: true
shutdown:
enabled: true
logfile:
enabled: true
external-file: logs/sba-client.log
endpoints:
web:
exposure:
# Liberamos todos os endpoints, mas lembre-se, em produção não se deve fazer isso.
include: "*"
cors:
allowed-headers: ${app.cors-headers}
allowed-methods: ${app.cors-methods}
allowed-origins: ${app.cors-origins}
## LOG
logging:
file:
name: logs/sba-client.log
path: logs
level:
root: info
web: info
dev.marksduarte: info
charset:
file: utf-8
logback:
rollingpolicy:
clean-history-on-start: true
max-file-size: 10MB
要简化,我们将启用“/执行器/**”端点的所有请求:
...
@EnableWebSecurity
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeHttpRequests()
.antMatchers("/actuator/**")
.permitAll();
return http.build();
}
}
好吧,这已经足以在服务器上注册我们的客户端应用程序。
但是,如果发生任何例外类型: httpmesagenotwratible exception 或响应错误http 416在尝试访问日志文件时,它不会害怕,如果您的系统具有某些类杰克逊配置,则可能发生这种情况扩展了 webmvcconfiguratationsupport 。
在这种情况下,可以用Spring Boot的模式禁用此类的实例。
要纠正这种问题,我们可以创建一个自定义bean并替换系统初始化中创建的标准配置。
@Configuration
public class JacksonConfig extends WebMvcConfigurationSupport {
private final Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
private static final List<MediaType> MEDIA_TYPE_LIST = List.of(
MediaType.ALL,
MediaType.parseMediaType("application/vnd.spring-boot.actuator.v2+json")
);
@Bean
public MappingJackson2HttpMessageConverter customMappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = actuatorConverter();
converter.setSupportedMediaTypes(MEDIA_TYPE_LIST);
return converter;
}
private MappingJackson2HttpMessageConverter actuatorConverter() {
return new MappingJackson2HttpMessageConverter(builder.build()) {
@Override
protected boolean canWrite(MediaType mediaType) {
// O método super, retorna true se for null.
// Assim evitamos a exceção _HttpMessageNotWritableException_ caso o Content-Type 'null' seja enviado.
return mediaType != null && super.canWrite(mediaType);
}
};
}
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
/*
Remove somente o MappingJackson2HttpMessageConverter
padrão e substitui pelo customMappingJackson2HttpMessageConverter.
*/
var defaultHttpConverterOpt = converters.stream()
.filter(MappingJackson2HttpMessageConverter.class::isInstance)
.findFirst();
defaultHttpConverterOpt.ifPresent(converters::remove);
converters.add(customMappingJackson2HttpMessageConverter());
}
}
目前是圣。 ato©更多! ;)