案例研究之聊聊 QLExpress 源码 (三)
发布于: 2021 年 01 月 11 日
目前源码分析的过程中,缺少非常详细的场景,只是简单的通读了源码,并对于整个源码有了大体模块和功能了解。如果需要具体的分析,可以有具体场景,因为看源码确实比较耗时间。
三、配置模块(config)
3.1、QLExpress 运行策略
预防空指针
比较空对象
禁止调用不安全的方法
3.1.1、UML 类图
3.1.2、QLExpressRunStrategy 源码
package com.ql.util.express.config;
import com.ql.util.express.exception.QLSecurityRiskException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* ExpressRunner设置全局生效的配置,直接使用静态方法控制
*/
public class QLExpressRunStrategy {
/**
* 预防空指针
*/
private static boolean avoidNullPointer = false;
/**
* 当空对象进行大小比较时,返回false, 例如 1 > null 和 null > 1都返回false
*/
private static boolean compareNullLessMoreAsFalse = false;
/**
* 是否比较空对象小于或者大于都返回false
* @return
*/
public static boolean isCompareNullLessMoreAsFalse() {
return compareNullLessMoreAsFalse;
}
public static void setCompareNullLessMoreAsFalse(boolean compareNullLessMoreAsFalse) {
QLExpressRunStrategy.compareNullLessMoreAsFalse = compareNullLessMoreAsFalse;
}
public static boolean isAvoidNullPointer() {
return avoidNullPointer;
}
public static void setAvoidNullPointer(boolean avoidNullPointer) {
QLExpressRunStrategy.avoidNullPointer = avoidNullPointer;
}
/**
* 禁止调用不安全的方法
*/
private static boolean forbiddenInvokeSecurityRiskMethods = false;
public static boolean isForbiddenInvokeSecurityRiskMethods() {
return forbiddenInvokeSecurityRiskMethods;
}
public static void setForbiddenInvokeSecurityRiskMethods(boolean forbiddenInvokeSecurityRiskMethods) {
QLExpressRunStrategy.forbiddenInvokeSecurityRiskMethods = forbiddenInvokeSecurityRiskMethods;
}
private static List<String>securityRiskMethods = new ArrayList<String>();
/**
* 静态代码块初始化,不允许外部调用系统方法
*/
static{
securityRiskMethods.add(System.class.getName()+"."+"exit");//系统退出
securityRiskMethods.add(Runtime.getRuntime().getClass().getName()+".exec");//运行脚本命令
}
public static void addSecurityRiskMethod(Class clazz, String methodName )
{
QLExpressRunStrategy.securityRiskMethods.add(clazz.getName()+"."+methodName);
}
public static void assertBlackMethod(Method m) throws QLSecurityRiskException {
if(forbiddenInvokeSecurityRiskMethods && m!=null){
if(securityRiskMethods.contains(m.getDeclaringClass().getName()+"."+m.getName())) {
throw new QLSecurityRiskException("使用QLExpress调用了不安全的系统方法:" + m.toString());
}
}
}
}
复制代码
3.2、QLExpressTimer 计时器
3.2.1、UML 类图
3.2.2、QLExpressTimer 源码
package com.ql.util.express.config;
import com.ql.util.express.exception.QLTimeOutException;
import java.sql.SQLTimeoutException;
/**
* QLExpress 计时器
* @author tianqiao@taobao.com
* @since 2019/6/17 4:12 PM
*/
public class QLExpressTimer {
/**
* 需要计时器,默认不需要
*/
private static ThreadLocal<Boolean> NEED_TIMER = new ThreadLocal<Boolean>(){
@Override
protected Boolean initialValue() {
return false;
}
};
/**
* 超时时间 s级
*/
private static ThreadLocal<Long> TIME_OUT_MILLIS = new ThreadLocal<Long>(){};
/**
* 开始时间
*/
private static ThreadLocal<Long> START_TIME = new ThreadLocal<Long>(){};
/**
* 结束时间
*/
private static ThreadLocal<Long> END_TIME = new ThreadLocal<Long>(){};
/**
* 设置计时器
* @param timeoutMillis 超时时间
*/
public static void setTimer(long timeoutMillis)
{
NEED_TIMER.set(true);
TIME_OUT_MILLIS.set(timeoutMillis);
}
/**
* 开始计时
*/
public static void startTimer()
{
if(NEED_TIMER.get()) {
long t = System.currentTimeMillis();
START_TIME.set(t);
END_TIME.set(t+TIME_OUT_MILLIS.get());
}
}
/**
* 断言是否超时
* @throws QLTimeOutException
*/
public static void assertTimeOut() throws QLTimeOutException {
if(NEED_TIMER.get() && System.currentTimeMillis()>END_TIME.get()){
throw new QLTimeOutException("运行QLExpress脚本的下一条指令将超过了限定时间:" + TIME_OUT_MILLIS.get() + "ms");
}
}
public static boolean hasExpired()
{
if(NEED_TIMER.get() && System.currentTimeMillis()>END_TIME.get()){
return true;
}
return false;
}
public static void reset()
{
if(NEED_TIMER.get()) {
START_TIME.remove();
END_TIME.remove();
NEED_TIMER.remove();
TIME_OUT_MILLIS.remove();
}
}
}
复制代码
3.3、小结
本模块属于配置模块,实际上更多的是附属追加的功能,比如禁止系统指令策略,计时器。之后如果有需要追加的扩展策略可以在这个模块下面补充。开源框架借鉴的思想如下:
对于系统运行或者已经定义的命令或者系统类禁止使用
securityRiskMethods.add(System.class.getName()+"."+"exit");//系统退出
securityRiskMethods.add(Runtime.getRuntime().getClass().getName()+".exec");//运行脚本命令
复制代码
计时器的线程安全 ThreadLocal 的使用
划线
评论
复制
发布于: 2021 年 01 月 11 日阅读数: 31
版权声明: 本文为 InfoQ 作者【小诚信驿站】的原创文章。
原文链接:【http://xie.infoq.cn/article/bdeda1dc059d74c630c4de57e】。文章转载请联系作者。
小诚信驿站
关注
小胜靠智,大胜靠德 2019.06.27 加入
历经创业、京东、腾讯、滴滴公司,希望能够有些东西一起分享。公众号:小诚信驿站,微信/CSDN搜索:wolf_love666
评论