功能分析
1、静态资源访问
1、静态资源目录
只要静态资源放在类路径下: called /static (or /public or /resources or /META-INF/resources
访问 : 当前项目根路径/ + 静态资源名
原理: 静态映射/**。
请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404页面
改变默认的静态资源路径
spring:
mvc:
static-path-pattern: /res/**
resources:
static-locations: [classpath:/haha/]
2、静态资源访问前缀
默认无前缀
spring:
mvc:
static-path-pattern: /res/**
当前项目 + static-path-pattern + 静态资源名 = 静态资源文件夹下找
3、webjar
自动映射 /webjars/**
https://www.webjars.org/
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.5.1</version>
</dependency>
访问地址:http://localhost:8080/webjars/jquery/3.5.1/jquery.js 后面地址要按照依赖里面的包路径
2.静态资源配置原理
- SpringBoot启动默认加载 xxxAutoConfiguration 类(自动配置类)
- SpringMVC功能的自动配置类 WebMvcAutoConfiguration,生效
spring:
resources:
add-mappings: false 禁用所有静态资源规则
3、请求参数处理
1.请求映射
1、rest使用与原理
Rest风格支持(使用HTTP请求方式动词来表示对资源的操作)
Rest原理(表单提交要使用REST的时候)
-
请求过来被HiddenHttpMethodFilter拦截 # 默认是false,需要开启
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
-
spring:
mvc:
hiddenmethod:
filter:
enabled: true
-
-
-
- 获取到**_method**的值。
- 兼容以下请求;PUT.DELETE.PATCH
- 原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是传入的值。
- 过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。
修改默认的_method
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
methodFilter.setMethodParam("_m");
return methodFilter;
}
2、请求映射原理
SpringMVC功能分析都从 org.springframework.web.servlet.DispatcherServlet-》doDispatch()
protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
throws Exception {
HandlerExecutionChain mappedHandler = null;
、、、
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
mappedHandler = getHandler(processedRequest);
RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射规则。
2.普通参数与基本注解
@GetMapping("/car/{id}/owner/{username}")
public Map<String,Object> getCar(@PathVariable("id") Integer id,
@PathVariable("username") String name,
@PathVariable Map<String,String> pv,){
}
# @PathVariable Map<String,String> pv, 用来存放所有的键值对,
#@PathVariable、@RequestParam、@RequestHeader 都可用map接受,意为全部
@RequestAttribute 获取request域属性
@MatrixVariable 矩阵变量
@GetMapping("/cars/{path}")
public Map carsSell(@MatrixVariable("low") Integer low,
@MatrixVariable("brand") List<String> brand,
@PathVariable("path") String path){
Map<String,Object> map = new HashMap<>();
map.put("low",low);
map.put("brand",brand);
map.put("path",path);
return map;
}
@GetMapping("/boss/{bossId}/{empId}")
public Map boss(@MatrixVariable(value = "age",pathVar = "bossId") Integer bossAge,
@MatrixVariable(value = "age",pathVar = "empId") Integer empAge){
Map<String,Object> map = new HashMap<>();
map.put("bossAge",bossAge);
map.put("empAge",empAge);
return map;
}
配置类:
3.复杂参数
Map、**Model(map、model里面的数据会被放在request的请求域 request.setAttribute)、**Errors/BindingResult、RedirectAttributes( 重定向携带数据)、ServletResponse(response)
4.拦截器
1.HandlerInterceptor 接口
package com.atxins.practicedemo.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
Object user = session.getAttribute("loginUser");
if (user != null) {
return true;
}
request.setAttribute("msg","请先登录");
request.getRequestDispatcher("/").forward(request,response);
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
2.配置拦截器
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**");
}
}
3、拦截器原理
5、文件上传
1.文件上传代码
@PostMapping("/upload")
public String upload(@RequestParam("email") String email,
@RequestParam("username") String username,
@RequestPart("headerImg") MultipartFile headerImg,
@RequestPart("photos") MultipartFile[] photos) throws IOException {
if(!headerImg.isEmpty()){
String originalFilename = headerImg.getOriginalFilename();
headerImg.transferTo(new File("H:\\cache\\"+originalFilename));
}
if(photos.length > 0){
for (MultipartFile photo : photos) {
if(!photo.isEmpty()){
String originalFilename = photo.getOriginalFilename();
photo.transferTo(new File("H:\\cache\\"+originalFilename));
}
}
}
return "main";
}
2.文件大小限制
spring:
servlet:
multipart:
//单个文件最大限制
max-file-size: 10MB
//所有文件总的限制
max-request-size: 100MB
6、全局异常处理器
spring boot 默认情况下会映射到 /error 进行异常处理,但是提示并不十分友好,下面自定义异常处理,提供友好展示。
@RestControllerAdvice +@ExceptionHandler 实现拦截异常并统一处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = Exception.class)
public Map errorHandler(Exception ex) {
Map map = new HashMap();
map.put("code", 100);
map.put("msg", ex.getMessage());
return map;
}
@ExceptionHandler(value = MyException.class)
public Map myErrorHandler(MyException ex) {
Map map = new HashMap();
map.put("code", ex.getCode());
map.put("msg", ex.getMsg());
return map;
}
}
public class MyException extends RuntimeException {
public MyException(String code, String msg) {
this.code = code;
this.msg = msg;
}
private String code;
private String msg;
}
@RestControllerAdvice是一个组合注解,由@ControllerAdvice、@ResponseBody组成,而@ControllerAdvice继承了@Component,因此@RestControllerAdvice本质上是个Component,用于定义@ExceptionHandler,@InitBinder和@ModelAttribute方法,适用于所有使用@RequestMapping方法。
@ControllerAdvice
public class GlobalController{
@ModelAttribute
public void addUser(Model model) {
model.addAttribute("msg", "此处将键值对添加到全局,注解了@RequestMapping的方法都可以获得此键值对");
}
@InitBinder("user")
public void initBinder(WebDataBinder binder) {
}
@ExceptionHandler(Exception.class)
@ResponseBody
public String handleException(Exception e) {
return "error";
}
}
@ModelAttribute:在Model上设置的值,对于所有被 @RequestMapping 注解的方法中,都可以通过 ModelMap 获取,如下:
@RequestMapping("/home")
public String home(ModelMap modelMap) {
System.out.println(modelMap.get("author"));
}
@RequestMapping("/home")
public String home(@ModelAttribute("author") String author) {
System.out.println(author);
}
7、Web原生组件注入(Servlet、Filter、Listener)
1.使用Servlet API
@WebServlet、@WebFilter、@WebListener +@ServletComponentScan
@WebServlet(urlPatterns = "/my")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("666");
}
}
@WebFilter(urlPatterns = {"/css/*","/images/*"})
@Slf4j
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("MyFilter初始化完成");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("MyFilter工作");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
log.info("MyFilter销毁");
}
}
@WebListener
@Slf4j
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContextListener.super.contextInitialized(sce);
log.info("MyServletContextListener监听到项目初始化完成");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("MyServletContextListener监听到项目销毁");
}
}
@SpringBootApplication
@ServletComponentScan
public class PracticeDemoApplication {
public static void main(String[] args) {
SpringApplication.run(PracticeDemoApplication.class, args);
}
}
2.使用RegistrationBean
ServletRegistrationBean , FilterRegistrationBean , and ServletListenerRegistrationBean
@Configuration
public class MyRegistConfig {
@Bean
public ServletRegistrationBean myServlet(){
MyServlet myServlet = new MyServlet();
return new ServletRegistrationBean(myServlet,"/my","/my02");
}
@Bean
public FilterRegistrationBean myFilter(){
MyFilter myFilter = new MyFilter();
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean myListener(){
MySwervletContextListener mySwervletContextListener = new MySwervletContextListener();
return new ServletListenerRegistrationBean(mySwervletContextListener);
}
}
@WebServlet(urlPatterns = “/my”),为什么没有经过Spring的拦截器?
对于多个Servlet都能处理到同一层路径,根据精确优选匹配原则
A: /
B: /my/
B会执行,会由原生的servlet(Tomcat处理),而只有由DispatcherServlet(Spring)处理的请求才会经过spring的拦截器。
执行顺序:监听器>filter>自定义servlet>dispatchServlet(springMvc)
8、定制化原理
1.定制化的常见方式
- 修改配置文件;
- xxxxxCustomizer(定制化器,可以改变xxxx的默认规则);
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;
@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
}
}
- 编写自定义的配置类 xxxConfiguration;+@Bean替换、增加容器中默认组件;
- Web应用 编写一个配置类实现WebMvcConfigurer 即可定制化web功能;+ @Bean给容器中再扩展一些组件
@Configuration
public class AdminWebConfig implements WebMvcConfigurer
2.原理分析套路
场景starter - >xxxxAutoConfiguration -> 导入xxx组件 -> 绑定xxxProperties – 绑定配置文件项
9、SpringBoot整合MyBatis-Plus
1.MyBatis-Plus
整合:
【Java】classpath到底是指什么
- 配置appHcation.yaml中,可做一些全局配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
- @MapperScan(“com.atguigu.admin.mapper”)会批量扫描@Mapper标注的接口,接口就可以不用标注@Mapper注解
自动配置:
- MybatisPlusAutoConfiguration 配置类, MybatisPlusProperties 配置项绑定配置文件前缀为mybatis-plus,xxx就是对mybatis-plus的定制
- SqISessionFactory 自动配置好,底层是容器中默认的数据源
- 容器中也自动配置好了 SqISessionTemplate
- @Mapper标注的接口也会被自动扫描
**优点:**只需要我们的Mapper继承 BaseMapper 就可以拥有crud能力
2.mybatis
- 导入mybatis官方starter
- 在application.yaml中指定Mapper配置文件的位置,以及指定全局配置文件的信息 (建议;配置在mybatis.configuration)
# 配置mybatis规则
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
configuration:
map-underscore-to-camel-case: true #匹配驼峰命名
- 简单方法直接注解方式
- 复杂方法编写mapper.xml进行绑定映射
@Mapper
public interface CityMapper {
@Select("select *from city where id=#{id}")
public City getById( Long id);
}
3.MyBatis-Plus分页使用
分页插件
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();
paginationInterceptor.setDbType(DbType.POSTGRE_SQL);
paginationInterceptor.setOverflow(false);
interceptor.addInnerInterceptor(paginationInterceptor);
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
controller:
@ApiOperation(value = "分页查询老师信息")
@GetMapping("/pageTeacher/{current}/{limit}")
public R pageListTeacher(
@ApiParam(name = "current", value = "当前页", required = true) @PathVariable long current,
@ApiParam(name = "limit", value = "每页记录数", required = true)@PathVariable long limit){
Page<EduTeacher> page = new Page<>(current, limit);
teacherService.page(page, null);
return R.ok().data("total", page.getTotal()).data("rows", page.getRecords());
}
springboot~@ConditionalOnMissingBean注解的作用
Mybatis-Plus:分页,简单分页查询&复杂分页查询
10、SpringBoot整合redis
1.redis的自动配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot- starter-data-redis</artifactId>
</dependency>
自动配置:
- RedisAutoConfiguration 自动配置类。RedisProperties 属性类 --> spring.redis.xxx是对redis
的配置 - 连接工厂是准备好的。导入了LettuceConnectionConfiguration、JedisConnectionConfiguration配置类
- 自动注入了RedisTemplate<Object, Object> : xxxTemplate;
- 自动注入了StringRedisTemplate; k: v都是String
- 底层只要我们使用 StringRedisTemplate、RedisTemplate就可以操作redis
redis环境搭建:
- 阿里云搜索redis,立即购买
- 阿里云按量付费redis、经典网络、读写分离板
- 申请redis的公网连接地址
- 修改白名单 允许0.0.0.0/0 访问,即允许所有机器访问
- 可以分配账号
- 用完后进行资源释放
2.RedisTemplate与Lettuce
spring:
redis:
host: law.internal.gridsumdissector.com
port: 34490
database: 0
password: Zsydian88
timeout: 10s
lettuce:
pool:
min-idle: 0
max-idle: 8
max-active: 8
max-wait: -1ms
@Test
void testRedis() {
redisTemplate.opsForValue().set("hello","world");
String hello = redisTemplate.opsForValue().get("hello");
System.out.println(hello);
}
3.切换至jedis
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
spring:
redis:
host: law.internal.gridsumdissector.com
port: 34490
database: 0
password: Zsydian88
client-type: jedis
jedis:
pool:
max-active: 8
4.使用redis统计接口访问次数
@Component
public class RedisUrlCountInterceptor implements HandlerInterceptor {
@Resource
StringRedisTemplate stringRedisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String url = String.valueOf(request.getRequestURL());
stringRedisTemplate.opsForValue().increment(url);
return true;
}
}
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Autowired
RedisUrlCountInterceptor urlCountInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(urlCountInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/css/**","/js/**","/images/**","/html/**");
}
}
@Test
void testGetUrlCount(){
String s = stringRedisTemplate.opsForValue().get("/addOrUpdateTag");
System.out.println(Long.parseLong(s));
}
11、单元测试
1.JUnit5 的变化
Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库
JUnit 5由三个不同子项目的几个不同模块组成。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit Platform: Junit Platform是在JVM上启动测试框架的基础,不仅支持Junit自制的测试引擎,其他测试引擎也都可以接入。 JUnit Jupiter: JUnit jupiter提供了JUnit5的新的编程模型,是jUnit5新特性的核心。内部包含了一个测试引擎,用于在junit Platform上运行。 JUnit Vintage: 由于JUint已经发展多年,为了照顾老的项目,JUnit Vintage提供了兼容JUnit4.x,Junit3.x的测试引擎。
<dependency>
< groupId >org.springframework.boot </groupId >
< artifactId > spring- boot -starter-test </artifactId >
< scope>test </scope>
</dependency>
注意: SpringBoot 2.4以上版本移除了默认对 Vintage 的依赖。如果需要兼容junit4需要自行引入
<dependency>
< gnoupId >org.junit.vintage</groupId >
< antifactld >junit-vintage-engine</artifactld >
< scope>test </scope>
<exclusions>
< exclusion>
< groupId >org.hamcrest </groupId >
< artifactId > hamcrest-core</artifactId >
</exclusion >
</exclusions>
</dependency>
@SpringBootTest
class Boot05WebAdminApplicationTests {
@Test
void contextLoads(){
}
}
以前: @SpringBootTest + @RunWith(SpringTest.class)
SpringBoot整合junit以后。
- 编写测试方法:@Test标注(注意需要使用junit5版本的注解)
- Junit类具有Spring的功能, @Autowired、比如 @Transactional 标注测试方法,测试完成后自
动回滚
2.JUnit5常用注解
https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations
@Test:表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由jupiter提供额外测试 @ParameterizedTest:表示方法是参数化测试 @RepeatedTest :表示方法可重复执行 @DisplayName:为测试类或者测试方法设置展示名称 @BeforeEach:表示在每个单元测试之前执行 @AfterEach:表示在每个单元测试之后执行 @BeforeAII:表示在所有单元测试之前执行 @AfterAII:表示在所有单元测试之后执行 @Tag:表示单元测试类别,类似于JUnit4中的@Categories @Disabled:表示测试类或测试方法不执行,类似于JUnit4中的@lgnore
@Timeout:表示测试方法运行如果超过了指定时间将会返回错误 @ExtendWith:为测试类或测试方法提供扩展类引用
import org.junit.jupiter.api.Test;
@DisplayName( "JUnit5的功能测试类")
public class TestDemo {
@Test
@DisplayName( "第一次测试")
public void firstTest() {
System.out.printIn("hello world");
}
@Timeout(value = 500,unit = TimeUnit.MILLISECONDS)
@Test
void testTimeout() throws InterruptedException {
Thread.sleep( millis: 600);
}
}
@SpringBootTest
public class TestDemo {
@Test
public void firstTest() {
System.out.printIn("hello world");
}
3.断言(assertions)
简单断言
方法 | 说明 |
---|
assertEquals | 判断两个对象或两个原始类型是否相等 | assertNotEquals | 判断两个对象或两个原始类型是否不相等 | assertSame | 判断两个对象弓I用是否指向同一个对象 | assertNotSame | 判断两个对象弓I用是否指向不同的对象 | assertTrue | 判断给定的布尔值是否为 true | assertFalse | 判断给定的布尔值是否为 false | assertNull | 判断给定的对象弓I用是否为 null | assertNotNull | 判断给定的对象引用是否不为 null |
数组断言
组合断言
assertAII 方法接受多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言,可以通过 lambda 表达式很容易的提供这些断言
异常断言
超时断言
快速失败
4.前置条件(assumptions)
JUnit 5 中的前置条件 (assumptions【假设】) 类似于断言,不同之处在于不满足的断言会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止。前置条件可以看成是测试方法执行的前提,当该前提不满足时,就没有继续执行的必要。
5.嵌套测试
JUnit 5 可以通过 java 中的内部类和@Nested 注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用@BeforeEach 和@AfterEach 注解,而且嵌套的层次没有限制。
6.参数化测试
@ValueSource: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型 @Nu11Source: 表示为参数化测试提供一个nu11的入参 @EnumSource: 表示为参数化测试提供一个枚举入参 @CsvFileSource: 表示读取指定CSV文件内容作为参数化测试入参 @MethodSource: 表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)
12、Profile功能
1.pplication-profile功能
-
默认配置文件 application.yaml; 任何时候都会加载 -
指定环境配置文件 application-{env}.yaml -
激活指定环境
- 通过配置文件激活,在application.yml中
Spring:
profiles:
active: prod
- 命令行激活:java -jar xxx.jar -spring.profiles.active=prod —person.name=haha
-
默认配置与环境配置同时生效 -
同名配置项,profile配置优先
2.@Profile条件装配功能
@Profile标注在类上
public interface Person {
String getName();
Integer getAge();
}
@Profile("prod")
@Data
@Component
@ConfigurationProperties("person")
public class Boss implements Person{
private String name;
private Integer age;
}
@Profile("test")
@Data
@Component
@ConfigurationProperties("person")
public class Worker implements Person{
private String name;
private Integer age;
}
若当前环境是test,则Worker对象生效,若当前环境是prod,则Boss对象生效。
@Profile标注在方法上,指定的环境,对应的方法组件会生效
@Configuration
public class MyConfig {
@Profile("test")
@Bean
public Color red(){
return Color.RED;
}
@Profile("prod")
@Bean
public Color blue(){
return Color.BLUE;
}
}
3.profile分组
spring.profiles.group.production[0]=proddb
spring.profiles.group.production[l]=prodmq
使用: spring,profiles.active=production 激活
4.外部化配置
Core Features (spring.io)
- 外部配置源
常用:Java properties 文件、YAML文件、环境变量、命令行参数;
(环境变量、命令行参数):系统环境变量,java -jar xxx.jar --spring.application.name=xxx
@Value("MAVEN_HOME")
private String msg;
@SpringBootApplication
public class SupervisionApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(SupervisionApplication.class, args);
ConfigurableEnvironment environment = run.getEnvironment();
Map<String, Object> systemEnvironment = environment.getSystemEnvironment();
Map<String, Object> systemProperties = environment.getSystemProperties();
System.out.println(systemEnvironment);
System.out.println(systemProperties);
}
}
- 配置文件查找位置(后面的可以覆盖前面的同名配置项)
Core Features (spring.io)Core Features (spring.io)
? (1) classpath 根路径(源码包标识的都叫,java、resource)
? (2) classpath 根路径下config目录
? (3) jar包当前目录
? ⑷ jar包当前目录的config目录
? (5) /config子目录的直接子目录(在linux系统下验证)
- 配置文件加载顺序(指定环境优先,外部优先,后面的可以覆盖前面的同名配置项)
- 当前jar包内部的的application.properties和application.yml
- 当前jar包内部的的application-{profile}.properties 和 application-{profile}.yml
- 引用的外部jar包的application.properties和application.ym
- 引用的外部jar包的application-{profile}.properties 和 application-{profile}.yml
13.自定义starter
高级特性-自定义starter细节
|