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
微信公众号: 架构师日常笔记 欢迎关注!