Spring Boot Admin 是一個很不錯的儀表板,用于監(jiān)控您的 Spring Boot 應(yīng)用程序。然而,設(shè)置它并不是那么簡單。
- 在您的啟動應(yīng)用程序中包含一個連接到管理應(yīng)用程序的客戶端庫——這需要將管理應(yīng)用程序部署在公共的某個地方或至少可以從您的應(yīng)用程序訪問,并讓您的應(yīng)用程序知道它正在被監(jiān)控。
- 使用云發(fā)現(xiàn),這意味著您的應(yīng)用程序是服務(wù)發(fā)現(xiàn)基礎(chǔ)設(shè)施的一部分,例如使用微服務(wù)
對于更簡單的場景,例如在某些 IaaS 上運行的單體應(yīng)用程序,以及將您的管理應(yīng)用程序部署在本地機(jī)器或某些本地公司基礎(chǔ)設(shè)施中,這兩種方案都不是很好的選擇。如果您還不需要云發(fā)現(xiàn),則它是一種矯枉過正的做法,并且包含客戶端庫會引入使應(yīng)用程序可訪問管理服務(wù)器的復(fù)雜性,反之亦然。此外,這種雙向依賴聽起來是錯誤的。
幸運的是,有一個未記錄但已實現(xiàn)的方法?SimpleDiscoveryClient
?,讓您只需在任何機(jī)器上運行帶有一些配置的 Spring Boot Admin,并將其連接到您的 Spring Boot 應(yīng)用程序。
第一個要求是在您的啟動應(yīng)用程序中設(shè)置 ?spring boot actuator
?。Actuator 公開了管理應(yīng)用程序工作所需的所有端點。設(shè)置聽起來很簡單——您只需添加一堆依賴項并可能指定一些配置參數(shù),僅此而已。事實上,在實際應(yīng)用中,這并不容易——尤其是關(guān)于執(zhí)行器端點的基本身份驗證。您需要一個單獨的 ?spring-security
?(除了現(xiàn)有的 spring-security 配置之外),以便僅將基本身份驗證應(yīng)用于執(zhí)行器端點。例如:
@Configuration
@Order(99)// the default security configuration has order 100
public class ActuatorSecurityConfigurationextends WebSecurityConfigurerAdapter {
@Value("${security.user.name}")
private String username;
@Value("${security.user.password}")
private String password;
@Override
protected void configure(HttpSecurity http)throws Exception {
InMemoryUserDetailsManager manager =new InMemoryUserDetailsManager();
manager.createUser(User.withUsername(username).password(password).roles("ACTUATOR","ADMIN").build());
http.antMatcher("/manage/**").authorizeRequests().anyRequest().hasRole("ACTUATOR").and().httpBasic()
.and().userDetailsService(manager);
}
}
這有點違反直覺,但它有效。不確定它是否是慣用的——使用 spring 安全和 spring 引導(dǎo),你永遠(yuǎn)不知道什么是慣用的。注意 - 據(jù)稱應(yīng)該可以將?security.user.name
?(和 ?password
?)自動包含在某個管理器中,但我沒有找到,所以我只是在內(nèi)存中實例化了一個。請注意?/manage/**
?路徑——為了在該路徑下?lián)碛兴袌?zhí)行器端點,您需要在應(yīng)用程序?qū)傩晕募兄付?management.context-path=/manage
?。
現(xiàn)在已經(jīng)設(shè)置了執(zhí)行器端點,我們必須附加我們的 spring 管理應(yīng)用程序。它看起來像這樣:
@Configuration
@EnableAutoConfiguration
@PropertySource("classpath:/application.properties")
@EnableAdminServer
public class BootAdminApplication {
public static void main(String[] args) {
SpringApplication.run(BootAdminApplication.class, args);
}
@Autowired
private ApplicationDiscoveryListener listener;
@PostConstruct
public void init() {
// we have to fire this event in order to trigger the service registration
InstanceRegisteredEvent<?> event =new InstanceRegisteredEvent<>("prod",null);
// for some reason publising doesn't work, so we invoke directly
listener.onInstanceRegistered(event);
}
}
通常,應(yīng)該將?ApplicationEventPublisher
?消息注入并推送到那里,而不是直接調(diào)用偵聽器,如上所示。我沒有設(shè)法讓它輕松工作,所以我解決了這個問題。
提到的 ?application.properties
? 文件應(yīng)該在 src/main/resources 中,看起來像這樣:
spring.cloud.discovery.client.simple.instances.prod[0].uri=https://your-spring-boot-application-url.com
spring.cloud.discovery.client.simple.instances.prod[0].metadata.user.name=<basic-auth-username>
spring.cloud.discovery.client.simple.instances.prod[0].metadata.user.password=<basic-auth-password>
spring.boot.admin.discovery.converter.management-context-path=/manage
spring.boot.admin.discovery.services=*
那是在做什么?它正在使用SimpleDiscoveryClient由自動配置實例化的 。實際上,該客戶端直到最新版本才工作——它拋出 ?NullPointerException
?因為元數(shù)據(jù)(處理用戶名和密碼)始終為空。在 1.2.2 的 cloud-commons 中,他們修復(fù)了它:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<version>1.2.2.RELEASE</version>
</dependency>
簡單的發(fā)現(xiàn)客戶端就是這樣——您指定啟動應(yīng)用程序的 URL,它會定期從執(zhí)行器端點獲取數(shù)據(jù)。為什么沒有記錄在案,為什么它直到最近才真正起作用——我不知道。另外,我不知道為什么您必須手動發(fā)送觸發(fā)發(fā)現(xiàn)的事件。也許它不是慣用的,但它不會自動發(fā)生,這使它起作用。
像往常一樣,“正常工作”和“簡單設(shè)置”的東西——從來都不是那樣的。如果你有比 hello world 稍微復(fù)雜一點的東西,你必須挖掘一些晦澀的類并“off-road”。幸運的是,在這種情況下,它確實有效,而不是需要不好的解決方法。