写点什么

案例研究之聊聊 QLExpress 源码 (三)

发布于: 2021 年 01 月 11 日
案例研究之聊聊 QLExpress 源码 (三)

目前源码分析的过程中,缺少非常详细的场景,只是简单的通读了源码,并对于整个源码有了大体模块和功能了解。如果需要具体的分析,可以有具体场景,因为看源码确实比较耗时间。


三、配置模块(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
用户头像

小胜靠智,大胜靠德 2019.06.27 加入

历经创业、京东、腾讯、滴滴公司,希望能够有些东西一起分享。公众号:小诚信驿站,微信/CSDN搜索:wolf_love666

评论

发布
暂无评论
案例研究之聊聊 QLExpress 源码 (三)