本文转载自微信公众号《程序员语皮》,作者语皮。转载本文请联系程序员Yupi公众号。大家好,我是Yupi,今天给大家分享企业项目开发的重要知识——多环境。本文大纲:鱼皮-多环境技术大纲什么是多环境?先想一个问题。假设我们有一个有数百万用户使用的网站,网页文件部署在几台服务器上。那么现在我们要开发上线一个新的功能,应该怎么做呢?小阿巴哥问:写好代码后,直接更新服务器上的网页文件吗?我一巴掌:如果你的代码有bug,那不影响在线用户使用吗?小弟想了想:写完代码,本地测试运行没有问题之后,再上线发布?我:想法是好的,但是问题是,如果本地和线上运行的项目连接的是同一个数据库,那么在本地测试时往数据库中插入乱七八糟的假数据或者修改数据库表结构的时候,won它影响在线数据吗?大哥拍拍手:对,那如何让本地测试不影响线上项目呢?这需要多个环境。根据实际需要,将同一个项目(或同一套代码)按照一定的方法进行区分,将需要的资源和项目本身部署到不同的机器上。不同环境下的项目可以有不同的行为,可以同时存在,互不影响。例如,可以为在线项目搭建开发环境。开发环境的数据存储在独立的开发数据库中,为了调试方便,所有用户数据无需登录即可访问:这样一来,本地和线上的项目完全隔离,开发者可以为所欲为想在当地!这就是多环境的好处。常用环境多个环境听起来很酷,但实际上,区分的环境越多越好!一方面,构建多个环境需要额外的工作量;另一方面,项目依赖的资源越多,成本就越高。维护起来比较麻烦。因此,企业中常用的环境就那么几个,而且几乎正在成为一种习惯规范。下面就让我来给大家介绍一下吧。不同的团队可能会以不同的方式区分环境,仅供参考。本地环境一般标有local,指的是前端或后端独立开发、独立测试的环境。通常是让项目和依赖运行在我们自己的电脑上,比如数据库、缓存、队列等各种服务,可能需要自己在本地搭建。本地环境的开发环境一般用dev来标识,指的是前后端(或多个程序员)协作开发、联调的环境。通常,项目和依赖都放在员工电脑可以直接访问的开发机器上。无需自己搭建,直接运行项目即可,提高开发协作效率。对于一个小规模的团队来说,有一套开发环境和本地环境就够了。毕竟本地也可以连接公共数据库等服务。开发环境和测试环境一般都标有test,指的是前后端开发联调完成的环境,做出完整的新功能后,交给测试同学找错误。通常,考试环境中需要有独立的考试数据库和其他服务,让考生大显身手。每次修改bug后,都要重新把项目发布到测试环境,让测试同学重新验证。测试环境预发布环境一般标有pre,是最接近线上项目的环境。一般只有测试验证通过,产品经理体验过后,项目才能发布到这个环境。实际上,预发布环境下项目的后端接口、连接的数据库、服务等都与线上项目“一致”。与线上项目唯一不同的是前端访问的域名。也正因为如此,预发布环境只能看到真实的用户数据,更多在测试环境中因为数据不足而没有发现的bug可以被发现。预发布环境的生产环境一般标有prod,也称为线上环境,是面向所有真实用户的环境。因此不能随意修改,向该环境发布项目时必须格外小心。线上的数据库、机器等资源一般都有专业的运维负责。如果要登录机器或修改配置,都需要经过严格的审批。生产环境如何实施?最后介绍一下多环境的实现方法。其实大同小异,通过抽象配置类+配置文件+环境参数注入三步就可以轻松实现。抽象配置类将项目代码中需要根据环境变化而变化的变量组织成一个或多个配置类集中管理。比如连接数据库时,我们需要数据库IP、端口、配置等信息,代码如下://数据库基本信息DBdb=newDB();db.setIp("10.0.0.1");db.setPort(3306);//数据库连接配置DBConnectionc=newDBConncetion();c.setTimeout(1000);我们可以把这些代码中的硬编码值全部替换成变量,把同样的变量放到一个类中://数据库配置类classDBConfig{Stringip="10.0.0.1";intport=3306;longtimeout=1000L;}然后从这个类中读取变量的值:DBdb=newDB();DBConfigcf=newDBConfig()//获取db.setIp(cffromtheclass.getIp());db.setPort(cf.getPort());DBConnectionc=newDBConncetion();c.setTimeout(cf.getTimeout());这样做的好处是,如果这些变量在代码的其他地方使用,也可以从同一个类中获取,而不是多次重写死值,难以维护。配置文件我们可以使用一个专门的配置文件来维护配置,这样用户修改配置就更方便了,不需要再去寻找和更改代码。常见的配置文件格式有properties、yaml、yml、json等,比如新建一个数据库配置文件db.properties:db.ip=10.0.0.1db.port=3306db.timeout=1000接下来初始化数据库的时候,可以将配置文件中的值加载到上一步写的配置类中,然后读取://从文件中读取配置值DBConfigcf=newDBConfig("db.properties");db.setIp(cf.getIp());db.setPort(cf.getPort());...实际上,它只是将配置值从代码移动到文件。但是这样一来,我们就可以加载我们要加载的配置文件了!比如我们要配置一个测试环境,只需要新建一个db-test.properties文件(在文件名中加上一个环境名),我们就可以在这个文件中写一个独立的配置,然后在代码中加载文件:newDBConfig("db-test.properties");无论是前端还是后端,大部分的多环境实现都是基于这个原则——多套配置,所以在项目中总能看到类似的配置文件:多环境配置文件注入环境参数至此,其实我们已经在代码中写了死值,告诉程序应该加载哪个配置文件。比如本地开发时,加载db-dev.properties。开发完成后,正式上线前,修改代码加载db-prod.properties。但是这样不仅麻烦,而且你可能会忘记修改,把开发环境项目发布到网上。理想的效果应该是:无论项目切换到哪个环境,整个项目根本不需要修改。所以我们可以把指定环境的事情放在最后,在打包或者通过命令启动项目的时候把环境参数写进去。比如我们在启动java项目的时候,给env系统变量传递不同的参数:#test环境java-jar-Denv=testdist.jar#production环境java-jar-Dend=proddist.jar然后在程序参数,加载相应配置即可://读取env参数Stringenv=System.getProperty("env");newDBConfig("db-"+env+".properties");同样,对于前端项目,可以在构建时将其打包在环境变量中传递,然后自己在代码中读取,或者交给Webpack等打包工具:{"scripts":{"serve":"env=devserve","build:test":"env=testbuild""build":"env=prodbuild"}}
