[TOC]
SpringCloud系列
以下内容,均在搭建 项目时,收集和写下的一些内容,如有错误欢迎指正>>>
实际中应用及推荐文章
推荐文章:https://blog.csdn.net/zrl0506/article/details/80165477
推荐文章:https://blog.csdn.net/qq_37170583/article/details/80704904
SpringCloud和SpringBoot对应版本
官方文档:http://spring.io/projects/spring-cloud(一切始于官方文档)
Table1
Table2
Component
Edgware.SR5
Finchley.SR2
Finchley.BUILD-SNAPSHOT
spring-cloud-cloudfoundry
注意:
SpringCloud 版本为 Edgware 及以下,eureka包改为:
Copy <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
SpringCloud 版本为 Edgware 以上,eureka包改为netflix:
Copy <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
SpringCloudEureka
入门案例(一) Server与Client
入门案例(二)Server、Porvider与Consumer
项目整体结构:
eureka-server入门
一、导入jar
Copy <?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>
<artifactId>lemon-soa</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-eureka-server</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/>
</parent>
<properties>
<spring-cloud.version>Dalston.SR4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
二、建立启动类
Copy package com.lemon.eureka.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @author sjp
*/
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
三、配置yml
Copy server:
port: 9001
eureka:
instance:
hostname: eureka-service
client:
# 不注册自己
register-with-eureka: false
# 获取服务
fetch-registry: false
# 注册中心地址
service-url:
defaultZone: http://localhost:${server.port}/eureka/
四、访问
http://localhost:9001/
eureka-api 入门
Tips :此部分属于provider和consumer公用部分,所以单独作为一个模块,打包成jar供provider和consumer使用
模块结构
一、导入jar
Copy <?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>
<artifactId>eureka-api</artifactId>
</project>
二、建立相关类
Copy package com.lemon.soa.api;
public interface VideoService {
/**
* 获取视频信息
* @param videoId 视频id
* @return 视频信息
*/
double getVideo(long videoId);
}
eureka-provider入门
Tips : Eureka本身只区分server和client(client有provider和consumer),通过不同的配置来告知client,本身是provider还是consumer.
模块结构
一、导入jar
Copy <?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>
<artifactId>eureka-provider</artifactId>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Dalston.SR4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--内部依赖-->
<dependency>
<groupId>com.lemon</groupId>
<artifactId>eureka-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
二、建立相关类
启动类:
Copy package com.lemon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class EurekaProviderApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaProviderApplication.class, args);
}
}
服务接口实现:
Copy package com.lemon.api.impl;
import org.springframework.stereotype.Service;
import com.lemon.soa.api.VideoService;
/**
* @author sjp
* @date 2019/1/24
**/
@Service
public class VideoServiceImpl implements VideoService {
@Override
public double getVideo(long videoId) {
return Math.random();
}
}
暴露服务:
Copy package com.lemon.controller;
import com.lemon.soa.api.VideoService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class VideoController {
@Resource
private VideoService videoService;
@RequestMapping(value = "/{videoId}", method = RequestMethod.GET)
public Double getVideo(@PathVariable long videoId) {
return videoService.getVideo(videoId);
}
}
三、配置yml
Copy server:
port: 9002
spring:
application:
name: eureka-provider
eureka:
instance:
#使用ip进行注册
prefer-ip-address: true
client:
serviceUrl:
defaultZone: http://localhost:9001/eureka/
四、访问
http://localhost:9001/
eureka-consumer入门
模块结构
一、导入jar
Copy <?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>
<artifactId>eureka-consumer</artifactId>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.12.RELEASE</version>
</parent>
<properties>
<spring-cloud.version>Edgware.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
二、建立相关类
启动类:
Copy package com.lemon.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @author sjp
* @date 2019/1/24
**/
@EnableDiscoveryClient
@SpringBootApplication
public class EurekaConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaConsumerApplication.class, args);
}
/**
* 启用负载均衡,默认算法是轮询
*/
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
调用服务:
Copy package com.lemon.consumer.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @author sjp
* @date 2019/1/24
**/
@RestController
public class ConsumerController {
@Resource
private RestTemplate restTemplate;
@RequestMapping("/")
public Double index() {
return restTemplate.getForObject("http://eureka-provider/1", Double.class);
}
}
三、配置yml
Copy server:
port: 9003
spring:
application:
name: eureka-consumer
eureka:
instance:
# 使用IP注册
prefer-ip-address: true
#注册地址
client:
service-url:
defaultZone: http://localhost:9001/eureka/
四、访问
http://localhost:9001/
熟悉掌握
eureka-server配置详解
自我保护模式,当出现出现网络分区、eureka在短时间内丢失过多客户端时,会进入自我保护模式,即一个服务长时间没有发送心跳,eureka 也不会将其删除,默认为true
eviction-interval-timer-in-ms
eureka server清理无效节点的时间间隔,默认60000毫秒,即60秒
a-s-g-cache-expiry-timeout-ms
缓存ASG信息的到期时间,单位为毫秒,默认为10 * 60 * 1000
查询AWS上ASG(自动缩放组)信息的超时值,单位为毫秒,默认为300
获取aws访问的id,主要用于弹性ip绑定,此配置是用于aws上的
获取aws私有秘钥,主要用于弹性ip绑定,此配置是用于aws上的
表示集群节点之间的复制是否为了网络效率而进行批处理
delta-retention-timer-interval-in-ms
清理任务程序被唤醒的时间间隔,清理过期的增量信息,单位为毫秒
disable-delta-for-remote-regions
disable-transparent-fallback-to-other-region
如果在远程区域本地没有实例运行,对于应用程序回退的旧行为是否被禁用
e-i-p-bind-rebind-retries
e-i-p-binding-retry-interval-ms-when-unbound
e-i-p-binding-retry-interval-ms
enable-replicated-request-compression
g-zip-content-from-remote-region
eureka服务器中获取的内容是否在远程地区被压缩,默认为true
如果没有设置默认的编解码器将使用全JSON编解码器,获取的是编码器的类名称
list-auto-scaling-groups-role-name
Eureka服务器是否应该登录clientAuthHeaders
max-elements-in-peer-replication-pool
max-elements-in-status-replication-pool:
max-idle-thread-age-in-minutes-for-peer-replication
min-threads-for-status-replication
max-idle-thread-in-minutes-age-for-status-replication
max-threads-for-peer-replication
尝试在丢弃复制事件之前进行复制的时间,默认为30000毫秒
min-threads-for-peer-replication
number-of-replication-retries
peer-eureka-nodes-update-interval-ms
集群里eureka节点的变化信息更新的时间间隔,单位为毫秒
peer-eureka-status-refresh-time-interval-ms
peer-node-connect-timeout-ms
peer-node-read-timeout-ms
peer-node-total-connections
peer-node-connection-idle-timeout-seconds
http连接被清理之后服务器的空闲时间,默认为30秒
peer-node-total-connections-per-host
prime-aws-replica-connections
速率限制的burst size ,默认为10,这里用的是令牌桶算法
rate-limiter-full-fetch-average-rate
速率限制器用的是令牌桶算法,此配置指定平均执行请求速率,默认为100
rate-limiter-privileged-clients
认证的客户端列表,这里是除了标准的eureka Java客户端。
rate-limiter-registry-fetch-average-rate
速率限制器用的是令牌桶算法,此配置指定平均执行注册请求速率,默认为500
rate-limiter-throttle-standard-clients
当eureka服务器启动时尝试去获取集群里其他服务器上的注册信息的次数,默认为5
registry-sync-retry-wait-ms
当eureka服务器启动时获取其他服务器的注册信息失败时,会再次尝试获取,期间需要等待的时间,默认为30 * 1000毫秒
remote-region-app-whitelist
remote-region-connect-timeout-ms
连接到对等远程地eureka节点的超时时间,默认为1000毫秒
remote-region-connection-idle-timeout-seconds
http连接被清理之后远程地区服务器的空闲时间,默认为30秒
remote-region-fetch-thread-pool-size
用于执行远程区域注册表请求的线程池的大小,默认为20
remote-region-read-timeout-ms
获取从远程地区eureka节点读取信息的超时时间,默认为1000毫秒
remote-region-registry-fetch-interval
从远程区域取出该注册表的信息的时间间隔,默认为30秒
remote-region-total-connections
获取远程地区对等节点上http连接的总数,默认为1000
remote-region-total-connections-per-host
获取远程地区特定的对等节点上http连接的总数,默认为500
remote-region-trust-store
用来合格请求远程区域注册表的信任存储文件,默认为空
remote-region-trust-store-password
获取偏远地区信任存储文件的密码,默认为“changeit”
remote-region-urls-with-name
renewal-percent-threshold
阈值因子,默认是0.85,如果阈值比最小值大,则自我保护模式开启
renewal-threshold-update-interval-ms
response-cache-auto-expiration-in-seconds
当注册表信息被改变时,则其被保存在缓存中不失效的时间,默认为180秒
response-cache-update-interval-ms
客户端的有效负载缓存应该更新的时间间隔,默认为30 * 1000毫秒
retention-time-in-m-s-in-delta-queue
客户端保持增量信息缓存的时间,从而保证不会丢失这些信息,单位为毫秒
route53-bind-rebind-retries
route53-binding-retry-interval-ms
服务器应该检查是否和Route53域绑定的时间间隔,默认为5 * 60 * 1000毫秒
sync-when-timestamp-differs
use-read-only-response-cache
目前采用的是二级缓存策略,一个是读写高速缓存过期策略,另一个没有过期只有只读缓存,默认为true,表示只读缓存
wait-time-in-ms-when-sync-empty
在Eureka服务器获取不到集群里对等服务器上的实例时,需要等待的时间,单位为毫秒,默认为1000 * 60 * 5
如果没有设置默认的编解码器将使用xml编解码器,获取的是编码器的类名称
SpringCloudFegin
官方文档:https://cloud.spring.io/spring-cloud-static/spring-cloud-openfeign/2.0.2.RELEASE/single/spring-cloud-openfeign.html
一、导入jar
Springboot 2.0.0 以下
Copy <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
Springboot 2.0.0 及以上
Copy <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
二、建立相关类
启动类(加上注解):
Copy /**
* 如果为了把eureka共有接口抽成单独模块,需注明扫描包,才可以加载jar包中的@FeignClient
* @EnableFeignClients(basePackages = { "com.lemon.soa.api" })
*/
@EnableFeignClients
修改类:
Copy package com.lemon.soa.api;
// 其中eureka-provider是提供服务者的应用名,即eureka-provider的应用名
@FeignClient(name = "eureka-provider")
public interface VideoService {
/**
* 获取视频信息
* @param videoId 视频id
* @return 视频信息
*/
@GetMapping(value = "/{videoId}")
double getVideo(long videoId);
}
调用服务:
Copy package com.lemon.consumer.controller;
import com.lemon.soa.api.dto.CategoryDTO;
import com.lemon.soa.api.provider.CategoryProvider;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* @author sjp
* @date 2019/1/24
**/
@RestController
public class ConsumerController {
/**
* feign 方式
*/
@Resource
private CategoryProvider categoryProvider;
@GetMapping(value = "/category")
public List<CategoryDTO> getCategoryTree() {
return categoryProvider.getCategoryTree();
}
}
三、配置yml
Copy server:
port: 9003
spring:
application:
name: eureka-consumer
eureka:
instance:
# 使用IP注册
prefer-ip-address: true
#注册地址
client:
service-url:
defaultZone: http://localhost:9001/eureka/
四、访问
http://localhost:9001/
坑:
问题一:
有些公共的组件抽出来其他模块的maven依赖,此时要在使用的项目中加载此jar包的spring component以及feign组件,仅仅依靠@ComponentScan是不够的,还需要在@EnableFeignClients(basePackages = {"com.xixicat"})中标注basekPackages。
问题二:
使用@FeignClient注解,要求name不重复,否则Bean会被覆盖,或者无法启动。这是Feign的一个缺点吧。
推荐修复方案:
Copy spring:
# 允许重复名称的bean定义,为了解决Fegin重复命名无法启动的问题
main:
allow-bean-definition-overriding: true
其他修复方案(手动初始化Feign代理的类):
Copy package com.lemon.consumer.controller;
import com.lemon.soa.api.dto.CategoryDTO;
import com.lemon.soa.api.dto.VideoDTO;
import com.lemon.soa.api.provider.CategoryProvider;
import com.lemon.soa.api.provider.VideoProvider;
import feign.Client;
import feign.Contract;
import feign.Feign;
import feign.Logger;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.slf4j.Slf4jLogger;
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
import org.springframework.context.annotation.Import;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* FeginMutiNameController Fegin的一个缺陷,feginName不可以重复定义(除set allow-bean-definition-overriding: true的第二种方案)
* @author sjp
* @date 2019/12/15
*/
@RestController
@Import(FeignClientsConfiguration.class)
public class FeginMutiNameController {
private VideoProvider videoProvider;
private CategoryProvider categoryProvider;
public FeginMutiNameController(Decoder decoder, Encoder encoder, Client client, Contract contract) {
this.videoProvider = Feign.builder().client(client).encoder(encoder).decoder(decoder).contract(contract)
// 默认是Logger.NoOpLogger
.logger(new Slf4jLogger(VideoProvider.class))
// 默认是Logger.Level.NONE
.logLevel(Logger.Level.FULL).target(VideoProvider.class, "http://provider");
this.categoryProvider = Feign.builder().client(client).encoder(encoder).decoder(decoder).contract(contract)
// 默认是Logger.NoOpLogger
.logger(new Slf4jLogger(CategoryProvider.class))
// 默认是Logger.Level.NONE
.logLevel(Logger.Level.FULL).target(CategoryProvider.class, "http://provider");
}
@GetMapping(value = "/test1")
public List<CategoryDTO> getCategoryTree() {
return categoryProvider.getCategoryTree();
}
@GetMapping(value = "/test2/{id}")
public VideoDTO index(@PathVariable(value = "id") Long id) {
return videoProvider.getVideo(id);
}
}
SpringCloud使用Config作为配置中心
一、介绍
服务端:配置中心
客户端:接受配置的应用
二、配置
1、Server端配置
A、pom
Copy <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>1.5.13.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
<!-- 添加spring-boot的maven插件 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
B、yml
C、Application
Copy import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
/**
* @author sjp
*/
@EnableConfigServer
@SpringBootApplication
public class LemonConfigApplication {
public static void main(String[] args) {
SpringApplication.run(LemonConfigApplication.class, args);
}
}
全部配置好后,启动应用,访问 http://localhost:9000/admin/dev (http://localhost:9000/admin-dev.json,http://localhost:9000/admin-dev.properties)
注:配置文件的访问规则如下:
Copy /{name}-{profiles}.yml
/{label}/{name}-{profiles}.yml
name : 文件名,一般以服务名来命名
profiles : 一般作为环境标识
lable : 分支(branch),指定访问某分支下的配置文件
例如:http://localhost:9000/dv_lemon_2019_07/provider-dev.yml
有一点值得注意的是,如果有两个前缀名相同文件,例如一个order.yml,一个order-dev.yml。那么在访问相同前缀的文件时,config-server会对这两个文件进行一个合并。例如order.yml有一段配置是order-dev.yml没有的,理应访问order-dev.yml的时候是没有那段配置的,但访问的结果却是它俩合并之后的内容,即order-dev.yml会拥有order.yml里所配置的内容。
2、Client端配置
A、pom
Copy <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>1.5.13.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 实现Config的客户端配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- 实现通过端点refresh手动刷新 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<!-- 添加spring-boot的maven插件 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
B、yml
Copy # 对应着config server所获取配置文件的{application}和URL
spring:
application:
name: admin
cloud:
config:
uri: http://localhost:9000/
# 对应着文件后面的后缀{profile}
profile: dev
# 分支
label: master
Copy version-config: ${version}
C、Application
Copy @SpringBootApplication
public class LemonAdminApplication {
public static void main(String[] args) {
SpringApplication.run(LemonAdminApplication.class, args);
}
}
D、Controller
Copy import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@Controller
@RestController
public class LoginController {
@Value("${version-config}")
private String version;
@GetMapping("/test")
public String getVersion() {
return this.version;
}
}
三、踩坑