1.準備java
下載可運行程序:http://www.mkyong.com/spring-boot/spring-boot-hello-world-example-jsp/web
2.添加服務監控依賴spring
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> <scope>provided</scope> </dependency>
3.啓動spring boot項目json
console 截圖以下:restful
4.servlet和filtermvc
4.1 使用ServletRegistrationBean註冊dispatcherServletapp
/** * 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)cors
查看全部註冊的beanless
http://127.0.0.1:8080/beansjsp
並把返回的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