Spring-boot特性(1)
初始化Spring-boot
最佳的文档结构。
com
+- example
+- myproject
+- Application.java
|
+- domain
| +- Customer.java
| +- CustomerRepository.java
|
+- service
| +- CustomerService.java
|
+- web
+- CustomerController.java
spring-boot还是建议按照标准的controller-service-dao结构分层。有一个独立的Application.java作为系统启动入口。
引入
这里仅仅以Maven为例:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-spring-boot-demo</artifactId>
<version>0.1.0</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.9.RELEASE</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
</project>
引入了 spring-boot-starter-web,基本上开发一个web应用所需的包都会引入其中。如果需要使用JPA等等功能需要另外引入对应的starter。spring-boot用pom的方式整合了许多开箱即用的工具,官方称之为starter特性,后面会介绍什么是starter。
启动
Spring boot提供了多种启动方式,最简单的方式是在main方法中调用 SpringApplication.run 方法即可启动Spring Boot。当然,run方法必须要配合相关的注解才能实现Spring Boot目标功能。关于spring boot打包以及jara -jar或者CLI启动,后续的博文会介绍。
DEBUG模式
通常情况下,启动Spting Boot时日志输出都是生产模式(关闭DEBUG级别的日志),在启动参数中增加--debug参数即可开启调试模式的日志输出。
Eclipse的设置:工程右键->Debug As->Debug Configurations->打开Arguments选项->在Program arguments中增加 --debug 参数。
纯Java配置——@Configuration
@Configuration是一个用于类的注解,他可以替换原来定义在xml文件中的spring配置。当为某一个类增加这个注解后,会将其视作一个源自配置文件的Bean。
其实spring的ioc容器一直以来都没多大变化,延续基于单例的IOC的机制一直向下衍生功能线,不管使用什么注解,基本上所有用到的实例都是一个Bean,所有的Bean都放在同一个的IOC容器中(当然也可以创建多个容器,但是似乎并没什么应用需要这么特殊的实现)。Spring Xml配置是根据xml的描述生成多个Bean,而引入@Configuration注解使得配置可以彻底基于Java代码。
自动配置注入——@EnableAutoConfiguration
这个注解用于在Spring的IOC容器中启用自动推导配置功能(使用boot中定义的默认配置)。其执行过程实际就是根据classpath中的包来决定是否需要注入某个用于资源配置的Bean来支持其工作。比如在classpath中发现了tomcat-embedded.jar
这个包,那么可以推定需要启用tomcat的嵌入工具,那么boot会帮助我们创建一个 TomcatEmbeddedServletContainerFactory
的实例作为Bean放置到容器中以供其使用。我们可以通过注解的 exclude()
和 excludeName()
方法告知不需要自动生成某些配置。也可以通过声明 spring.autoconfigure.exclude
JVM参数。
实质上Spring-Boot-Web就是一个更加自动化的Spring-Webmvc——不用整合servlet容器并且分分钟启动。而Spring-Boot最大的亮点之一就是根据引入的包自动注入配置。如果打开--debug模式会看到很多匹配相关的内容输出。下面是自动匹配输出的一些内容,为了便于说明只选取了很小一部分,实际输出的内容比这个多得多。
=========================
AUTO-CONFIGURATION REPORT
=========================
Positive matches:
-----------------
DispatcherServletAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)
DispatcherServletAutoConfiguration.DispatcherServletConfiguration matched:
- @ConditionalOnClass found required class 'javax.servlet.ServletRegistration'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- Default DispatcherServlet did not find dispatcher servlet beans (DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition)
Negative matches:
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)
从AUTO-CONFIGURATION REPORT 开始就是匹配日志,Positive matche 之后的表示匹配上的配置,Negative matches之后表示未匹配上的配置。每一项的内容都详细说明了匹配上的依赖关系和未匹配的原因。
包扫描——@ComponentScan
@ComponentScan注解用于设定IOC容器加载Bean的扫描路径,等价于xml配置中的<context:component-scan>元素(@ComponentScan属于Spring Framework的Context模块)。在指定的路径中会将@Component及其子类限定的类(如@Service、@Repository、@Controller)作为一个Bean添加到IOC容器中。
@ComponentScan中包含多个参数,例如basePackages、basePackageClasses、excludeFilters等,都是用于定义扫描的包路径或限定名。如果没有为@ComponentScan注解设定任何参数,则会扫描当前包以及所有子孙包。
Spring-boot整合——@SpringBootApplication
@SpringBootApplication注解整合了@Configuration、@EnableAutoConfiguration、@ComponentScan的效果。当为一个入口类(包含启动的main方法)定义一个@SpringBootApplication注解后,意味着增加了上述三个注解的功能——1)当前类是一个资源Bean,2)启用spring boot的自动推导配置(开箱即用)、3)自动扫描入口类之后的所有子包。
所以下面2种写法实现的效果是几乎一致的(在@SpringBootApplication中对@ComponentScan做了参数限定,所以只能说几乎一致。):
@EnableAutoConfiguration
@ComponentScan
@Configuration
public class Demo{
public static void main(String[] args) throws Exception {
SpringApplication.run(Demo.class, args);
}
}
@SpringBootApplication
public class Demo{
public static void main(String[] args) throws Exception {
SpringApplication.run(Demo.class, args);
}
}
开箱即用——Starter
Spring Boot通过Maven的方式提供了一系列开箱即用(一站式服务)的工具,包括MQ、AOP、JPA等,文档上将这个特性命名为Starter。前面 引入 部分使用的 spring-boot-starter-web 就是一个Starter 。Starter 特性并没有什么新的技术,仅仅是通过pom文件的方式引用了一些必要的包,然后在引入之后通过Spring Boot的自动推导配置为引入的jar包注入必要的配置Bean。官网的表13.1 列举了所有Sprint Boot官方提供的Starter。
当然除了官方提供的Starter我们还可以自定义。不过需要注意的是命名规则——由官方提供的Starter命名规则为spring-boot-starter-*,而自定义(第三方提供)的规则为 acme-spring-boot-starter-*。自定义的Starter在某些使用需要额外指定自动配置功能,详情请看 关于自定义Starter的说明。
逐渐替换默认配置
这也是Spring Boot的最佳实践之一。虽然它提供了相当丰富的默认配置,但是并不是所有的东西用默认配置就可以解决。Spring Boot建议根据需要逐渐替换工程所需的配置。例如默认情况下工程引入了 HSQLDB ,并且没有配置DataSource,那么我们所有的数据库操作(例如JPA)都会直接使用HSQLDB内存数据库。如果我们向容器注入了DataSource实例,那么我们定义的配置将会替换默认配置。
开发Spring-boot
全局定义开发环境——spring-boot-devtools
spring-boot-devtools(以下简称Devtools)为开发环境提供了许多快速便捷的设置,仅需要增加一个依赖即可实现开发所需的配置,以Maven为例:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
在引入他之后当前环境自动变为开发环境。需要注意的是如果运行完整打包的工程Spring Boot不启用任何Devtools相关的功能(实际上打包工具spring-boot-maven-plugin默认情况下不会去打包Devtools),为了防止Devtools的作用域污染子项目,我们最好增加 Maven 的 optional 标记。
下面介绍Devtools具体提供了什么功能。
1.代码修改与热部署
Devtools 的一项功能就是能够监控代码的变更,并在发现变更时“热部署”最新的代码。不过这里的热部署不是Jvm bytecode级别的热部属,也和OGSI没任何关系。
根据官方的介绍是实现了两个ClassLoader——BaseClassLoader和RestartClassLoader(推断这2个ClassLoader应该破坏了双亲委派模型)。第一次启动JVM时所有的.class文件和.jar文件中的类都用BaseClassLoader加载,然后在开发的过程中凡是变更过的.class 文件都会被标记,这些被标记的.class之后都会使用RestartClassLoader加载。在初始化一个类时,被标记了用RestartClassLoader加载的Class<?>实例,没有被标则委派给BaseClassLoader加载,每次发起“热部署”时都会新建一个RestartClassLoader重新加载类,这样可以保证变更过的代码都是重新加载的。
在Devtools进行“热部署”时会调用spring的上下文挂钩(spring context hook)来重新部署IOC容器。如果你关闭了它——SpringApplication.setRegisterShutdownHook(false),“热部署”无法将新加载的类实例部署到IOC容器中导致代码替换失败。
上面是开发过程中Jconsole的输出,每一次修改代码保存都会新增一些非堆(方法区)的空间,这说明重新加载了新的字节码数据并解析到非堆中。
jvm环境中classPath路径下的任何文件修改都会触发Devtools 的热部署,某些时候并不需要都监控所有的路径,例如/resources、/static、/template等,我们可以通过设定spring.devtools.restart.exclude属性来排除热部署监控的位置。例如:
spring.devtools.restart.exclude=static/**
此外,使用“热部署”时还需注意以下几点(个个都有可能是引发问题的坑啊):
- 属性spring.devtools.restart.additional-paths属性可以用来增加监控classpath之外的路径。
- Devtools内嵌了LiveReload,如果不想启用它可以将spring.devtools.livereload.enabled属性设置为fasles。
- Devtools会自动忽略某些包的扫描,例如spring-boot、spring-boot-devtools、spring-boot-autoconfigure、spring-boot-actuator、spring-boot-starter。
- Devtools会修改SpringContext指定的ResourceLoader,如果自定义了一个新的ResourceLoader,修改后的getResource方法将无法生效。
- 将spring.devtools.restart.enabled属性设置为false可以关闭Devtools的“热部署”功能。
- 某些IDE整合了代码监控功能,可以通过spring.devtools.restart.trigger-file属性指定要监控的文件,只有这个文件发生变更时才会触发Devtools进行全局的文件变更检查。
- 前面介绍了Devtools的“热部署”是通过2个ClassLoader(BaseClassLoader、RestartClassLoader)实现的,默认情况下.jar包中的类只会使用BaseClassLoader加载。我们可以通过在根目录新建一个META-INF/spring-devtools.properties文件,然后在其中设置restart.exclude. 和 restart.include. 属性来指定被 RestartClassLoader 加载的 .jar 类。详情见官网例子。
2.缓存启用和停用
很多框架、工具都提供了缓存功能,在生产环境中对某些热数据进行适当的缓存能够有效的提高性能。但是在开发环境这些缓存反而会影响我们验证功能。所以Devtools全局提供了缓存管理,并默认关闭大部分工具或框架的缓存。开发人员可用通过设置运行环境properties的方式来指定缓存功能,例如:
System.setProperty("spring.thymeleaf.cache", "true");
就可以指定启用thymeleaf模板引擎的缓存。缓存管理相关的配置请看 github上spring-boot-devtools环境设置相关的代码 。
3.文件配置
除了使用参数,我们可以把Devtools的所有配置写到$HOME目录下一个".spring-boot-devtools.properties"的文件中。例如:
spring.devtools.reload.trigger-file=.reloadtrigger
4.远程开发
Devtools除了提供本机开发的增强功能之外,还增加了强大的远程开发与调试功能。
首先,我们需要在打包的时候连同spring-boot-devtools一起打包并发布,而spring-boot-maven-plugin默认不是打包Devtools的,所以我们需要将Pom文件的plugins配置简单修改一下:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeDevtools>false</excludeDevtools>
</configuration>
</plugin>
</plugins>
</build>
发布之前需要设置一个属性:
spring.devtools.remote.secret=mysecret
特别需要注意:这个属性会带来安全风险,所以仅仅用于测试和开发,切记不要用于生产运行。
将打好的包部署到远程服务器即可,我们称之为服务端。
然后,要在本地开发环境配置一个客户端。
客户端需要配合IDE一起使用。假设你的工程名字为my-app在Eclipse下进行下面的配置:
- Run 菜单栏目里选择Run Configurations...。
- 创建一个新的 Java Application(在Java Application处右键,然后选择new)。
- Project一栏里选择my-app工程。
- Main Class一栏里使用org.springframework.boot.devtools.RemoteSpringApplication作为main方法类。
- Arguments选项卡中,在Program arguments中添加服务端的地址(类似https://myapp.cfapps.io的格式)
最后,启用了spring.devtools.remote.secret之后,客户端会监控本地classpath下文件变更。一旦触发“热部署”它会先在本地完成,然后将变更的内容推送到远程服务端触发“热部署”。就像你在本地开发一样,这对开发一些回调应用和不同环境的调试带来了极大的便利。
还有,Devtools在基于jdwp远程调式的基础上进行了扩展,提供支持HTTP传输远程调试信息。绝大部分情况下都能使用Java的远程调试能解问题,如有特殊需求(如用到docker等),可以看 这里。
转载于:https://my.oschina.net/chkui/blog/1609325
推荐阅读
-
微软从明年1月12日起停止对IE6-IE8浏览器提供技术支持
-
京东华瑞1号和余额宝哪个更好些?国华华瑞1号vs余额宝收益率对比
-
Intellij IDEA创建spring-boot项目的图文教程
-
谷歌googleCode暂停服务 明年1月25日全面关闭
-
ThinkPadE430笔记本怎么设置Fn与F1至F12键的功能?
-
Android新特性ConstraintLayout完全解析
-
php让图片可以下载的代码第1/2页
-
php中的session完全教程第1/2页
-
推荐学习php sesson的朋友必看PHP会话(Session)使用入门第1/2页
-
一个简单的PHP&MYSQL留言板源码第1/2页