天天看点

SpringBoot学习 @SpringBootApplication和热部署

接上篇文章,今天继续学习Spring Boot文档,

禁用具体的自动配置的类

在前面的文章中写道

spring boot

是可以在项目启动的时候,根据

pom.xml

中的

spring boot

依赖进行继承,相关的依赖会自动配置,那么如何来禁用其中某个自动配置的类,下面来说一下方法:

可以看一下

@EnableAutoConfiguration

注解的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * 排除指定的自动配置类,这样它们就永远不会被执行
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * 如果要排除的类不在当前路劲中,可以使用该方法
	 * 排除,需要指定那些类的名字的全限定的类的名字,
	 * 这样它们就永远不会被执行
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}
           

比如可以这样写:

@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
           

最后,还可以使用

spring.autoconfigure.exclude

属性控制要排除的自动配置类的列表。

举例:

@ComponentScan

注解可以扫描到它的包及子包下的所有

bean

,比如下面这个例子:

package com.example.demo;

import com.example.demo.sub.ExtralClass;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        ExtralClass extra =  context.getBean(ExtralClass.class);
        System.out.println(extra);
    }
}
           
package com.example.demo.sub;

import org.springframework.stereotype.Component;

@Component
public class ExtralClass {
}
           

从代码可以看出来

ExtraClass

Application.java

的子包的类,我们通过在

application.java

中打印,发现执行了,而且打印出了如下的信息,说明该

ExtralClass.java

也被纳入到容器中进行管理。

SpringBoot学习 @SpringBootApplication和热部署

当我们使用

@SpringBootApplication

注解中的属性对于指定的类进行排除,那么我们在启动项目的时候会看到一场信息,比如添加了

exclude

属性来禁用,让扫描不到

ExtraClass

package com.example.demo;

import com.example.demo.sub.ExtralClass;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication(exclude = ExtralClass.class)
public class Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        ExtralClass extra =  context.getBean(ExtralClass.class);
        System.out.println(extra);
    }
}
           

运行异常信息如下:

SpringBoot学习 @SpringBootApplication和热部署

从异常信息中可以看出,这里说了,

ExtralClass.java

不是一个自动配置类,无法排除掉。

同样也可以使用

@SpringBootApplication(excludeName = "com.example.demo.sub.ExtralClass")

,效果和上图的错误信息提示一致。

Spring Bean和依赖注入

在我们的日常开发中,我们经常使用

@ComponentScan

注解来寻找你的

Bean

,通过使用

@Autowired

注解来进行构造器注入。

如果你在你的包的根目录中的

application.class

,你可以添加

@ComponentScan

注解(可以不写任何参数),你的应用的所有组件(

@Component

,

@Service

,

@Repository

,

@Controller

等等)会被自动的注册为

Spring

的容器。

下面的这个例子是使用了

@Service

注解,进行构造器注入来获取一个

RiskAssessor

Bean。

package com.example.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DatabaseAccountService implements AccountService {
	private final RiskAssessor riskAssessor;
	@Autowired
	public DatabaseAccountService(RiskAssessor riskAssessor) {
		this.riskAssessor = riskAssessor;
	}
}
           

Bean的注入方式:

关于

Bean

的注入我们有三种方式:

(1)构造器注入

(2)

setter

注入

(3)接口注入

其中我们最常用的第二种

Setter

注入的方式。

@SpringBootApplication注解

一般我们在

spring boot

项目中会使用

@SpringBootApplication

注解,因为它可以做到自动配置,组件类扫描和定义额外的配置类,也就是说一个注解可以达到三种效果,而这三种效果又相当于三个注解的作用,这三个等价注解分别是:

(1)

@EnableAutoConfiguration

:自动装配依赖

(2)

@ComponentScan

:在应用程序所在的包上启用@component 的扫描

(3)

@Configuration

:允许在上下文中注册额外的

Bean

,或者引入额外的配置类

因此

@SpringBootApplication

注解相当于

@EnableAutoConfiguration

@ComponentScan

@Configuration

注解的综合效果。

其实,在2.1.5版本中可以看到

@SpringBootApplication

注解中没有明确写

@Configuration

注解,但是存在一个

@SpringBootConfiguration

注解,在该注解中包含一个

@Configuration

注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//该注解中存在@Configuration注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM,
				classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
           
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}
           

@SpringBootApplication

也提供别名来定制这两个属性

@EnableAutoConfiguration

@ComponentScan

.

比如,你不想使用

@ComponentScan

注解来扫描自动将

bean

纳入容器,你可以选择使用

@Import

注解自己手动写好需要纳入容器的类:

package com.example.myapplication;

import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@EnableAutoConfiguration
@Import({ MyConfig.class, MyAnotherConfig.class })
public class Application {
	public static void main(String[] args) {
			SpringApplication.run(Application.class, args);
	}

}
           

如何来运行你的spring boot 的可执行jar

如果你将你的项目打包成为一个可执行的Jar,通过使用命令你可以运行你可执行的jar文件,你打包好的jar文件一般在你的target目录下面,如果要运行可以参考如下命令:

$ java -jar target/myapplication-0.0.1-SNAPSHOT.jar
           

还可以在启用远程调试支持的情况下运行打包应用程序。这样做可以将调试器附加到打包的应用程序,如下面的示例所示:

$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \
       -jar target/myapplication-0.0.1-SNAPSHOT.jar
           

使用Maven Plugin

Spring boot

项目有

maven plugin

,其中包含了一个

run

的全局命令,它可以很快的编译并运行你的应用。下面是一个典型的例子:

$ mvn spring-boot:run
           

特别需要注意的是:当你的maven项目过大的时候,启动项目可能会抛出溢出的异常信息,此时,我们就需要设置一下maven的JVM参数,如下所示:

$ export MAVEN_OPTS=-Xmx1024m
           

使用Gradle插件

使用如下的命令:

$ gradle bootRun
           

如果项目启动的时候出现溢出,那么可以进行如下的操作系统设置:

$ export JAVA_OPTS=-Xmx1024m
           

总结:当出现溢出的时候,因为项目过大,此时我们就需要调整JVM参数,来调整一下堆的大小。

热部署

可以采用JRebel插件。

spring boot

也提供了

spring-boot-devtools

模块支持快速重启应用程序。

pom.xml

文件中,你可以添加如下的依赖:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-devtools</artifactId>
	<optional>true</optional>
</dependency>
           

如果是在

gradle

中,可以添加如下的依赖:

configurations {
	developmentOnly
	runtimeClasspath {
		extendsFrom developmentOnly
	}
}
dependencies {
	developmentOnly("org.springframework.boot:spring-boot-devtools")
}
           

当你运行一个完整的包应用的时候,开发工具是被自动禁止的。如果你的应用是通过

java -jar

命令来运行或者是从一个特殊的加载器启动,那么该应用就会被认为是一个“生产应用”。如果不适用于你,那么你就应该考虑排除掉

devtools

或者在系统属性中进行如下的设置

-Dspring.devtools.restart.enable=false

默认情况下,重新打包的存档不包含

devtools

。如果要使用某个远程

devtools

功能,则需要禁用

excludedevtools build

属性来包含它。

Maven

Gradle

插件都支持该属性。

默认的属性

SpringBoot

支持的几个库使用缓存来提高性能。例如,模板引擎缓存已编译的模板,以避免重复解析模板文件。此外,

SpringMVC

还可以在服务静态资源时向响应添加HTTP缓存头。

虽然缓存在生产中非常有益,但在开发过程中它可能会适得其反,从而阻止您看到刚刚在应用程序中所做的更改。因此,

Spring-boot-devtools

默认禁用缓存。

缓存选项通常在

application.properties

文件中进行设置。例如,

thymeleaf

提供

spring.thymeleaf.cache

属性。

Springbootdevtools

模块不需要手动设置这些属性,而是自动应用合理的开发时间配置。

因为在开发

SpringMVC

SpringWebFlux

应用程序时需要更多关于

Web

请求的信息,开发人员工具将为

Web

日志记录组启用

DEBUG

日志记录。这将为您提供有关传入请求、哪个处理程序正在处理它、响应结果等的信息。如果您希望记录所有请求详细信息(包括潜在的敏感信息),可以打开

spring.http.log-request-details

配置属性。

如果你不希望使用默认的属性,那么你可以在

application.properties

中设置

spring.devtools.add-properties=false

可以去这个类

DevToolsPropertyDefaultsPostProcessor

中查看完整的

devtools

中包含的属性:

static {
		Map<String, Object> properties = new HashMap<>();
		properties.put("spring.thymeleaf.cache", "false");
		properties.put("spring.freemarker.cache", "false");
		properties.put("spring.groovy.template.cache", "false");
		properties.put("spring.mustache.cache", "false");
		properties.put("server.servlet.session.persistent", "true");
		properties.put("spring.h2.console.enabled", "true");
		properties.put("spring.resources.cache.period", "0");
		properties.put("spring.resources.chain.cache", "false");
		properties.put("spring.template.provider.cache", "false");
		properties.put("spring.mvc.log-resolved-exception", "true");
		properties.put("server.error.include-stacktrace", "ALWAYS");
		properties.put("server.servlet.jsp.init-parameters.development", "true");
		properties.put("spring.reactor.stacktrace-mode.enabled", "true");
		PROPERTIES = Collections.unmodifiableMap(properties);
	}

           

自动重启

当你的应用中不管什么时间,有文件变动的时候,应用使用

spring-boot-devtools

自动重启。在你使用IDE的时候这个最有助于开发,避免你手动启动项目,目前在我们项目中,我的IDEA中旧装了

JRebel

插件,当你的文件有改动的时候,项目就会自动编译改动过的文件。对于静态的资源是不需要重新启动应用的。

触发重新启动

由于devtools监视类路径资源,触发重新启动的唯一方法是更新类路径。导致类路径更新的方式取决于您使用的IDE。在Eclipse中,保存修改过的文件会导致类路径更新并触发重新启动。在intellij思想中,构建项目(build->build project)具有相同的效果。

DevTools

是依赖于应用上下文关闭

hook

的,如果你进行了如下的设置

SpringApplication springApplication = new SpringApplication(); springApplication.setRegisterShutdownHook(false);

那么它当前就不可以正常工作。

当确定类路径上的条目在更改时是否应触发重新启动时,devtools会自动忽略名为:

spring-boot, spring-boot-devtools

,

spring-boot-autoconfigure

,

spring-boot-actuator

, 和

spring-boot-starter

.

devtools

需要自定义

applicationContext

使用的

resourceloader

。如果您的应用程序已经提供了一个,那么它将被包装。不支持直接重写

ApplicationContext

上的

getResource

方法。

重新启动与重新加载

SpringBoot

提供的重启技术通过使用两个类加载器来工作。不更改的类(例如,来自第三方

JAR

的类)被加载到基本类加载器中。您正在积极开发的类将加载到重新启动的类加载器中。重新启动应用程序时,会丢弃重新启动类加载器并创建新的类加载器。这种方法意味着应用程序的重新启动通常比“冷启动”快得多,因为基本类加载器已经可用并已填充。

如果您发现重启对于您的应用程序来说不够快,或者遇到了类加载问题,那么您可以考虑重新加载技术,如

jrebel from zeroturnary

。这些方法是在加载类时重写类,以使它们更易于重新加载。

总结:所以说,我们使用

JRebel

是对你修改过的类文件进行重新加载,然后利用,而不是重新启动项目,来加载所有的类文件。

记录条件评估中的更改

默认情况下,每次重新启动应用程序时,都会记录一个显示条件评估增量的报告。当您进行诸如添加或删除bean以及设置配置属性等更改时,报告将显示对应用程序自动配置的更改。

要禁用报告的日志记录,请设置以下属性:

spring.devtools.restart.log-condition-evaluation-delta=false
           

资源排除

当某些资源发生变动的时候是不需要重新启动的。比如

Thymeleaf

模板可以被及时的编辑。默认的,改变这些下面的资源的时候,不会触发项目重新启动,但是会触发一个

live reload

/META-INF/maven, /META-INF/resources, /resources, /static, /public, 或者 /templates

。如果你想定制这些排除,你可以使用

spring.devtools.restart.exclude

属性,例如,排除掉

/static

/public

下改动的资源:

spring.devtools.restart.exclude=statis/**,public/**
           

如果要保留这些默认值并添加其他排除项,请改用

spring.devtools.restart.additional-exclude

属性。

类路径之外的文件变动

你或许想要你的应用重新启动或者加载当你改变了一些不在当前类路径的文件。此时可以使用

spring.devtools.restart.additional-paths

属性来配置额外的路径来关注文件的变化。您可以使用前面描述的

spring.devtools.restart.exclude

属性控制附加路径下的更改是触发完全重新启动还是实时重新加载。

禁用重启项

在你不想使用重启项的时候,你可以使用

spring.devtools.restart.enabled

属性的设置来禁用重新启动。在大多数情况下,你可以在

application.properties

文件中进行设置:

spring.devtools.restart.enabled=false
           

(虽然你禁用了重新启动的属性,仍然会初始化重启加载器,但是它会忽略文件的变动)

如果你想完全禁用重启项支持(例如,因为它不适用于特定的类库),在调用

SpringApplication.run(...)

方法之前,你可以设置

spring.devtools.restart.enabled

属性通过

System

.,例如:

public static void main(String[] args) {
	System.setProperty("spring.devtools.restart.enabled", "false");
	SpringApplication.run(MyApp.class, args);
}
           

使用触发器文件

如果您使用的是一个持续编译更改文件的IDE,那么您可能更喜欢只在特定的时间触发重启。为此,您可以使用“触发器文件”,这是一个特殊的文件,当您想要实际触发重新启动检查时,必须对其进行修改。更改文件只会触发检查,仅当devtools检测到必须执行某些操作时才会重新启动。触发器文件可以手动更新,也可以使用IDE插件更新。

要使用触发器文件,请将

spring.devtools.restart.trigger-file

属性设置为触发器文件的路径。

您可能希望将

spring.devtools.restart.trigger-file

设置为全局设置,以便所有项目的行为方式都相同。

自定义重新启动类加载器

上面讨论过重新启动和重新加载的区别,重新启动是需要两个类加载器,一个是未改变的类的加载器,一个是有改动的类的加载器。对于大多数应用,重新启动都是管用的。但是,有时候重新启动会造成一些加载的问题。

默认的,任何开源的项目在IDE中被加载都是通过“重新启动

restart

"加载器,任何正规的

.jar

文件被加载都是通过"基本"的类加载器。如果你的项目处于一个多模块化,并且不是所有的模块都引入到你的IDE中,那么你或许需要定制化一些东西,这样你就需要创建一个

META-INF/spring-devtools.properties

文件。

这个文件是干嘛用的?它里面包含了一些包含前缀为

restart.exclude

restart.include

的属性。

include

元素是应该是被放入“

restart

”类加载器的类别,

exclude

元素是应该放入“

base

”类加载器的项。属性的值是应用于类路径的正则表达式模式,如下例所示:

restart.exclude.companycommonlibs=/mycorp-common-[\\w-]+\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w-]+\.jar
           

所有的属性的

key

都应该是独一无二的,而且所有的

key

都应该用

restart.include.

或者

restart.exclude.

开头。

将加载类路径中的所有

meta-inf/spring-devtools.properties

。您可以将文件打包到项目内部或项目使用的库中。

已知限制

重新启动功能不适用于使用标准

ObjectInputstream

反序列化的对象。如果需要反序列化数据,可能需要将

Spring

configurableObjectInputstream

thread.currentThread().getContextClassLoader()

结合使用。

不幸的是,一些第三方库在不考虑上下文类加载器的情况下反序列化。如果你发现这样一个问题,你需要向原始作者请求修复。

LiveReoload

spring-boot-devtools

模块包含一个内嵌的

LiveReload

服务,当资源文件有改动的时候可以被用来触发浏览器刷新。

LiveReload

浏览器的扩展对于Chrome, Firefox 和Safari来说是可以利用的。

你只可以一次运行一个

LiveReload

服务。在你启动你的应用之前,确保没有其他的

LiveReload

服务正在运行。如果你从你的IDE中启动多个应用,那么只有第一个

LiveReload

是被支持的。

全局设置

可以通过将名为

.spring-boot-devtools.properties

的文件添加到

$home

文件夹来配置全局

devtools

设置(请注意,文件名以

“.”

开头)。添加到此文件的任何属性都将应用于使用

devtools

的计算机上的所有

Spring

引导应用程序。例如,要将

Restart

配置为始终使用触发器文件,您需要添加以下属性:

~/.spring-boot-devtools.properties.

spring.devtools.reload.trigger-file=.reloadtrigger

[注意]

.spring-boot-devtools.properties

中激活的配置文件不会影响特定配置文件的加载。

远程应用

spring boot

开发者工具不仅限于本地的开发,而且当你远程运行应用的时候还可以使用一些新特性。远程支持即

opt-in

。你应该确保你的

devtools

被包含在重新打包的存档中。

<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

,在远程应用上面启动

spring-boot-devtools

是存在安全风险的。建议不要在远程应用中开启这个支持。

远程

devtools

支持分为两部分:接受连接的服务器端端点和在

IDE

中运行的客户端应用程序。设置

spring.devtools.remote.secret

属性时,将自动启用服务器组件。必须手动启动客户端组件。

运行远程客户端应用程序

远程客户端应用程序设计为从您的IDE中运行。您需要使用与所连接的远程项目相同的类路径运行。

org.springframework.boot.devtools.RemoteSpringApplication

。应用程序的单个必需参数是它所连接的远程URL。

例如,如果你正在使用

Eclipse

或者

STS

,并且你的项目名字叫做

my-app

,你要把该项目部署到云端,那么你将做下面的事情:

(1)选择

Run Configurations...

Run

菜单中

(2)创建一个新的Java应用程序来运行配置

(3)使用

org.springframework.boot.devtools.RemoteSpringApplication

作为

main

(4)将

https://myapp.cfapps.io

添加到

Program arguments

(或任何远程URL)。

一个运行的远程客户端或许像下面显示的这样:

.   ____          _                                              __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _          ___               _      \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` |        | _ \___ _ __  ___| |_ ___ \ \ \ \
 \\/  ___)| |_)| | | | | || (_| []::::::[]   / -_) '  \/ _ \  _/ -_) ) ) ) )
  '  |____| .__|_| |_|_| |_\__, |        |_|_\___|_|_|_\___/\__\___|/ / / /
 =========|_|==============|___/===================================/_/_/_/
 :: Spring Boot Remote :: 2.1.5.RELEASE

2015-06-10 18:25:06.632  INFO 14938 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Starting RemoteSpringApplication on pwmbp with PID 14938 (/Users/pwebb/projects/spring-boot/code/spring-boot-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code/spring-boot-samples/spring-boot-sample-devtools)
2015-06-10 18:25:06.671  INFO 14938 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.spring[email protected]2a17b7b6: startup date [Wed Jun 10 18:25:06 PDT 2015]; root of context hierarchy
2015-06-10 18:25:07.043  WARN 14938 --- [           main] o.s.b.d.r.c.RemoteClientConfiguration    : The connection to http://localhost:8080 is insecure. You should use a URL starting with 'https://'.
2015-06-10 18:25:07.074  INFO 14938 --- [           main] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2015-06-10 18:25:07.130  INFO 14938 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Started RemoteSpringApplication in 0.74 seconds (JVM running for 1.105)
           

因为远程客户端应用使用的是与实际应用程序相同的类路径,所以它可以直接读取应用程序属性。这是如何读取

spring.devtools.remote.secret

属性并将其传递给服务器进行身份验证。

建议将

https://

作为连接协议,以便在传递的过程中加密,密码不会被拦截。

如果你想使用一个代理来访问远程应用,配置一下下面两个属性:

spring.devtools.remote.proxy.host
spring.devtools.remote.proxy.port
           

远程更新

远程客户端以与本地重新启动相同的方式监视应用程序类路径的更改。任何更新的资源都被推送到远程应用程序,并且(如果需要)触发重新启动。如果您迭代一个使用本地没有的云服务的功能,这将很有帮助。通常,远程更新和重新启动要比完全重建和部署周期快得多。

只有在远程客户端运行时才监视文件。如果在启动远程客户端之前更改了文件,则不会将其推送到远程服务器。

SpringBoot学习 @SpringBootApplication和热部署