第3章 Spring Boot快速开始Hello World
2017-09-13 14:28
561 查看
第3章 Spring Boot快速开始Hello World
3.1 SpringBoot版的Restful Hello,World
3.1.1 Spring Boot CLI groovy版Hello World
首先安装Spring Boot CLI,参考文档:http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#getting-started-installing-the-cli在命令行验证spring环境安装成功:
$ spring --version Spring CLI v1.3.6.RELEASE
随便打开编辑器,敲入如下代码:
@Controller class HelloController{ @RequestMapping("/hello") @ResponseBody String hello(){ return "Hello World!" } }
然后在命令行执行:
$ spring run HelloController.groovy
你将看到如下输出日志:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.3.6.RELEASE) 2017-04-04 21:37:29.685 INFO 87317 --- [ runner-0] o.s.boot.SpringApplication : Starting application on jacks-MacBook-Air.local with PID 87317 (/Users/jack/.m2/repository/org/springframework/boot/spring-boot/1.3.6.RELEASE/spring-boot-1.3.6.RELEASE.jar started by jack in /Users/jack/book) 2017-04-04 21:37:29.699 INFO 87317 --- [ runner-0] o.s.boot.SpringApplication : No active profile set, falling back to default profiles: default 2017-04-04 21:37:30.367 INFO 87317 --- [ runner-0] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@30cc0018: startup date [Tue Apr 04 21:37:30 CST 2017]; root of context hierarchy 2017-04-04 21:37:33.757 INFO 87317 --- [ runner-0] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http) 2017-04-04 21:37:33.790 INFO 87317 --- [ runner-0] o.apache.catalina.core.StandardService : Starting service Tomcat 2017-04-04 21:37:33.793 INFO 87317 --- [ runner-0] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.0.36 2017-04-04 21:37:33.986 INFO 87317 --- [ost-startStop-1] org.apache.catalina.loader.WebappLoader : Unknown loader org.springframework.boot.cli.compiler.ExtendedGroovyClassLoader$DefaultScopeParentClassLoader@67cc18dd class org.springframework.boot.cli.compiler.ExtendedGroovyClassLoader$DefaultScopeParentClassLoader 2017-04-04 21:37:34.037 INFO 87317 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2017-04-04 21:37:34.038 INFO 87317 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3673 ms 2017-04-04 21:37:34.538 INFO 87317 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/] 2017-04-04 21:37:34.552 INFO 87317 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] 2017-04-04 21:37:34.553 INFO 87317 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] 2017-04-04 21:37:34.553 INFO 87317 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] 2017-04-04 21:37:34.553 INFO 87317 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] 2017-04-04 21:37:35.309 INFO 87317 --- [ runner-0] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@30cc0018: startup date [Tue Apr 04 21:37:30 CST 2017]; root of context hierarchy 2017-04-04 21:37:35.482 INFO 87317 --- [ runner-0] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/hello]}" onto public java.lang.String HelloController.hello() 2017-04-04 21:37:35.485 INFO 87317 --- [ runner-0] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 2017-04-04 21:37:35.486 INFO 87317 --- [ runner-0] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) 2017-04-04 21:37:35.523 INFO 87317 --- [ runner-0] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2017-04-04 21:37:35.524 INFO 87317 --- [ runner-0] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2017-04-04 21:37:35.606 INFO 87317 --- [ runner-0] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2017-04-04 21:37:36.225 INFO 87317 --- [ runner-0] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup 2017-04-04 21:37:36.397 INFO 87317 --- [ runner-0] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http) 2017-04-04 21:37:36.403 INFO 87317 --- [ runner-0] o.s.boot.SpringApplication : Started application in 8.263 seconds (JVM running for 12.897)
一个极简的Restful Hello World就搞定了。浏览器访问:http://localhost:8080/hello(或者curl http://localhost:8080/hello)
你会看到输出:
Hello World!
3.1.2 常规的Java版的Hello World
1.命令行输入:$ spring init -dweb --build gradle Using service at https://start.spring.io Content saved to 'demo.zip'
2.解压zip,导入idea中
你将看到如下一个Demo Application
. ├── build.gradle ├── gradle │ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src ├── main │ ├── java │ │ └── com │ │ └── example │ │ └── DemoApplication.java │ └── resources │ ├── application.properties │ ├── static │ └── templates └── test └── java └── com └── example └── DemoApplicationTests.java 14 directories, 8 files
其中DemoApplication.java代码如下:
package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
build.gradle配置文件如下:
buildscript { ext { springBootVersion = '1.5.2.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test') }
OK,我们直接Run
Run
同样的,你讲看到如下日志:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.5.2.RELEASE) 2017-04-04 22:51:58.995 INFO 89676 --- [ main] com.example.DemoApplication : Starting DemoApplication on jacks-MacBook-Air.local with PID 89676 (/Users/jack/book/demo/build/classes/main started by jack in /Users/jack/book/demo) 2017-04-04 22:51:58.998 INFO 89676 --- [ main] com.example.DemoApplication : No active profile set, falling back to default profiles: default 2017-04-04 22:51:59.191 INFO 89676 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6950e31: startup date [Tue Apr 04 22:51:59 CST 2017]; root of context hierarchy 2017-04-04 22:52:02.718 INFO 89676 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http) 2017-04-04 22:52:02.750 INFO 89676 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat 2017-04-04 22:52:02.754 INFO 89676 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.11 2017-04-04 22:52:02.974 INFO 89676 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2017-04-04 22:52:02.974 INFO 89676 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3788 ms 2017-04-04 22:52:03.173 INFO 89676 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/] 2017-04-04 22:52:03.198 INFO 89676 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] 2017-04-04 22:52:03.199 INFO 89676 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] 2017-04-04 22:52:03.199 INFO 89676 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] 2017-04-04 22:52:03.200 INFO 89676 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] 2017-04-04 22:52:03.758 INFO 89676 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6950e31: startup date [Tue Apr 04 22:51:59 CST 2017]; root of context hierarchy 2017-04-04 22:52:03.931 INFO 89676 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 2017-04-04 22:52:03.932 INFO 89676 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) 2017-04-04 22:52:03.986 INFO 89676 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2017-04-04 22:52:03.987 INFO 89676 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2017-04-04 22:52:04.076 INFO 89676 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2017-04-04 22:52:04.334 INFO 89676 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup 2017-04-04 22:52:04.447 INFO 89676 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http) 2017-04-04 22:52:04.455 INFO 89676 --- [ main] com.example.DemoApplication : Started DemoApplication in 6.41 seconds (JVM running for 7.608)
通过日志,我们可以看到SpringBootApplication大致的启动流程。这个过程中,很大一部分工作是在做Spring应用的初始化。
Initializing Spring embedded WebApplicationContext
同时,嵌入式的servlet容器tomcat的启动,org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext是关键类。对细节感兴趣的可以直接debug一下源码。
上面的代码虽然看不出什么效果。但SpringBootApplication的基本架构流程已经基本在里面了。SpringBoot通过注解@SpringBootApplication,完成了自动配置的工作。(源码参见: org.springframework.boot.autoconfigure.SpringBootApplication)
3.写个HelloWorldController
package com.example.controller; import java.util.Date; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Created by jack on 2017/4/4. */ @RestController public class HelloWorldController { @RequestMapping("hello") String hello() { return "Hello World! " + new Date(); } }
直接Run DemoApplication,我们可以看到有如下的日志:
... Mapped "{[/hello]}" onto java.lang.String com.example.controller.HelloWorldController.hello() ...
浏览器访问:http://localhost:8080/hello
我们将看到如下输出:
Hello World! Tue Apr 04 23:08:33 CST 2017
另外,如果是在命令行运行,使用SpringBoot gradle插件的执行:
$gradle bootRun
使用SpringBoot maven插件的执行:
$mvn spring-boot:run
3.2 启动Springboot的自动配置@EnableAutoConfiguration
SpringBoot AutoConfiguration的原理是通过Spring的@Conditional注解实现。@Conditional以编程的方式确定的bean的状态,来决定哪些bean是要初始化到容器中(根据外界条件注册不同Bean)。@EnableAutoConfiguration的意思是启用Spring应用程序上下文的自动配置,通过扫描CLASSPATH里面所有的组件,然后基于条件来决定是否注册bean来使得Spring的ApplicationContext自动配置。
比如说,Spring检测jdbcTemplate是否在classpath?if true, 看看bean容器里面是否有DataSource ? if true, 配置一个JdbcTemplate的Bean到容器中。
看EnableAutoConfiguration源码:
package org.springframework.boot.autoconfigure; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.Import; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({EnableAutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
可以发现,这里Import了EnableAutoConfigurationImportSelector。
Import主要是配合Configuration来使用的,用来导出更多的Configuration类,ConfigurationClassPostProcessor会读取Import的内容来实现具体的逻辑。
EnableAutoConfigurationImportSelector实现了DeferredImportSelector接口,并实现了selectImports方法,用来导出Configuration类。
String[] selectImports(AnnotationMetadata importingClassMetadata);
导出的类是通过SpringFactoriesLoader.loadFactoryNames()读取了ClassPath下面的META-INF/spring.factories文件,这个文件内容大致如下:
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ ...... org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\ org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
其中EmbeddedServletContainerAutoConfiguration是实现web服务的主要的配置类。这个类会根据当前存在的类的信息注入必要的EmbeddedServletContainerFactory类。
spring-boot-starter-tomcat引入了tomcat的依赖,所以EmbeddedServletContainerAutoConfiguration发现存在Tomcat.class就会注入TomcatEmbeddedServletContainerFactory来内置web容器。
当然,如果你想排除一些bean的自动注入,你可以用Class<?>[] exclude() 或者String[] excludeName()。
SpringBoot在spring-boot-autoconfigure-{版本号}.jar里面提供了很多AutoConfiguration的类来负责注册各种不同的组件。这些组件几乎涵盖了Spring开发中需要的绝大部分的配置。
本章源代码
https://github.com/EasySpringBoot/HelloWorld/tree/hello_world_2017.4.4相关文章推荐
- 快速构建可运行的Spring-boot项目(Hello World)
- 快速构建可运行的Spring-boot项目(Hello World)
- 快速构建可运行的Spring-boot项目(Hello World)
- Spring boot-(1) Spring Boot快速开始
- Spring Boot快速入门(Hello World)
- 快速构建可运行的Spring-boot项目(Hello World)
- easymybatis快速开始(springboot)
- 玩转spring boot——快速开始
- 快速构建可运行的Spring-boot项目(Hello World)
- Spring Boot快速入门之Hello World
- 快速构建可运行的Spring-boot项目(Hello World)
- 快速构建可运行的Spring-boot项目(Hello World)
- Spring boot教程之Spring boot简单快速入门从HelloWorld开始
- 快速构建可运行的Spring-boot项目(Hello World)
- 玩转spring boot 快速开始(1)
- 快速构建可运行的Spring-boot项目(Hello World)
- 快速构建可运行的Spring-boot项目(Hello World)
- SpringBoot初使用:从Hello World开始
- 快速构建可运行的Spring-boot项目(Hello World)
- 快速构建可运行的Spring-boot项目(Hello World)