-
2022-02-24 11:26:29
Prometheus 热加载配置
-
先使用下面的命令访问prometheus查看是否正常
curl -X POST http://localhost:9090/-/reload
-
请求接口后返回
Lifecycle API is not enabled
. 就是没有开启热更新配置 ,需在启动命令增加参数:--web.enable-lifecycle
-
具体启动命令
./prometheus --web.enable-lifecycle --config.file=prometheus.yml
使用容器部署prometheus中,可以在运行参数中加入
--web.enable-lifecycle
更多相关内容 -
-
使用Go语言实现配置文件热加载功能
2021-01-03 05:04:21说到配置文件热加载,这个功能在很多框架中都提供了,如beego,实现的效果就是当你修改文件后,会把你修改后的配置重新加载到配置文件中,而不用重启程序,这个功能在日常中还是非常实用的,毕竟很多时候,线上的... -
配置文件热加载
2013-03-23 15:01:59应用程序在启动的时候,可能会读取应用所需要的配置文件,如果说配置文件的内容不是一成不变的,在需要...假如,这个配置文件是我们的应用完全可控的,我们可以在不重启服务器的情况下,把新的配置文件数据加载起来。 -
配置文件热加载的go语言实现
2018-07-25 10:18:07通常我们更新应用程序的配置文件,都需要手动重启程序或手动重新加载配置...今天我们就用go实现配置文件热加载的小功能,以后更新配置再也不用手动重启了... 1.基本思路 通常应用程序启动的流程:加载配置,然后...通常我们更新应用程序的配置文件,都需要手动重启程序或手动重新加载配置。假设一组服务部署在10台机器上,你需要借助批量运维工具执行重启命令,而且10台同时重启可能还会造成服务短暂不可用。要是更新配置后,服务自动刷新配置多好...今天我们就用go实现配置文件热加载的小功能,以后更新配置再也不用手动重启了...
1.基本思路
通常应用程序启动的流程:加载配置,然后run()。我们怎么做到热加载呢?我们的思路是这样的:
【1】在加载配置文件之后,启动一个线程。
【2】该线程定时监听这个配置文件是否有改动。
【3】如果配置文件有变动,就重新加载一下。
【4】重新加载之后通知需要使用这些配置的应用程序(进程或线程),实际上就是刷新内存中配置。
2.加载配置
首先我们要实现加载配置功能。假设配置文件是k=v格式的,如下:
那我们得写一个解析配置的包了...让我们一起面向对象:
filename string 配置文件名称
data map[string]string 将配置文件中的k/v解析存放到map中
lastModifyTime int64 记录配置文件上一次更改时间
rwLock sync.RWMutex 读写锁,处理这样一种竞争情况:更新这个结构体时其他线程正在读取改结构体中的内容,后续用到的时候会讲
notifyList []Notifyer 存放所有观察者,此处我们用到了观察者模式,也就是需要用到这个配置的对象,我们就把它加到这个切片。当配置更新之后,通知切片中的对象配置更新了。
接下来我们可以给这个结构体添加一些方法了:
2.1 构造函数
1 func NewConfig(file string)(conf *Config, err error){ 2 conf = &Config{ 3 filename: file, 4 data: make(map[string]string, 1024), 5 } 6 7 m, err := conf.parse() 8 if err != nil { 9 fmt.Printf("parse conf error:%v\n", err) 10 return 11 } 12 13 // 将解析配置文件后的数据更新到结构体的map中,写锁 14 conf.rwLock.Lock() 15 conf.data = m 16 conf.rwLock.Unlock() 17 18 // 启一个后台线程去检测配置文件是否更改 19 go conf.reload() 20 return 21}
构造函数做了三件事:
【1】初始化Config
【2】调用parse()函数,解析配置文件,并把解析后的map更新到Config
【3】启动一个线程,准确说是启动一个goroutine,即reload()
注意此处更新map时加了写锁了,目的在于不影响拥有读锁的线程读取数据。
2.2 parse()
解析函数比较简单,主要是读取配置文件,一行行解析,数据存放在map中。
1 func (c *Config) parse() (m map[string]string, err error) { 2 // 如果在parse()中定义一个map,这样就是一个新的map不用加锁 3 m = make(map[string]string, 1024) 4 5 f, err := os.Open(c.filename) 6 if err != nil { 7 return 8 } 9 defer f.Close() 10 11 reader := bufio.NewReader(f) 12 // 声明一个变量存放读取行数 13 var lineNo int 14 for { 15 line, errRet := reader.ReadString('\n') 16 if errRet == io.EOF { 17 // 这里有一个坑,最后一行如果不是\n结尾会漏读 18 lineParse(&lineNo, &line, &m) 19 break 20 } 21 if errRet != nil { 22 err = errRet 23 return 24 } 25 26 lineParse(&lineNo, &line, &m) 27 } 28 29 return 30} 31 32 func lineParse(lineNo *int, line *string, m *map[string]string) { 33 *lineNo++ 34 35 l := strings.TrimSpace(*line) 36 // 如果空行 或者 是注释 跳过 37 if len(l) == 0 || l[0] =='\n' || l[0]=='#' || l[0]==';' { 38 return 39 } 40 41 itemSlice := strings.Split(l, "=") 42 // = 43 if len(itemSlice) == 0 { 44 fmt.Printf("invalid config, line:%d", lineNo) 45 return 46 } 47 48 key := strings.TrimSpace(itemSlice[0]) 49 if len(key) == 0 { 50 fmt.Printf("invalid config, line:%d", lineNo) 51 return 52 } 53 if len(key) == 1 { 54 (*m)[key] = "" 55 return 56 } 57 58 value := strings.TrimSpace(itemSlice[1]) 59 (*m)[key] = value 60 61 return 62}
这里我写了两个函数。lineParse()是解析每一行配置的。parse()就是解析的主函数,在parse()中我调用了两次lineParse()。原因是在使用bufio按行读取配置文件的时候,有时候会出现这样的情况:有的人在写配置文件的时候,最后一行没有换行,也就是没有‘\n’,然后我们就直接读到io.EOF了,这时候如果直接break就会导致最后一行丢失。所以这种情况下我们应该在break之前调用lineParse()把最后一行处理了。
3 封装接口
上面我们已经实现了读取配置文件,并放到一个Config示例中,我们需要为这个Config封装一些接口,方便用户通过接口访问Config的内容。这步比较简单:
1func (c *Config) GetInt(key string)(value int, err error){ 2 c.rwLock.RLock() 3 defer c.rwLock.RUnlock() 4 5 str, ok := c.data[key] 6 if !ok { 7 err = fmt.Errorf("key [%s] not found", key) 8 } 9 value, err = strconv.Atoi(str) 10 return 11} 12 13func (c *Config) GetIntDefault(key string, defaultInt int)(value int){ 14 c.rwLock.RLock() 15 defer c.rwLock.RUnlock() 16 17 str, ok := c.data[key] 18 if !ok { 19 value = defaultInt 20 return 21 } 22 value, err := strconv.Atoi(str) 23 if err != nil { 24 value = defaultInt 25 } 26 return 27} 28 29func (c *Config) GetString(key string)(value string, err error){ 30 c.rwLock.RLock() 31 defer c.rwLock.RUnlock() 32 33 value, ok := c.data[key] 34 if !ok { 35 err = fmt.Errorf("key [%s] not found", key) 36 } 37 return 38} 39 40func (c *Config) GetIStringDefault(key string, defaultStr string)(value string){ 41 c.rwLock.RLock() 42 defer c.rwLock.RUnlock() 43 44 value, ok := c.data[key] 45 if !ok { 46 value = defaultStr 47 return 48 } 49 return 50}
如上,一共封装了4个接口:
GetInt(key string)(value int, err error) 通过key获取value,并将value转成int类型
GetIntDefault(key string, defaultInt int)(value int) 通过key获取value,并将value转成int类型;如果获取失败,使用默认值
GetString(key string)(value string, err error) 通过key获取value,默认value为string类型
GetIStringDefault(key string, defaultStr string)(value string) 通过key获取value,默认value为string类型;如果获取失败,使用默认值
注意:四个接口都用了读锁
4 reload()
上面我们已经实现了解析,加载配置文件,并为Config封装了比较友好的接口。接下来,我们可以仔细看一下我们之前启动的goroutine了,即reload()方法。
1func (c *Config) reload(){ 2 // 定时器 3 ticker := time.NewTicker(time.Second * 5) 4 for _ = range ticker.C { 5 // 打开文件 6 // 为什么使用匿名函数? 当匿名函数退出时可用defer去关闭文件 7 // 如果不用匿名函数,在循环中不好关闭文件,一不小心就内存泄露 8 func (){ 9 f, err := os.Open(c.filename) 10 if err != nil { 11 fmt.Printf("open file error:%s\n", err) 12 return 13 } 14 defer f.Close() 15 16 fileInfo, err := f.Stat() 17 if err != nil { 18 fmt.Printf("stat file error:%s\n", err) 19 return 20 } 21 // 或取当前文件修改时间 22 curModifyTime := fileInfo.ModTime().Unix() 23 if curModifyTime > c.lastModifyTime { 24 // 重新解析时,要考虑应用程序正在读取这个配置因此应该加锁 25 m, err := c.parse() 26 if err != nil { 27 fmt.Printf("parse config error:%v\n", err) 28 return 29 } 30 31 c.rwLock.Lock() 32 c.data = m 33 c.rwLock.Unlock() 34 35 c.lastModifyTime = curModifyTime 36 37 // 配置更新通知所有观察者 38 for _, n := range c.notifyList { 39 n.Callback(c) 40 } 41 } 42 }() 43 } 44}
reload()函数中做了这几件事:
【1】用time.NewTicker每隔5秒去检查一下配置文件
【2】如果配置文件的修改时间比上一次修改时间大,我们认为配置文件更新了。那么我们调用parse()解析配置文件,并更新conf实例中的数据。并且更新配置文件的修改时间。
【3】通知所有观察者,即通知所有使用配置文件的程序、进程或实例,配置更新了。
5 观察者模式
我们反复提到观察者,反复提到通知所有观察者配置文件更新。那么我们就要实现这个观察者:
1type Notifyer interface { 2 Callback(*Config) 3}
定义这样一个Notifyer接口,只要实现了Callback方法的对象,就都实现了这个Notifyer接口。实现了这个接口的对象,如果都需要被通知配置文件更新,那这些对象都可以加入到前面定义的notifyList []Notifyer这个切片中,等待被通知配置文件更新。
好了,此处我们是否少写了添加观察者的方法呢??是的,马上写:
1// 添加观察者 2func (c *Config) AddObserver(n Notifyer) { 3 c.notifyList = append(c.notifyList, n) 4}
6 测试
经过上面一番折腾,咱们的热加载就快实现了,我们来测一测:
通常我们在应用程序中怎么使用配置文件?【1】加载配置文件,加载之后数据放在一个全局结构体中 【2】run()
也就是run()中我们要使用全局的结构体,但是这个全局结构体会因为配置文件的更改被更新。此时又存在需要加锁的情况了。我擦,是不是很麻烦。。不用担心,我们用一个原子操作搞定。
假设我们的配置文件中存放的是hostname/port/kafkaAddr/kafkaPort这几个字段。。
1type AppConfig struct { 2 hostname string 3 port int 4 kafkaAddr string 5 kafkaPort int 6}
接下来我们要用原子操作保证数据一致性了:
1// reload()协程写 和 for循环的读,都是对Appconfig对象,因此有读写冲突 2type AppConfigMgr struct { 3 config atomic.Value 4} 5 6// 初始化结构体 7var appConfigMgr = &AppConfigMgr{}
atomic.Value能保证存放数据和读取出数据不会有冲突。所以当我们更新数据时存放到atomic.Value中,我们使用数据从atomic.Value加载出来,这样不用加锁就能保证数据的一致性了。完美~~
我们需要AppConfigMgr实现Callback方法,即实现Notifyer接口,这样才能被通知配置更新:
1func (a *AppConfigMgr)Callback(conf *reconf.Config) { 2 appConfig := &AppConfig{} 3 hostname, err := conf.GetString("hostname") 4 if err != nil { 5 fmt.Printf("get hostname err: %v\n", err) 6 return 7 } 8 appConfig.hostname = hostname 9 10 kafkaPort, err := conf.GetInt("kafkaPort") 11 if err != nil { 12 fmt.Printf("get kafkaPort err: %v\n", err) 13 return 14 } 15 appConfig.kafkaPort = kafkaPort 16 17 appConfigMgr.config.Store(appConfig) 18 19}
这个Callback实现功能是:当被通知配置更新时,马上读取更新的数据并存放到config atomic.Value 中。
好了,我们要写主函数了。
1 func initConfig(file string) { 2 // [1] 打开配置文件 3 conf, err := reconf.NewConfig(file) 4 if err != nil { 5 fmt.Printf("read config file err: %v\n", err) 6 return 7 } 8 9 // 添加观察者 10 conf.AddObserver(appConfigMgr) 11 12 // [2]第一次读取配置文件 13 var appConfig AppConfig 14 appConfig.hostname, err = conf.GetString("hostname") 15 if err != nil { 16 fmt.Printf("get hostname err: %v\n", err) 17 return 18 } 19 fmt.Println("Hostname:", appConfig.hostname) 20 21 appConfig.kafkaPort, err = conf.GetInt("kafkaPort") 22 if err != nil { 23 fmt.Printf("get kafkaPort err: %v\n", err) 24 return 25 } 26 fmt.Println("kafkaPort:", appConfig.kafkaPort) 27 28 // [3] 把读取到的配置文件数据存储到atomic.Value 29 appConfigMgr.config.Store(&appConfig) 30 fmt.Println("first load sucess.") 31 32} 33 34func run(){ 35 for { 36 appConfig := appConfigMgr.config.Load().(*AppConfig) 37 38 fmt.Println("Hostname:", appConfig.hostname) 39 fmt.Println("kafkaPort:", appConfig.kafkaPort) 40 fmt.Printf("%v\n", "--------------------") 41 time.Sleep(5 * time.Second) 42 } 43} 44 45func main() { 46 confFile := "../parseConfig/test.cfg" 47 initConfig(confFile) 48 // 应用程序 很多配置已经不是存在文件中而是etcd 49 run() 50}
主函数中调用了initConfig()和run()。
initConfig()中:reconf.NewConfig(file)的时候我们已经第一次解析配置,并启动线程不断更新配置了。此外initConfig()还做了一些事,就是通过Config提供的接口,将配置文件中的数据读取到appConfig 中,然后再将appConfig 存储到 atomic.Value中。
run()就是模拟应用程序在运行过程中使用配置的过程:run()中获取配置信息就是从 atomic.Value加载出来,这样保证数据一致性。
编译运行,然后不断更改配置文件中kafkaAddr,测试结果如下:
这样配置文集热加载就实现了。
参考:
https://www.yuque.com/docs/share/c0783186-46d2-44e9-ac51-0ff10cbbfeeb
-
.net Core 配置文件热加载
2019-11-06 17:27:08在这里以读取一个json文件为例,演示配置文件的热加载,代码如下。我再目录下创建了一个appsettings.json文件,内容如下: { "loginName": "sysAdmin", "loginDB": { "server": "192.168.10.1", "uid": "sa", ...No.1 准备
在这里以读取一个json文件为例,演示配置文件的热加载,代码如下。我再目录下创建了一个appsettings.json文件,内容如下:
{ "loginName": "sysAdmin", "loginDB": { "server": "192.168.10.1", "uid": "sa", "pwd": "123456" }, "JAVA_HOME": "123" }
No.2 代码实现
IConfiguration configuration = new ConfigurationBuilder() .SetBasePath(Environment.CurrentDirectory) .AddJsonFile($"appsettings.json", optional: true, reloadOnChange: true) .Build(); while (true) { var loginname = configuration["loginDB:server"]; Console.WriteLine(loginname); System.Threading.Thread.Sleep(2000); }
No.3 结果
这里我会在运行的途中修改,配置文件内容,可以观察是否能够热加载
我在过程中修改了了值,结果发生了变化,热加载实验成功。 -
Springboot热加载和配置文件
2020-02-14 20:07:43热加载 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true<...热加载
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
添加依赖后,在ide里面重启应用,后续修改后马上可以生效
不被热部署的文件
1、/META-INF/maven, /META-INF/resources, /resources, /static, /public, or /templates
2、指定文件不进行热部署 spring.devtools.restart.exclude=static/,public/
3、手工触发重启 spring.devtools.restart.trigger-file=trigger.txt 改代码不重启,通过一个文本去控制
注意点:生产环境不要开启这个功能,如果用java -jar启动,springBoot是不会进行热部署的
xml、properties、json、yaml
配置文件参数的映射(属性和实体)
配置文件加载:
方法1:
- 1、Controller上面配置 @PropertySource({"classpath:xxxxx.properties"})
- 不加{}也可以
- 2、增加属性 @Value("${test.name}")
- private String name;
@Controller @PropertySource("classpath:application.properties") public class FileController { @RequestMapping("/api/v1/gopage") public Object getPage() { return "index"; } ///User/ligang/Desktop/person/springboot/src/main //images的路径 //注意 后面要加 / // // private static final String filepath="/Users/ligang/Desktop/"; //使用配置文件的方式解决硬编码问题 @Value("${web.file.path}") private String filepath; ......
application.properties
#文件上传路径配置 web.file.path=/Users/ligang/Desktop/
方法2:
实体类配置:
- 1、添加 @Component 注解;
- 2、使用 @PropertySource 注解指定配置文件位置; @PropertySource(value="classpath:application.properties")
- 3、使用 @ConfigurationProperties(prefix="test") 注解,设置相关属性;
- 4、必须 通过注入IOC对象Resource 进来 , 才能在类中使用获取的配置文件值。
- @Autowired
- private ServerSettings serverSettings;
常见问题: 1、配置文件注入失败,Could not resolve placeholder 解决:根据springboot启动流程,会有自动扫描包没有扫描到相关注解, 默认Spring框架实现会从声明@ComponentScan所在的类的package进行扫描,来自动注入, 因此启动类最好放在根路径下面,或者指定扫描包范围 spring-boot扫描启动类对应的目录和子目录 2、注入bean的方式,属性名称和配置文件里面的key一一对应,就不用加@Value 这个注解 如果不一样,就要加@value("${XXX}")
@Component @ConfigurationProperties @PropertySource(value="classpath:application.properties") public class ServerSetting { //名称 @Value("${test.name}") private String name; //域名地址 @Value("${test.domain}") private String domain; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDomain() { return domain; } public void setDomain(String domain) { this.domain = domain; } }
注入使用:
application.properties文件中的配置
#测试配置文件注入 在getController中返回显示 test.name=xijie test.domain=www.baidu.com
@Autowired private ServerSetting serverSetting; @GetMapping("/v1/test_properties") public Object testProperties(){ return serverSetting;
方法2:通过名称映射
在加入前缀的时候,就不需要加@Value("${test.name}")
@ConfigurationProperties(prefix="test")
private String name
相当于test.name 映射到配置文件中到属性
@Component @ConfigurationProperties(prefix="test") @PropertySource(value="classpath:application.properties") public class ServerSetting2 { //名称 private String name; //域名地址 private String domain; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDomain() { return domain; } public void setDomain(String domain) { this.domain = domain; } }
方法3:不加(prefix="xxx")
这样要一一对应(变量名称要与配置文件中到变量一致)
@Component @ConfigurationProperties @PropertySource(value="classpath:application.properties") public class ServerSetting3 { //名称 private String name; //域名地址 private String domain; .......
application.properties
name=name domain=domain
@Autowired private ServerSetting3 serverSetting3; @GetMapping("/v1/test_properties3") public Object testProperties3(){ return serverSetting3; }
-
Spring动态加载配置文件
2012-08-21 14:48:50本文档是很专业的 Spring动态加载配置文件,实现热部署方案。 -
spring boot加载第三方jar包的配置文件的方法
2020-08-29 04:01:14本篇文章主要介绍了spring boot加载第三方jar包的配置文件的方法,详细的介绍了spring boot jar包配置文件的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 -
prometheus热加载配置文件
2021-06-04 17:27:40prometheus启动后修改配置文件就需要再重启生效 可以通过以下方式 热加载 curl -X POST http://localhost:9090/-/reload 请求接口后返回 Lifecycle API is not enabled. 那么就是启动的时候没有开启热更新配置,需要... -
springcloud config实现配置热加载(简易版本)
2020-05-26 18:08:04前言: 准备:git搭建(新建gateway.properties) springboot:2.3.0 springcloud:Hoxton.SR4 ...启动文件开启配置中心,引入配置@EnableConfigServer启动即可 浏览器访问localhost:888... -
docker配置热加载(设置共享文件夹用来配合Docker的挂载)
2020-07-23 15:03:13当然也有解决的办法,那就是我们今天说的docker配置热加载 配置 首先在项目文件gunicorn.conf.py,中添加 reload = True 之后我们需要在Oracle VM VirtualBox内创建本地项目的共享文件,如下图 -
Hadoop配置文件加载
2020-09-16 14:13:551. hadoop使用org.apache.hadoop.conf.Configuration类来加载配置文件 2. 在使用Configuration conf = new Configuration()来创建conf对象时默认加载了哪些配置项呢? 看Configuration类的源码可以看到,默认是... -
MyBatis热加载配置所需要的文件
2019-06-15 20:48:45里面是用来配置mybatis热加载所需要的文件,除了myabtis-config.xml文件放在resource目录下,其他文件找一个目录放着 -
spring boot中配置mybatis热加载.zip
2018-01-31 15:50:50spring boot中配置mybatis xml资源文件热加载的方法以及相关文件 -
Web应用配置文件热加载
2013-03-23 15:09:02假如,这个配置文件是我们的应用完全可控的,我们可以在不重启服务器的情况下,把新的配置文件数据加载起来。 2.实现步骤 (1)应用提供一个Http接口,用来接收客户端新上传的文件数据。 (2)客户端调用http... -
spring boot中配置mybatis热加载相关文件
2018-01-31 16:08:10spring boot中配置mybatis xml资源文件热加载的方法以及相关文件 -
Haproxy热加载配置文件。
2020-05-12 15:30:42haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid) ...如果之前服务器未保存PID到文件 可以修改/var/run/haproxy.pid将进程ID放到文件里面,每个PID占一行即可。 -
热部署与热加载的配置
2018-05-10 08:49:58有两种方式热部署 和热加载: 1.热加载:在server.xml -> context 属性中 设置 reloadable="true"?1<Context docBase="xxx" path="/xxx" reloadable="true"... -
logstash K8S 下热加载配置文件
2021-03-17 16:08:38实际日志采集中,可能需要动态修改 gork的解析规则,来完成业务方面的需求,之前的chart部署文件默认是不会热加载相关的配置文件的,需要修改两个地方 1 修改配置文件的挂载方式 这里的目的是将 configMap 下的配置... -
prometheus 动态加载配置文件 热更新
2020-11-19 19:41:56现通过docker启动prometheus 的时候,需要动态加载新的target,启动的时候需要添加一个配置项 --web.enable-lifecycle 完整的启动命令: docker run -d -p 9090:9090 -v /opt/prometheus/prometheus.yml:/etc/... -
JAVA实现热加载配置文件(不重启服务器加载配置文件)
2020-03-20 17:38:37通过文件的当前时间和上次修改时间做比较,判断是否需要重新读取文件,从而实现不重启服务器获取修改后的参数 package com.shp.util; import java.io.File; import java.io.FileInputStream; import java.io.... -
详解go基于viper实现配置文件热更新及其源码分析
2020-12-17 11:33:53go第三方库 github.com/spf13/viper 实现了对配置文件的读取并注入到结构中,好用方便。 其中以 viperInstance := viper.New() // ...可实现配置的热更新,不用重启项目新配置即可生效(实现热加载的方法也不止这一 -
Go加载配置文件
2022-03-20 13:39:16) //InitConfig 初始化项目配置 func InitConfig(path string) map[string]string { config := make(map[string]string) f, err := os.Open(path) defer f.Close() if err != nil { panic(err) } r := bufio... -
webpack-config-reload:热加载 webpack 配置。修改 webpack 相关配置文件后,自动重启脚本命令,比如 dev-...
2021-05-05 07:48:11热加载 webpack 配置。修改 webpack 相关配置文件后,自动重启脚本命令,比如 dev-server,比较方便的是在调试 webpack 繁琐的配置时候,省去一遍遍地 Ctrl+c 和重复输入命令。 注意:只支持 webpack/webpack-dev-... -
flask 加载配置文件
2020-07-30 20:21:32优点:可以发挥继承的优势,复用多个配置文件 缺点:需放在工程中 class DefaultConfig(object): """默认配置""" SECRET_KEY = '123123' app = Flask(__name__) app.config.from_object(DefaultConfig) # 载入... -
Nginx跨域配置及配置文件加载过程讲解
2022-03-21 17:08:43在学习如何配置HTTPS之前,我们先来简单回顾下HTTPS的工作流程是怎么样的?它是如何进行加密保证安全的? HTTPS 工作流程 客户端(浏览器)访问https://www.baidu.com百度网站; 百度服务器返回HTTPS使用的... -
Spring boot 集成apollo达到配置的热加载
2020-06-11 00:34:29尤其是配置的热加载。让我们避免了多次生产发布的情况。他拥有可视化的配置界面(以Key-value的形势)。这篇文章的主要目的是看apollo是如何实现热更新的 使用 接入apollo pom文件中引入meven依赖 <... -
SpringBoot下配置MyBatis热加载
2019-06-15 21:02:06SpringBoot下配置MyBatis热加载(不影响MyBatisPlus)背景步骤 背景 在使用mybatis的时候,修改了xml资源之后不会马上生效,需要重启服务才行;MyBatisPlus前几个版本是带有这个功能的,但是最新版本的Mybatis则是... -
lu-cli:koa + react + ssr +热更新+按需加载实现同构,可在配置文件设置服务端渲染和客户端渲染
2021-02-03 17:40:16此脚手架基于koa + react + ssr + antd +热更新+按需加载实现同构,可在配置文件设置服务端渲染和客户端渲染。 线上演示: : 概要 因为项目需要,也是基于学习的目的所以重叠了一个React服务端渲染,城市表面也是有...