SpringBootCLI使用相关
介绍
Spring Boot CLI(Command Line Interface)是一个命令行工具,我们可以用它来快速构建Spring原型应用。通过Spring Boot CLI,我们可以通过编写Java脚本来快速的构建出Spring Boot应用,并通过命令行的方式将其运行起来。
下载工具包
下载地址
这里我们使用 2.0.1.RELEASE 版本,更高的版本可能需要更高的JDK版本来配合。我们也需要提前配置JAVA路径的环境变量,这里使用JDK11。
运行Java脚本
脚本如下
@RestController
public class HelloController {
@RequestMapping("/")
public String home() {
return "Hello World!";
}
}
运行命令
.\spring.bat run HelloController.java
运行结果
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.codehaus.groovy.vmplugin.v7.Java7$1 (jar:file:/C:/Users/xxx/Downloads/spring-boot-cli-2.0.1.RELEASE-bin/spring-2.0.1.RELEASE/lib/spring-boot-cli-2.0.1.RELEASE.jar!/BOOT-INF/lib/groovy-2.4.15.jar!/) to constructor java.lang.invoke.MethodHandles$Lookup(java.lang.Class,int)
WARNING: Please consider reporting this to the maintainers of org.codehaus.groovy.vmplugin.v7.Java7$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Resolving dependencies..............................................................................
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.1.RELEASE)
2023-01-30 14:35:29.867 INFO 14080 --- [ runner-0] o.s.boot.SpringApplication : Starting application on SH-FM-NB-320 with PID 14080 (started by xxx in C:\Users\xxx\Downloads\spring-boot-cli-2.0.1.RELEASE-bin\spring-2.0.1.RELEASE\bin)
2023-01-30 14:35:29.881 INFO 14080 --- [ runner-0] o.s.boot.SpringApplication : No active profile set, falling back to default profiles: default
2023-01-30 14:35:30.096 INFO 14080 --- [ runner-0] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@1650a964: startup date [Mon Jan 30 14:35:30 CST 2023]; root of context hierarchy
2023-01-30 14:35:31.494 INFO 14080 --- [ runner-0] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-01-30 14:35:31.527 INFO 14080 --- [ runner-0] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-01-30 14:35:31.527 INFO 14080 --- [ runner-0] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.29
2023-01-30 14:35:31.540 INFO 14080 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [C:\D-myfiles\java\jdk\jdk-11\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Python27\;C:\Python27\Scripts;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\PuTTY\;C:\Program Files (x86)\Tencent\微信web开发者工具\dll;C:\Users\xxx\AppData\Local\Microsoft\WindowsApps;C:\Users\xxx\AppData\Local\Programs\Git\cmd;C:\D-myfiles\java\jdk\jdk-11\bin;C:\D-myfiles\java\apache-maven-3.6.1\bin;C:\Users\xxx\AppData\Local\Programs\Microsoft VS Code\bin;.]
2023-01-30 14:35:31.599 INFO 14080 --- [ost-startStop-1] org.apache.catalina.loader.WebappLoader : Unknown loader org.springframework.boot.cli.compiler.ExtendedGroovyClassLoader$DefaultScopeParentClassLoader@22eeefeb class org.springframework.boot.cli.compiler.ExtendedGroovyClassLoader$DefaultScopeParentClassLoader
2023-01-30 14:35:31.691 INFO 14080 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-01-30 14:35:31.691 INFO 14080 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1596 ms
2023-01-30 14:35:31.910 INFO 14080 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/]
2023-01-30 14:35:31.921 INFO 14080 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2023-01-30 14:35:31.921 INFO 14080 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2023-01-30 14:35:31.922 INFO 14080 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2023-01-30 14:35:31.922 INFO 14080 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2023-01-30 14:35:32.150 INFO 14080 --- [ runner-0] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2023-01-30 14:35:32.460 INFO 14080 --- [ runner-0] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@1650a964: startup date [Mon Jan 30 14:35:30 CST 2023]; root of context hierarchy
2023-01-30 14:35:32.564 INFO 14080 --- [ runner-0] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String HelloController.home()
2023-01-30 14:35:32.569 INFO 14080 --- [ 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.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2023-01-30 14:35:32.570 INFO 14080 --- [ 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.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2023-01-30 14:35:32.607 INFO 14080 --- [ runner-0] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2023-01-30 14:35:32.608 INFO 14080 --- [ runner-0] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2023-01-30 14:35:33.054 INFO 14080 --- [ runner-0] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2023-01-30 14:35:33.101 INFO 14080 --- [ runner-0] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-01-30 14:35:33.107 INFO 14080 --- [ runner-0] o.s.boot.SpringApplication : Started application in 3.938 seconds (JVM running for 102.914)
2023-01-30 14:36:38.790 INFO 14080 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2023-01-30 14:36:38.790 INFO 14080 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2023-01-30 14:36:38.831 INFO 14080 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 41 ms
会先去maven中央仓库下载依赖,然后运行。
原理分析
在任意一个maven项目中添加此依赖,最好不要是SpringBoot项目,可能有未知的问题。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-cli</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
启动类为 org.springframework.boot.cli.SpringCli,这里我们以 spring run xxx.java 命令为例来分析原理。
- RunCommand的run()方法
- RunOptionHandler的run()方法
- SpringApplicationRunner的compileAndRun()方法,开始编译并运行
- GroovyCompiler的compile()方法,将java文件编译为class
- 开启一个守护线程RunThread
- 创建一个SpringApplicationLauncher来启动应用程序,简单来说就是通过反射来创建 org.springframework.boot.SpringApplication 对象并调用run()方法,和我们自己启动SpringBoot项目类似。
- 编译后得到的HelloController类通过构造器参数传入SpringApplication。
在创建GroovyCompiler对象的过程中也会处理maven依赖相关,这块逻辑比较复杂,核心为AetherGrapeEngine类。
顺便一提,.\spring.bat init --dependencies=web myproject 内部就是直接调用 https://start.spring.io/starter.zip 生成项目代码,接口返回为zip文件,再解压为文件夹,起始类为InitCommand。
源码运行遇到的问题
Unable to find groovy JAR

缩短命令行的方式,不能选择第三或第四种,可以选择第一或第二种。
maven依赖的处理
点击查看代码
主要使用了aether框架,spring-boot-cli 也是在此基础上封装的。更多用法可以参考官网。
参考
Spring Boot快速开发利器:Spring Boot CLI
Spring Cloud CLI-官方
利用aether api实现从指定maven仓库下载jar包
eclipse aether入门