防止开发者不关DB的策略及实践

笔者的工作内容主要是研发框架,即提供了一整套平台框架(登陆模块、菜单模块、组织机构模块、权限模块、流程、表单、润乾。。。),其中业务程序开发模块供业务开发者进行二次开发使用。通常,业务开发者只需要在引导页面输入一些表名、字段名等信息,就可以完整地生成一个程序页面(列表、维护、树型页面等)。但是,业务需求总是千差万别的,平台框架不可能满足所有现场的特殊需求,这时候,就需要业务开发者在我们限定的方案内进行二次开发。

举个栗子,下图是平台框架中自动生成的新建维护页面;比如现在有个特殊需求,在打开新建维护页面的时候,根据登陆人的信息,自动给【工程项目】赋值,这就需要业务开发者进行二次开发了。

肯定是不能改平台框架的代码了,我们提供了修改业务细节的方法。他们可以在该程序对应的Java代码beforeInit()方法中,给【工程项目】赋值,如下图。 

 那么,问题来了,如果要在上图的beforeInit()方法中使用DB连接怎么办?

可以看到 业务类CMCCCC00101.java继承了M.java,而M的除Object.java的顶级父类是Business.java,我们给Business.java添加了属性db,在它构造方法里给db赋值,然后Business.java的子类可以随意使用这些创建好的db。

我们并不知道开发者何时结束使用这个db,所以不能主动去关闭db。那就需要一种特别的方式去关闭由业务类的顶级父类Business.java所创建的db。方法是,将Business.java构造时创建的db加入到本地线程中,当请求结束的时候截取并清空本地线程中的db对象。

//在Business构造处,将创建好的DB加入数据库线程本地map中
public class DatabaseHolder {

    /**
     * 数据库线程本地map
     */
    public static final ThreadLocal<List<Database>> dbThreadLocalMap = new ThreadLocal<>();

    /**
     * 将db存入数据库本地线程map中
     * @author chengmeng
     */
    public static void addDB(Database db) {
        if(dbThreadLocalMap.get() == null) {
            dbThreadLocalMap.set(new ArrayList<Database>());
        }
        dbThreadLocalMap.get().add(db);
    }
}
@Aspect
@Component
public class DbCleanAspect {
    /**
     * 在ResponseDataHandler中截获响应,并触发清理本地线程中的未关闭连接的db
     * @author chengmeng
     */
    public static void cleanDbAfterRequest() {
        try {
            List<Database> list = DatabaseHolder.dbThreadLocalMap.get();
            if(CollectionUtils.isEmpty(list)) {
                return;
            }
            for(Database db : list) {
                if(db != null) {
                    db.cleanup();
                }
            }
            DatabaseHolder.dbThreadLocalMap.set(new ArrayList<>());
        } catch (Exception e) {
            Log.error(">>>> 切面程序清理数据库连接时发生异常:", e);
        }
    }
}

上面是我们提供给业务程序类的db,使他们不需要关注db的创建与销毁从而专注功能的开发。

但除了业务程序类,还有很多其它非标准程序类,这时怎么规范他们用db呢?采用拉姆达表达式:

//拉姆达表达式,当TODO操作完毕,db会自动释放连接
Object obj = DataBase.execute(db->{
    //TODO
});

 不仅如此,我们还封闭了他们通过DataBase类创建实例的渠道,我们将DataBase.getInstance()方法修改为私有,并在其中加入了调用方的路径判断,非白名单内的Java类路径调用getInstance()时会直接报错。

public static DataBase getInstance() throws Exception{
    if( 调用方法 in 白名单 ){
        return DB对象;
    }else{
        throw new Exception("此方法仅供平台使用,业务程序请勿调用!");
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_38316944/article/details/114640939