Skip to content

Commit

Permalink
@value 字面量 SpEL & 动态刷新实例
Browse files Browse the repository at this point in the history
  • Loading branch information
liuyueyi committed Jun 7, 2021
1 parent 8794081 commit 7ece3ef
Show file tree
Hide file tree
Showing 10 changed files with 297 additions and 2 deletions.
7 changes: 6 additions & 1 deletion spring-boot/002-properties-value/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,10 @@

<artifactId>002-properties-value</artifactId>


<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
package com.git.hui.boot.properties.value;

import com.git.hui.boot.properties.value.config.ConfigProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* @author yihui
* @date 2021/6/2
*/
@RestController
@SpringBootApplication
public class Application {
@Autowired
private ConfigProperties configProperties;

@GetMapping("show")
public String showProperties() {
return configProperties.toJsonStr();
}

public static void main(String[] args) {
SpringApplication.run(Application.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.git.hui.boot.properties.value.config;

import com.alibaba.fastjson.JSONObject;
import com.git.hui.boot.properties.value.model.Jwt;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
Expand All @@ -14,6 +16,7 @@
* @author yihui
* @date 2021/6/2
*/
@Data
@Component
public class ConfigProperties {

Expand Down Expand Up @@ -47,6 +50,24 @@ public class ConfigProperties {
@Value("${auth.jwt.tt}")
private Jwt tt;

@Value("1+2")
private String a;

@Value("#{1+2}")
private String b;

/**
* 配置注入 + 前缀
*/
@Value("prefix_${auth.jwt.token}")
private String c;

/**
* spel表达式
*/
@Value("#{randomService.randUid()}")
private String rid;

@Autowired
private Environment environment;

Expand All @@ -55,4 +76,8 @@ public void init() {
System.out.println("token: " + token + "\nexpire:" + expire + "\nno:" + no + "\nwhiteList:" + whiteList +
"\nblackList:" + Arrays.asList(blackList) + "\ntt:" + tt);
}

public String toJsonStr() {
return JSONObject.toJSONString(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package com.git.hui.boot.properties.value.config.dynamic;

import com.alibaba.fastjson.JSONObject;
import javafx.util.Pair;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.PropertyPlaceholderHelper;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
* 配置的动态刷新
*
* @author yihui
* @date 2021/6/7
*/
@Component
public class AnoValueRefreshPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements EnvironmentAware {
private Map<String, FieldPair> mapper = new HashMap<>();
private Environment environment;

@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
processMetaValue(bean);
return super.postProcessAfterInstantiation(bean, beanName);
}

/**
* 扫描bean的所有属性,并获取@MetaVal修饰的属性
*
* @param bean
*/
private void processMetaValue(Object bean) {
Class clz = bean.getClass();
if (!clz.isAnnotationPresent(RefreshValue.class)) {
return;
}

try {
for (Field field : clz.getDeclaredFields()) {
if (field.isAnnotationPresent(Value.class)) {
Value val = field.getAnnotation(Value.class);
Pair<String, String> pair = pickPropertyKey(val.value());
mapper.put(pair.getKey(), new FieldPair(bean, field, val, pair.getValue()));
}
}
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}

/**
* 实现一个基础的配置文件参数动态刷新支持
*
* @param value
* @return
*/
private Pair<String, String> pickPropertyKey(String value) {
int start = value.indexOf("$") + 2;
int middle = value.indexOf(":", start);
int end = value.indexOf("}", start);

String key;
String defaultValue;
if (middle > 0 && middle < end) {
// 包含默认值
key = value.substring(start, middle);
defaultValue = value.substring(middle + 1, end);
} else {
// 不包含默认值
key = value.substring(start, end);
defaultValue = null;
}
return new Pair<>(key, defaultValue);
}

@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public static class FieldPair {
private static PropertyPlaceholderHelper propertyPlaceholderHelper = new PropertyPlaceholderHelper("${", "}");

Object bean;
Field field;
Value value;
String defaultVal;

public void updateValue(Environment environment) throws IllegalAccessException {
boolean access = field.isAccessible();
if (!access) {
field.setAccessible(true);
}

String val = value.value();
if (defaultVal != null) {
val = value.value().replace(":" + defaultVal, "");
}

String updateVal = propertyPlaceholderHelper.replacePlaceholders(val, environment::getProperty);
field.set(bean, JSONObject.parseObject(updateVal, field.getType()));
field.setAccessible(access);
}
}

public static class ConfigUpdateEvent extends ApplicationEvent {
String key;

/**
* Create a new {@code ApplicationEvent}.
*
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public ConfigUpdateEvent(Object source, String key) {
super(source);
this.key = key;
}
}

@EventListener
public void updateConfig(ConfigUpdateEvent configUpdateEvent) throws IllegalAccessException {
FieldPair pair = mapper.get(configUpdateEvent.key);
if (pair != null) {
pair.updateValue(environment);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.git.hui.boot.properties.value.config.dynamic;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
* @author yihui
* @date 2021/6/7
*/
@RestController
public class DynamicRest {
@Autowired
ApplicationContext applicationContext;
@Autowired
ConfigurableEnvironment environment;
@Autowired
RefreshConfigProperties refreshConfigProperties;

@GetMapping(path = "dynamic/update")
public RefreshConfigProperties updateEnvironment(String key, String value) {
String name = "applicationConfig: [classpath:/application-dynamic.yml]";
MapPropertySource propertySource = (MapPropertySource) environment.getPropertySources().get(name);
Map<String, Object> source = propertySource.getSource();
Map<String, Object> map = new HashMap<>(source.size());
map.putAll(source);
map.put(key, value);
environment.getPropertySources().replace(name, new MapPropertySource(name, map));

applicationContext.publishEvent(new AnoValueRefreshPostProcessor.ConfigUpdateEvent(this, key));
return refreshConfigProperties;
}

@GetMapping(path = "dynamic/show")
public RefreshConfigProperties show() {
return refreshConfigProperties;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.git.hui.boot.properties.value.config.dynamic;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
* 演示动态配置刷新
*
* @author yihui
* @date 2021/6/7
*/
@Data
@Component
@RefreshValue
public class RefreshConfigProperties {

@Value("${xhh.dynamic.name}")
private String name;

@Value("${xhh.dynamic.age:18}")
private Integer age;

@Value("${xhh.dynamic.other:test}")
private String other;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.git.hui.boot.properties.value.config.dynamic;

import java.lang.annotation.*;

/**
* @author yihui
* @date 2021/6/7
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RefreshValue {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.git.hui.boot.properties.value.service;

import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;

/**
* @author yihui
* @date 2021/6/7
*/
@Service
public class RandomService {
private AtomicInteger cnt = new AtomicInteger(1);

public String randUid() {
return cnt.getAndAdd(1) + "_" + UUID.randomUUID().toString();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
xhh:
dynamic:
name: 一灰灰blog
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ auth:
- 100
- 200
- 300
tt: token:tt_token; expire:1622616888888
tt: token:tt_token; expire:1622616888888
spring:
profiles:
active: dynamic

0 comments on commit 7ece3ef

Please sign in to comment.