编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

如何做自己的服务监控?spring boot 1.x服务监控揭秘

wxchong 2024-08-04 02:46:58 开源技术 27 ℃ 0 评论

1.准备

下载可运行程序:http://www.mkyong.com/spring-boot/spring-boot-hello-world-example-jsp/

2.添加服务监控依赖

 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-actuator</artifactId>
 <scope>provided</scope>
 </dependency>

3.启动spring boot项目

console 截图如下:

4.servlet和filter

4.1 使用ServletRegistrationBean注册dispatcherServlet

/**
 * A {@link ServletContextInitializer} to register {@link Servlet}s in a Servlet 3.0+
 * container. Similar to the {@link ServletContext#addServlet(String, Servlet)
 * registration} features provided by {@link ServletContext} but with a Spring Bean
 * friendly design.
 * <p>
 * The {@link #setServlet(Servlet) servlet} must be specified before calling
 * {@link #onStartup}. URL mapping can be configured used {@link #setUrlMappings} or
 * omitted when mapping to '/*' (unless
 * {@link #ServletRegistrationBean(Servlet, boolean, String...) alwaysMapUrl} is set to
 * {@code false}). The servlet name will be deduced if not specified.
 *
 * @param <T> the type of the {@link Servlet} to register
 * @author Phillip Webb
 * @since 1.4.0
 * @see ServletContextInitializer
 * @see ServletContext#addServlet(String, Servlet)
 */

总结:类似于ServletContext#addServlet(String, Servlet)

查看所有注册的bean

http://127.0.0.1:8080/beans

并把返回的json 格式化 视图查看,在线工具(http://www.bejson.com/jsonviewernew/)

注册的流程:

spring-boot-autoconfigure模块spring.facotories的属性org.springframework.boot.autoconfigure.EnableAutoConfiguration=DispatcherServletAutoConfiguration

 @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
 @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
 public DispatcherServletRegistrationBean dispatcherServletRegistration(
 DispatcherServlet dispatcherServlet) {
 DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(
 dispatcherServlet, this.webMvcProperties.getServlet().getPath());
 registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
 registration.setLoadOnStartup(
 this.webMvcProperties.getServlet().getLoadOnStartup());
 if (this.multipartConfig != null) {
 registration.setMultipartConfig(this.multipartConfig);
 }
 return registration;
 }

4.2 使用FilterRegistrationBean注册各种filter

/**
 * A {@link ServletContextInitializer} to register {@link Filter}s in a Servlet 3.0+
 * container. Similar to the {@link ServletContext#addFilter(String, Filter) registration}
 * features provided by {@link ServletContext} but with a Spring Bean friendly design.
 * <p>
 * The {@link #setFilter(Filter) Filter} must be specified before calling
 * {@link #onStartup(ServletContext)}. Registrations can be associated with
 * {@link #setUrlPatterns URL patterns} and/or servlets (either by {@link #setServletNames
 * name} or via a {@link #setServletRegistrationBeans ServletRegistrationBean}s. When no
 * URL pattern or servlets are specified the filter will be associated to '/*'. The filter
 * name will be deduced if not specified.
 *
 * @param <T> the type of {@link Filter} to register
 * @author Phillip Webb
 * @since 1.4.0
 * @see ServletContextInitializer
 * @see ServletContext#addFilter(String, Filter)
 * @see DelegatingFilterProxyRegistrationBean
 */

总结:类似于ServletContext#addFilter(String, Filter)

spring-boot-actuator-autoconfigure模块spring.facotories的属性org.springframework.boot.autoconfigure.EnableAutoConfiguration=WebMvcMetricsAutoConfiguration,......

5.RequestMappingHandlerAdapter查找controller注解

使用

2019-01-16 09:47:07.715 INFO 8468 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@66ac5762: startup date [Wed Jan 16 09:47:06 CST 2019]; root of context hierarchy

定义:

/**
 * An {@link AbstractHandlerMethodAdapter} that supports {@link HandlerMethod}s
 * with their method argument and return type signature, as defined via
 * {@code @RequestMapping}.
 *
 * <p>Support for custom argument and return value types can be added via
 * {@link #setCustomArgumentResolvers} and {@link #setCustomReturnValueHandlers}.
 * Or alternatively, to re-configure all argument and return value types,
 * use {@link #setArgumentResolvers} and {@link #setReturnValueHandlers}.
 *
 * @author Rossen Stoyanchev
 * @author Juergen Hoeller
 * @since 3.1
 * @see HandlerMethodArgumentResolver
 * @see HandlerMethodReturnValueHandler
 */

内部实现源码

private void initControllerAdviceCache() {
 if (getApplicationContext() == null) {
 return;
 }
 if (logger.isInfoEnabled()) {
 logger.info("Looking for @ControllerAdvice: " + getApplicationContext());
 }
 List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
 AnnotationAwareOrderComparator.sort(beans);
 List<Object> requestResponseBodyAdviceBeans = new ArrayList<Object>();
 for (ControllerAdviceBean bean : beans) {
 Set<Method> attrMethods = MethodIntrospector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
 if (!attrMethods.isEmpty()) {
 this.modelAttributeAdviceCache.put(bean, attrMethods);
 if (logger.isInfoEnabled()) {
 logger.info("Detected @ModelAttribute methods in " + bean);
 }
 }
 Set<Method> binderMethods = MethodIntrospector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
 if (!binderMethods.isEmpty()) {
 this.initBinderAdviceCache.put(bean, binderMethods);
 if (logger.isInfoEnabled()) {
 logger.info("Detected @InitBinder methods in " + bean);
 }
 }
 if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
 requestResponseBodyAdviceBeans.add(bean);
 if (logger.isInfoEnabled()) {
 logger.info("Detected RequestBodyAdvice bean in " + bean);
 }
 }
 if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
 requestResponseBodyAdviceBeans.add(bean);
 if (logger.isInfoEnabled()) {
 logger.info("Detected ResponseBodyAdvice bean in " + bean);
 }
 }
 }
 if (!requestResponseBodyAdviceBeans.isEmpty()) {
 this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
 }
 }

6.使用RequestMappingHandlerMapping查找controller映射路径

2019-01-16 09:47:07.758 INFO 8468 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String com.mkyong.WelcomeController.welcome(java.util.Map<java.lang.String, java.lang.Object>)

定义:

/**
 * Creates {@link RequestMappingInfo} instances from type and method-level
 * {@link RequestMapping @RequestMapping} annotations in
 * {@link Controller @Controller} classes.
 *
 * @author Arjen Poutsma
 * @author Rossen Stoyanchev
 * @author Sam Brannen
 * @since 3.1
 */

作用:使用注解@RequestMapping在controller类内创建一个类型或者方法级别的RequestMappingInfo实例

7.EndpointHandlerMapping映射的监控项

2019-01-15 14:19:30.985 INFO 9440 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/trace || /trace.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-01-15 14:19:30.986 INFO 9440 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/health || /health.json],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(java.security.Principal)
2019-01-15 14:19:30.987 INFO 9440 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/metrics/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)
2019-01-15 14:19:30.987 INFO 9440 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/metrics || /metrics.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-01-15 14:19:30.988 INFO 9440 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/dump || /dump.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-01-15 14:19:30.988 INFO 9440 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/heapdump || /heapdump.json],methods=[GET],produces=[application/octet-stream]}" onto public void org.springframework.boot.actuate.endpoint.mvc.HeapdumpMvcEndpoint.invoke(boolean,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException,javax.servlet.ServletException
2019-01-15 14:19:30.989 INFO 9440 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/beans || /beans.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-01-15 14:19:30.990 INFO 9440 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/autoconfig || /autoconfig.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-01-15 14:19:30.992 INFO 9440 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/env/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint.value(java.lang.String)
2019-01-15 14:19:30.992 INFO 9440 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/env || /env.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-01-15 14:19:30.995 INFO 9440 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/info || /info.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-01-15 14:19:30.996 INFO 9440 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/mappings || /mappings.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2019-01-15 14:19:30.996 INFO 9440 --- [ main] o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/configprops || /configprops.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()

其中,

/trace 通过EndpointMvcAdapter.invoke()触发TraceEndpoint的invoke方法

/health通过HealthMvcEndpoint.invoke()触发

/metrics/{name:.*}通过MetricsMvcEndpoint.value()触发

/metrics通过EndpointMvcAdapter.invoke()触发MetricsEndpoint的invoke方法

/dump通过EndpointMvcAdapter.invoke()触发DumpEndpoint的invoke方法

/heapdump通过HeapdumpMvcEndpoint.invoke()触发

/beans通过EndpointMvcAdapter.invoke()触发BeansEndpoint的invoke方法

/autoconfig通过EndpointMvcAdapter.invoke()触发AutoconfigEndpoint的invoke方法

/env/{name:.*}通过EnvironmentMvcEndpoint.value()方法触发

/info通过EndpointMvcAdapter.invoke()触发InfoEndpoint的invoke方法

/mappings通过通过EndpointMvcAdapter.invoke()触发RequestMappingEndpoint的invoke方法

小结:

restful请求实现分两种,一种通过EndpointMvcAdapter.invoke()触发

而EndpointMvcAdapter.invoke()通过注解@GetMapping实现了restful服务

/**
 * Adapter class to expose {@link Endpoint}s as {@link MvcEndpoint}s.
 *
 * @author Dave Syer
 * @author Andy Wilkinson
 */
public class EndpointMvcAdapter extends AbstractEndpointMvcAdapter<Endpoint<?>> {
 /**
 * Create a new {@link EndpointMvcAdapter}.
 * @param delegate the underlying {@link Endpoint} to adapt.
 */
 public EndpointMvcAdapter(Endpoint<?> delegate) {
 super(delegate);
 }
 @Override
 @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
 @ResponseBody
 public Object invoke() {
 return super.invoke();
 }
}

另一种,通过继承MvcEndpoint的invoke方法来触发

例如HealthMvcEndpoint

 @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
 @ResponseBody
 public Object invoke(Principal principal) {
 if (!getDelegate().isEnabled()) {
 // Shouldn't happen because the request mapping should not be registered
 return getDisabledResponse();
 }
 Health health = getHealth(principal);
 HttpStatus status = getStatus(health);
 if (status != null) {
 return new ResponseEntity<Health>(health, status);
 }
 return health;
 }

7.1 EndpointHandlerMapping的定义

/**
 * {@link HandlerMapping} to map {@link Endpoint}s to URLs via {@link Endpoint#getId()}.
 * The semantics of {@code @RequestMapping} should be identical to a normal
 * {@code @Controller}, but the endpoints should not be annotated as {@code @Controller}
 * (otherwise they will be mapped by the normal MVC mechanisms).
 * <p>
 * One of the aims of the mapping is to support endpoints that work as HTTP endpoints but
 * can still provide useful service interfaces when there is no HTTP server (and no Spring
 * MVC on the classpath). Note that any endpoints having method signatures will break in a
 * non-servlet environment.
 *
 * @author Phillip Webb
 * @author Christian Dupuis
 * @author Dave Syer
 */

7.2 层次结构

7.3 查看对应的bean的生成

 {
 "bean": "endpointHandlerMapping",
 "aliases": [
 
 ],
 "scope": "singleton",
 "type": "org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping",
 "resource": "class path resource [org/springframework/boot/actuate/autoconfigure/EndpointWebMvcManagementContextConfiguration.class]",
 "dependencies": [
 
 ]
 }

7.4 获取流程

 @Bean
 @ConditionalOnMissingBean
 public EndpointHandlerMapping endpointHandlerMapping() {
 Set<? extends MvcEndpoint> endpoints = mvcEndpoints().getEndpoints(); //1
 CorsConfiguration corsConfiguration = getCorsConfiguration(this.corsProperties);
 EndpointHandlerMapping mapping = new EndpointHandlerMapping(endpoints,
 corsConfiguration); //2
 boolean disabled = this.managementServerProperties.getPort() != null 
 && this.managementServerProperties.getPort() == -1; 
 mapping.setDisabled(disabled);
 if (!disabled) {
 mapping.setPrefix(this.managementServerProperties.getContextPath()); //3
 }
 if (this.mappingCustomizers != null) {
 for (EndpointHandlerMappingCustomizer customizer : this.mappingCustomizers) {
 customizer.customize(mapping); //4
 }
 }
 return mapping;
 }

7.4.1 MvcEndpoints获取endpoint定义

 @Override
 public void afterPropertiesSet() throws Exception {
 Collection<MvcEndpoint> existing = BeanFactoryUtils
 .beansOfTypeIncludingAncestors(this.applicationContext, MvcEndpoint.class)
 .values();
 this.endpoints.addAll(existing);
 this.customTypes = findEndpointClasses(existing);
 @SuppressWarnings("rawtypes")
 Collection<Endpoint> delegates = BeanFactoryUtils
 .beansOfTypeIncludingAncestors(this.applicationContext, Endpoint.class)
 .values();
 for (Endpoint<?> endpoint : delegates) {
 if (isGenericEndpoint(endpoint.getClass()) && endpoint.isEnabled()) {
 EndpointMvcAdapter adapter = new EndpointMvcAdapter(endpoint);
 String path = determinePath(endpoint,
 this.applicationContext.getEnvironment());
 if (path != null) {
 adapter.setPath(path);
 }
 this.endpoints.add(adapter);
 }
 }
 }

7.4.2 定义映射关系

其内部实现源码:

 private String getPath(Object handler) {
 if (handler instanceof String) {
 handler = getApplicationContext().getBean((String) handler);
 }
 if (handler instanceof MvcEndpoint) {
 return ((MvcEndpoint) handler).getPath();
 }
 return "";
 }

7.4.3 增加contextpath

7.4.4 自定义EndpointHandlerMappingCustomizer

8.其它通过

 @Bean
 @ConditionalOnBean(EnvironmentEndpoint.class)
 @ConditionalOnEnabledEndpoint("env")
 public EnvironmentMvcEndpoint environmentMvcEndpoint(EnvironmentEndpoint delegate) {
 return new EnvironmentMvcEndpoint(delegate);
 }
 @Bean
 @ConditionalOnMissingBean
 @ConditionalOnEnabledEndpoint("heapdump")
 public HeapdumpMvcEndpoint heapdumpMvcEndpoint() {
 return new HeapdumpMvcEndpoint();
 }
 @Bean
 @ConditionalOnBean(HealthEndpoint.class)
 @ConditionalOnEnabledEndpoint("health")
 public HealthMvcEndpoint healthMvcEndpoint(HealthEndpoint delegate,
 ManagementServerProperties managementServerProperties) {
 HealthMvcEndpoint healthMvcEndpoint = new HealthMvcEndpoint(delegate,
 isHealthSecure(), managementServerProperties.getSecurity().getRoles());
 if (this.healthMvcEndpointProperties.getMapping() != null) {
 healthMvcEndpoint
 .addStatusMapping(this.healthMvcEndpointProperties.getMapping());
 }
 return healthMvcEndpoint;
 }
 @Bean
 @ConditionalOnBean(MetricsEndpoint.class)
 @ConditionalOnEnabledEndpoint("metrics")
 public MetricsMvcEndpoint metricsMvcEndpoint(MetricsEndpoint delegate) {
 return new MetricsMvcEndpoint(delegate);
 }
 @Bean
 @ConditionalOnEnabledEndpoint("logfile")
 @Conditional(LogFileCondition.class)
 public LogFileMvcEndpoint logfileMvcEndpoint() {
 return new LogFileMvcEndpoint();
 }
 @Bean
 @ConditionalOnBean(ShutdownEndpoint.class)
 @ConditionalOnEnabledEndpoint(value = "shutdown", enabledByDefault = false)
 public ShutdownMvcEndpoint shutdownMvcEndpoint(ShutdownEndpoint delegate) {
 return new ShutdownMvcEndpoint(delegate);
 }

以health为例

 @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
 @ResponseBody
 public Object invoke(Principal principal) {
 if (!getDelegate().isEnabled()) {
 // Shouldn't happen because the request mapping should not be registered
 return getDisabledResponse();
 }
 Health health = getHealth(principal);
 HttpStatus status = getStatus(health);
 if (status != null) {
 return new ResponseEntity<Health>(health, status);
 }
 return health;
 }

调用HealthEndpoint

 /**
 * Invoke all {@link HealthIndicator} delegates and collect their health information.
 */
 @Override
 public Health invoke() {
 return this.healthIndicator.health();
 }

总结:

spring boot提供http请求的方式可以分两种:

1.通过查找@Controller注解中的@RequestMapping来形成HandlerMapping

2.直接通过@RequestMapping来形成HandlerMapping如actuator模块,这里面又分成两种:

2.1 一种集中式的通过继承@RequestMapping来实现如通过EndpointMvcAdapter.invoke()触发

2.2 另一种通过直接的@RequestMapping注解实现

3.spring boot1.x监控的实现

/trace 通过EndpointMvcAdapter.invoke()触发TraceEndpoint的invoke方法

/health通过HealthMvcEndpoint.invoke()触发

/metrics/{name:.*}通过MetricsMvcEndpoint.value()触发

/metrics通过EndpointMvcAdapter.invoke()触发MetricsEndpoint的invoke方法

/dump通过EndpointMvcAdapter.invoke()触发DumpEndpoint的invoke方法

/heapdump通过HeapdumpMvcEndpoint.invoke()触发

/beans通过EndpointMvcAdapter.invoke()触发BeansEndpoint的invoke方法

/autoconfig通过EndpointMvcAdapter.invoke()触发AutoconfigEndpoint的invoke方法

/env/{name:.*}通过EnvironmentMvcEndpoint.value()方法触发

/info通过EndpointMvcAdapter.invoke()触发InfoEndpoint的invoke方法

/mappings通过通过EndpointMvcAdapter.invoke()触发RequestMappingEndpoint的invoke方法。

4. 这些实现都定义在spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.CacheStatisticsAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.InfoContributorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.MetricRepositoryAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.MetricsDropwizardAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.MetricsChannelAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.MetricExportAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.PublicMetricsAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.TraceRepositoryAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.TraceWebFilterAutoConfiguration
org.springframework.boot.actuate.autoconfigure.ManagementContextConfiguration=\
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcManagementContextConfiguration,\
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcHypermediaManagementContextConfiguration

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表