目录
热部署
相关问题
- 如何重新加载spring boot上的更改,而无需重启服务器?
- spring boot项目如何热部署?
常用有2种方式
- Spring Boot DevTools:监听文件修改,修改代码后自动重启应用,需要重新部署整个应用,耗时较长,不推荐
- 使用JRebel插件:支持本地热部署、远程服务器的热部署,修改代码后 Ctrl+Shift+F9 一键同步部署,只重新部署修改的部分、不重启应用,速度快,推荐。
都支持web静态资源的自动刷新,Spring Boot DevTools 刷新web静态资源无需重启应用。
方式一 Spring Boot DevTools
spring boot devtools 需要IDE自动编译的支持,先配置IDE的自动编译、运行时自动编译。
1、Settings -> Build,Execution,Deployment -> Compiler -> 勾选自动编译
2、Ctrl+Shift+Alt+/ -> Registry -> 勾选运行时自动编译
3、后续创建springboot项目时勾选 Developer Tools -> Spring Boot DevTools,或手动添加 spring-boot-devtools 的依赖,即可实现热部署
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
方式二 使用JRebel插件
1、安装插件 JRebel and XRebel
从 IDEA Plugins 安装的高版本 JRebel and XRebel,激活时容易报错 LS client not configued
,建议去插件市场搜索安装 2022.4.1 版本:
https://plugins.jetbrains.com/plugin/4441-jrebel-and-xrebel/versions/stable/245481
2、激活JRebel
https://www.guidgen.com/ -> 复制GUID
JRebel Activation -> Team URL -> 填写 https://jrebel.qekang.com/{GUID}、邮箱,邮箱可以瞎填
3、点击右上角的JRebel运行应用,修改代码后 Ctrl+Shift+F9 同步更改
web静态资源的存放
springboot默认的web静态资源存放位置有4个
- classpath:/static
- classpath:/public
- classpath:/resources
- classpath:/META-INF/resources
一般是在resources下新建static文件夹存放web静态资源。
jackson日期时间设置
可以在yml中统一设置 jackson 的日期时间格式,不必在实体类的每个Date字段上加@JsonFormat
spring:
jackson:
serialization:
# 序列化时Date转换为时间戳,key也可以写为 WRITE_DATES_AS_TIMESTAMPS
write-dates-as-timestamps: true
# 不管是前后端交互,还是后端不同编程语言写的服务之间的交互,时间戳格式都通用,不推荐使用以下格式
# date-format: yyyy-MM-dd HH:mm:ss
# time-zone: GMT+8
组件扫描、资源导入
引导类上的 @SpringBootApplication 中包含了 @ComponentScan,但默认只扫描引导类同级目录下的组件,不会扫描依赖中的组件。
一些基础模块、类库,可能会直接使用spring|springboot来写,使用dspring|springboot的注解。引入这种依赖包时,需要在显式配置包扫描,把要扫描的依赖中的包也加进去
组件扫描
- 可以用 @ComponentScan 或 @ComponentScans 来配置,可以配置多个 @ComponentScan
- 可以用单独的配置类 (@Configuration)来配置,也可以直接标注在引导类上
- 指定 项目本身 + 依赖 中要扫描的包
//value、basePackages互为别名,String[]
@ComponentScan({"com.chy.xxx1", "com.chy.xxx2"})
//可以用 excludeFilters 排除指定包中不需要扫描的类
@ComponentScan(
value = {"com.chy.xxx1", "com.chy.xxx2"},
//@ComponentScan.Filter[]
excludeFilters = {
//排除指定的类,value为String[],classes为Class[],互为别名
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {com.chy.xxx1.A.class, com.chy.xxx2.B.class}),
//排除指定注解
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {com.chy.xxx1.A.class, com.chy.xxx2.B.class}),
//排除正则表达式匹配的包、类
@ComponentScan.Filter(type = FilterType.REGEX, pattern = {"com.chy.xxx1.config", "com.chy.xxx2.config"})
})
//不一定非要配置value,比如项目中自定义的bean、依赖中定义的bean冲突,可以直接excludeFilters移除不需要的
@ComponentScan(excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {com.chy.xxx1.A.class, com.chy.xxx2.B.class}),
})
//value是 @ComponentScan[]
@ComponentScans(value = {
@ComponentScan({"com.chy.xxx1", "com.chy.xxx2"}),
@ComponentScan({"com.chy.xxx3", "com.chy.xxx4"})
})
//@SpringBootApplication与@ComponentScan、@EnableAutoConfiguration的部分字段互为别名,可以直接配置
@SpringBootApplication(
//要扫描的包
scanBasePackages = {"com.chy.xxx1", "com.chy.xxx2"},
//要扫描的类
scanBasePackageClasses = {com.chy.xxx1.A.class, com.chy.xxx2.B.class},
//要排除的自动配置类,也可以用 excludeName 字段来配置。关联的是 @EnableAutoConfiguration 的字段,只能排除自动配置类,不同于 @ComponentScan 的 excludeFilters
//自动配置类bean定义冲突报错时,也可以用此属性来排除
exclude = {DataSourceAutoConfiguration.class}
)
资源导入
//value、locations互为别名,String[]
@ImportResource({"classpath*:spring/**.xml"})
运行项目的多个实例
勾选Allow parallel run
修改项目使用的端口号有2种方式
- 在VM options中指定,示例: -Dserver.port=9000
- 在Program arguments中指定,示例:–server.port=9000,注意此处是2根短横
这2种方式均会覆盖配置文件中指定的端口号。
资源文件的拷贝问题
运行、打包时resources下很多自定义的文件夹、文件都不会自动拷贝,需要我们配置一下pom.xml
<build>
<!--配置resources的拷贝-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
如果已存在输出目录target文件夹,需要先删除target文件夹才会生效
读取resources下的文件
假设要读取的文件是 resources/template/1.txt
// 方式一 开头不加/
ClassPathResource classPathResource = new ClassPathResource("template/1.txt");
InputStream is = classPathResource.getInputStream();
// 方式二 开头要加/
InputStream is = this.getClass().getResourceAsStream("/template/1.txt");
SpEL的解析、计算
有时候需要将表达式放到数据表、nacos配置等外部位置,动态加载解析表达式,传入参数计算结果。
eg. 一个连续7天的抽奖活动,要求第一天中奖概率100%,每天的中奖概率依次降低10%
//表达式
String probabilityExpression = "1 - (#root['dayNum']-1) * 0.1";
//String probabilityExpression = "1 - (#this.get('dayNum')-1) * 0.1";
SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
Expression expression = spelExpressionParser.parseExpression(probabilityExpression);
//参数,Object类型,常使用数组、集合、实体对象
Map<String, Object> extParams = new HashMap<>();
extParams.put("dayNum", dayNum);
//传入参数,计算结果
StandardEvaluationContext ctx = new StandardEvaluationContext(extParams);
Double result = expression.getValue(ctx, Double.class);
表达式
- 对象用 .fieldName 来取字段值,map用 [‘key’] 来取值,数组用 [index] 来取元素。
- 可以使用2个内置对象:#root、#this,都表示传入的参数(整体),#root是数据容器、上下文,用于取值;#this代表参数自身,即传入的map、实体等的引用,可以通过#this来调用map、实体等的方法。
常见问题
运行、打包springboot项目时报错:找不到主类
可以尝试以下三种方式
- mvn clean compile,重新编译(推荐)
- 清除IDEA的缓存后重启IDEA
- 在pom.xml中显式指定主类
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!--指定主类-->
<mainClass>com.chy.mall.MallApplication</mainClass>
</configuration>
</plugin>