Skip to content

Commit

Permalink
feat(*): Spring EL support extract environment property with `#env['p…
Browse files Browse the repository at this point in the history
…rop']` or `@env.get('prop')`.
  • Loading branch information
yizzuide committed Apr 21, 2020
1 parent c93e9dc commit fa61dca
Show file tree
Hide file tree
Showing 12 changed files with 138 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*
* @author yizzuide
* @since 3.0.0
* @version 3.0.8
* @version 3.1.0
* Create at 2020/04/09 14:03
*/
@Slf4j
Expand Down Expand Up @@ -67,21 +67,17 @@ public static void activeDeadJobs() {
}
int count = 0;
while (!CollectionUtils.isEmpty(delayJobs)) {
log.info("Ice 正在恢复延迟作业Jobs {}", delayJobs.stream().map(DelayJob::getJodId).collect(Collectors.toList()));
log.info("Ice 正在Dead Queue恢复延迟作业Jobs {}", delayJobs.stream().map(DelayJob::getJodId).collect(Collectors.toList()));
delayBucket.add(delayJobs);
count += delayJobs.size();
// 如果恢复完成,退出
if (delayJobs.size() != retrieveCount) {
break;
}
try {
Thread.sleep(retrieveCount);
} catch (InterruptedException ignore) {
}
delayJobs = deadQueue.pop(retrieveCount);
}
if (count > 0) {
log.info("Ice 恢复Dead Queue Job到延迟队列总个数:{}", count);
log.info("Ice 完成从Dead Queue恢复Job到延迟队列总个数:{}", count);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.github.yizzuide.milkomeda.universe.context.ApplicationContextHolder;
import com.github.yizzuide.milkomeda.util.JSONUtil;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.EventListener;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;
Expand All @@ -19,7 +19,7 @@
* @since 3.0.8
* Create at 2020/04/17 00:51
*/
public class RedisDeadQueue implements DeadQueue, InitializingBean, ApplicationListener<IceInstanceChangeEvent> {
public class RedisDeadQueue implements DeadQueue, InitializingBean {

private StringRedisTemplate redisTemplate;

Expand Down Expand Up @@ -74,7 +74,7 @@ public void afterPropertiesSet() throws Exception {
redisTemplate = ApplicationContextHolder.get().getBean(StringRedisTemplate.class);
}

@Override
@EventListener
public void onApplicationEvent(IceInstanceChangeEvent event) {
String instanceName = event.getSource().toString();
this.deadQueueKey = "ice:dead_queue:" + instanceName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*
* @author yizzuide
* @since 1.5.0
* @version 3.1.0
* Create at 2019/05/30 22:22
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
Expand All @@ -26,9 +27,7 @@
String name() default "";

/**
* 唯一标识键,用于组成redis的key
* 1. 支持Spring EL表达式,如:#id
* 2. 支持HTTP Header获取表达式(内建支持),如::token
* 唯一标识键,用于组成redis的key,支持Spring EL表达式,如:#id、#request.getHeader('token')、#env['title']、@env.get('spring.application.name')
* @return String
*/
String key() default "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*
* @author yizzuide
* @since 1.5.0
* @version 3.1.0
* Create at 2019/05/30 22:29
*/
@Slf4j
Expand All @@ -42,7 +43,8 @@ public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
long expire = limit.expire();
Limiter limiter = !StringUtils.isEmpty(beanName) ? ApplicationContextHolder.get().getBean(beanName, Limiter.class)
: ApplicationContextHolder.get().getBean(limit.limiterBeanClass());
return limiter.limit(prefix + ":" + key, expire, (particle ->
String decorateKey = StringUtils.isEmpty(prefix) ? key : prefix + ":" + key;
return limiter.limit(decorateKey, expire, (particle ->
joinPoint.proceed(injectParam(joinPoint, particle, limit, true))));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.github.yizzuide.milkomeda.universe.context.ApplicationContextHolder;
import com.github.yizzuide.milkomeda.universe.context.WebContext;
import com.github.yizzuide.milkomeda.universe.env.Environment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
Expand All @@ -16,16 +17,24 @@
*
* @author yizzuide
* @since 2.0.0
* @version 3.0.1
* @version 3.1.0
* Create at 2019/12/13 19:09
*/
@Configuration
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class MilkomedaContextConfig {

@Bean
public Environment env() {
return new Environment();
}

@Bean
@ConditionalOnMissingBean
public ApplicationContextHolder applicationContextHolder() {
return new ApplicationContextHolder();
public ApplicationContextHolder applicationContextHolder(Environment env) {
ApplicationContextHolder applicationContextHolder = new ApplicationContextHolder();
ApplicationContextHolder.setEnvironment(env);
return applicationContextHolder;
}

@Autowired
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
package com.github.yizzuide.milkomeda.universe.context;

import com.github.yizzuide.milkomeda.universe.el.ELContext;
import com.github.yizzuide.milkomeda.universe.env.Environment;
import lombok.Getter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;

/**
* ApplicationContextHolder
*
* @author yizzuide
* @since 0.2.1
* @version 2.0.0
* @version 3.1.0
* Create at 2019/04/12 11:04
*/
public class ApplicationContextHolder implements ApplicationContextAware {

private static ApplicationContextHolder INSTANCE;

private static Environment environment;

@Getter
private ApplicationContext applicationContext;

private static ApplicationContextHolder INSTANCE;

public ApplicationContextHolder() {
INSTANCE = this;
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
ELContext.setApplicationContext(applicationContext);
if (applicationContext instanceof ConfigurableApplicationContext) {
ApplicationContextHolder.environment.setConfigurableEnvironment(((ConfigurableApplicationContext) applicationContext).getEnvironment());
}
}

/**
* 获取Spring IOC上下文
* @return ApplicationContext
Expand All @@ -31,9 +46,15 @@ public static ApplicationContext get() {
return INSTANCE.getApplicationContext();
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
ELContext.setApplicationContext(applicationContext);
public static void setEnvironment(Environment environment) {
ApplicationContextHolder.environment = environment;
}

/**
* 获取Spring环境变量
* @return Environment
*/
public static Environment getEnvironment() {
return environment;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.github.yizzuide.milkomeda.universe.el;

import com.github.yizzuide.milkomeda.universe.context.ApplicationContextHolder;
import com.github.yizzuide.milkomeda.universe.context.WebContext;
import com.github.yizzuide.milkomeda.universe.env.Environment;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.expression.AnnotatedElementKey;
import org.springframework.context.expression.CachedExpressionEvaluator;
Expand All @@ -9,6 +12,7 @@
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.Map;
Expand All @@ -20,6 +24,7 @@
*
* @author yizzuide
* @since 1.5.0
* @version 3.1.0
* Create at 2019/05/30 22:24
*/
public class ExpressionEvaluator<T> extends CachedExpressionEvaluator {
Expand Down Expand Up @@ -50,7 +55,16 @@ public StandardEvaluationContext createEvaluationContext(Object object, Class<?>
// 创建基于方法的执行上下文
MethodBasedEvaluationContext evaluationContext = new MethodBasedEvaluationContext(root, targetMethod, args, this.paramNameDiscoverer);
// 添加变量引用
evaluationContext.setVariable("target", root.getObject());
Environment env = ApplicationContextHolder.getEnvironment();
if (env != null) {
evaluationContext.setVariable("env", env.getProperties());
}
evaluationContext.setVariable("target", object);
ServletRequestAttributes requestAttributes = WebContext.getRequestAttributes();
if (requestAttributes != null) {
evaluationContext.setVariable("request", requestAttributes.getRequest());
evaluationContext.setVariable("reqParams", requestAttributes.getRequest().getParameterMap());
}
return evaluationContext;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.github.yizzuide.milkomeda.universe.env;

import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.util.Properties;

/**
* Environment
*
* @author yizzuide
* @since 3.1.0
* Create at 2020/04/21 10:44
*/
public class Environment {

// Spring可配置环境变量
private ConfigurableEnvironment configurableEnvironment;

// 附加配置源
private Properties properties = new Properties();

public void setConfigurableEnvironment(ConfigurableEnvironment configurableEnvironment) {
this.configurableEnvironment = configurableEnvironment;
MutablePropertySources propertySources = configurableEnvironment.getPropertySources();
propertySources.addLast(new PropertiesPropertySource("milkomedaProperties", properties));
}

/**
* 添加Spring环境变量
* @param key 键
* @param value 值
*/
public void put(String key, String value) {
this.properties.setProperty(key, value);
}

/**
* 获取Spring环境变量
* @param key 键
* @return 如果key不存在,返回null
*/
public @Nullable String get(String key) {
if (this.configurableEnvironment == null) {
return null;
}
return this.configurableEnvironment.getProperty(key);
}

/**
* 获取配置源
* @return Properties
*/
public @NonNull Properties getProperties() {
return this.properties;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.yizzuide.milkomeda.demo;

import com.github.yizzuide.milkomeda.ice.IceHolder;
import com.github.yizzuide.milkomeda.universe.context.ApplicationContextHolder;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
Expand All @@ -15,7 +16,12 @@
public class MilkomedaApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// 设置延迟队列实例名
IceHolder.setInstanceName("product");
// 激活Dead queue里的job(重试超过次数的job)
IceHolder.activeDeadJobs();

// 调用环境变量,给Spring EL表达 #env 提供数据源
ApplicationContextHolder.getEnvironment().put("product", "milkomeda");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.github.yizzuide.milkomeda.universe.metadata.BeanIds;
import com.github.yizzuide.milkomeda.universe.parser.url.URLPlaceholderResolver;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

Expand All @@ -22,9 +21,9 @@ public class CometConfig {
public URLPlaceholderResolver urlPlaceholderResolver() {
return (placeholder, request) -> {
if ("uid".equals(placeholder)) {
String token = request.getHeader("token");
// 假设以前四位为用户id
return StringUtils.isBlank(token) ? null : token.substring(0, 4);
// 一般是从token中解析出uid
// String token = request.getHeader("token");
return 123;
}
return null;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ public ResponseEntity<String> check2(String token, Particle particle/*这个状
}

@RequestMapping("check3")
// 注解的方式限制一次请求的重复调用(:用于取HTTP请求header里的值
// 注解的方式限制一次请求的重复调用(#env获取自定义环境变量,#request获取请求对象
// 注意:由于配置了限制器链,就有了两个去重限制器,由于框架内部根据类型查找,这里需要通过limiterBeanName指定
@Limit(name = "user:check", key = ":Token", expire = 60L, limiterBeanName = "idempotentLimiter")
@Limit(name = "user:check", key = "#env['product'] + #request.getHeader('token')", expire = 60L, limiterBeanName = "idempotentLimiter")
public ResponseEntity<String> check3(Particle particle/*这个状态值自动注入*/) throws Throwable {
// 判断是否被限制
log.info("limited: {}", particle.isLimited());
Expand Down
2 changes: 2 additions & 0 deletions MilkomedaDemo/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ server:
timeout: 120m

spring:
application:
name: milkomeda
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/milkomeda?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useSSL=false&rewriteBatchedStatements=true&allowMultiQueries=true
Expand Down

0 comments on commit fa61dca

Please sign in to comment.