简体   繁体   English

如何在java webapps中管理嵌入式配置文件和库?

[英]How do you manage embedded configuration files and libraries in java webapps?

I'm currently working on a j2ee project that's been in beta for a while now. 我目前正在研究一个已经测试了一段时间的j2ee项目。 Right now we're just hammering out some of the issues with the deployment process. 现在我们正在解决部署过程中的一些问题。 Specifically, there are a number of files embedded in the war (some xml-files and .properties) that need different versions deploying depending on whether you are in a dev, testing or production environment. 具体来说,战争中嵌入了许多文件(一些xml文件和.properties),这些文件需要部署不同的版本,具体取决于您是在开发,测试还是生产环境中。 Stuff like loglevels, connection pools, etc. 像loglevels,连接池等的东西

So I was wondering how developers here structure their process for deploying webapps. 所以我想知道开发人员如何构建他们部署webapps的过程。 Do you offload as much configuration as you can to the application server? 您是否将尽可能多的配置卸载到应用程序服务器? Do you replace the settings files programmatically before deploying? 在部署之前以编程方式替换设置文件吗? Pick a version during build process? 在构建过程中选择一个版本? Manually edit the wars? 手动编辑战争?

Also how far do you go in providing dependencies through the application servers' static libraries and how much do you put in the war themselves? 您还可以通过应用程序服务器的静态库在多大程度上提供依赖关系,以及您自己在战争中投放了多少? All this just to get some ideas of what the common (or perhaps best) practice is at the moment. 所有这些只是为了了解目前常见(或可能是最佳)实践的一些想法。

I think that if the properties are machine/deployment specific, then they belong on the machine. 我认为如果属性是特定于机器/部署的,那么它们属于机器。 If I'm going to wrap things up in a war, it should be drop-innable, which means nothing that's specific to the machine it's running on. 如果我要在战争中把事情包起来,它应该是无法实现的,这意味着没有任何特定于它正在运行的机器。 This idea will break if the war has machine dependent properties in it. 如果战争中有与机器相关的属性,这个想法就会破裂。

What I like to do is build a project with a properties.example file, each machine has a .properties that lives somewhere the war can access it. 我喜欢做的是使用properties.example文件构建一个项目,每台机器都有一个.properties,它存在于war可以访问它的某个地方。

An alternative way would be to have ant tasks, eg for dev-war, stage-war, prod-war and have the sets of properties part of the project, baked in in the war-build. 另一种方法是拥有蚂蚁任务,例如开发战争,阶段战争,生产战争,并将项目的一组属性作为战争构建中的一部分。 I don't like this as much because you're going to end up having things like file locations on an individual server as part of your project build. 我不喜欢这个,因为你最终会在单个服务器上将文件位置等内容作为项目构建的一部分。

I work in an environment where a separate server team performs the configuration of the QA and Production servers for our applications. 我在一个单独的服务器团队为我们的应用程序执行QA和Production服务器配置的环境中工作。 Each application is generally deployed on two servers in QA and three servers in Production. 每个应用程序通常部署在QA中的两个服务器和生产中的三个服务器上。 My dev team has discovered that it is best to minimize the amount of configuration required on the server by putting as much configuration as possible in the war (or ear). 我的开发团队发现,最好通过在战争(或耳朵)中放置尽可能多的配置来最小化服务器上​​所需的配置量。 This makes server configuration easier and also minimizes the chance that the server team will incorrectly configure the server. 这使服务器配置更容易,并最大限度地减少了服务器团队错误配置服务器的可能性。

We don't have machine-specific configuration, but we do have environment-specific configuration (Dev, QA, and Production). 我们没有特定于机器的配置,但我们确实有特定于环境的配置(Dev,QA和Production)。 We have configuration files stored in the war file that are named by environment (ex. dev.properties, qa.properties, prod.properties). 我们有一些存储在war文件中的配置文件,这些配置文件由环境命名(例如dev.properties,qa.properties,prod.properties)。 We put a -D property on the server VM's java command line to specify the environment (ex. java -Dapp.env=prod ...). 我们在服务器VM的java命令行上放置-D属性来指定环境(例如java -Dapp.env = prod ...)。 The application can look for the app.env system property and use it to determine the name of the properties file to use. 应用程序可以查找app.env系统属性并使用它来确定要使用的属性文件的名称。

I suppose if you have a small number of machine-specific properties then you could specify them as -D properties as well. 我想如果你有少量特定于机器的属性,那么你也可以将它们指定为-D属性。 Commons Configuration provides an easy way to combine properties files with system properties. Commons Configuration提供了一种将属性文件与系统属性组合在一起的简便方法。

We configure connection pools on the server. 我们在服务器上配置连接池。 We name the connection pool the same for every environment and simply point the servers that are assigned to each environment to the appropriate database. 我们将连接池命名为每个环境都相同,只需将分配给每个环境的服务器指向相应的数据库即可。 The application only has to know the one connection pool name. 应用程序只需要知道一个连接池名称。

wrt configuration files, I think Steve's answer is the best one so far. wrt配置文件,我认为史蒂夫的答案是目前为止最好答案。 I would add the suggestion of making the external files relative to the installation path of the war file - that way you can have multiple installations of the war in the one server with different configurations. 我会添加关于使外部文件相对于war文件的安装路径的建议 - 这样你就可以在具有不同配置的一个服务器中安装多个war。

eg If my dev.war gets unpacked into /opt/tomcat/webapps/dev , then I would use ServletContext.getRealPath to find the base folder and war folder name, so then the configuration files would live in ../../config/dev relative to the war, or /opt/tomcat/config/dev for absolute. 例如,如果我的dev.war被解压缩到/opt/tomcat/webapps/dev ,那么我将使用ServletContext.getRealPath来查找基本文件夹和war文件夹名称,这样配置文件就会存在于../../config/dev相对于war,或/opt/tomcat/config/dev为绝对。

I also agree with Bill about putting as little as possible in these external configuration files. 我也同意Bill关于尽可能少地放在这些外部配置文件中。 Using the database or JMX depending on your environment to store as much as it makes sense to. 根据您的环境使用数据库或JMX来存储尽可能多的内容。 Apache Commons Configuration has a nice object for handling configurations backed by a database table. Apache Commons Configuration有一个很好的对象来处理由数据库表支持的配置。

Regarding libraries, I agree with unknown to have all the libs in the WEB-INF/lib folder in the war file (self-packaged). 关于库,我同意unknown知道在war文件的WEB-INF/lib文件夹中有所有的WEB-INF/lib (自封装)。 The advantage is that each installation of the application is autonomous, and you may have different builds of the war using different versions of the libraries concurrently. 优点是应用程序的每个安装都是自治的,并且您可能同时使用不同版本的库具有不同的战争版本。

The disadvantage is that it will use more memory as each web application will have its own copy of the classes, loaded by its own class loader. 缺点是它将使用更多内存,因为每个Web应用程序都有自己的类副本,由其自己的类加载器加载。

If this poses a real concern, then you could put the jars in the common library folder for your servlet container ( $CATALINA_HOME/lib for tomcat). 如果这引起了真正的关注,那么你可以将jar放在servlet容器的公共库文件夹中( $CATALINA_HOME/lib用于tomcat)。 All installations of your web application running on the same server have to use the same versions of the libraries though. 在同一服务器上运行的Web应用程序的所有安装都必须使用相同版本的库。 (Actually, that's not strictly true as you could put overriding versions in the individual WEB-INF/lib folder if necessary, but that's getting pretty messy to maintain.) (实际上,这并不完全正确,因为如果有必要,你可以在个别的WEB-INF/lib文件夹中放置重写版本,但维护起来非常麻烦。)

I would build an automated installer for the common libraries in this case, using InstallShield or NSIS or equivalent for your operating system. 在这种情况下,我会为您的操作系统使用InstallShield或NSIS或等效的库构建一个自动安装程序。 Something that can make it easy to tell if you have the most up to date set of libraries, and upgrade, downgrade, etc. 可以让您轻松判断您是否拥有最新的库集,升级,降级等等。

I usually make two properties files: 我通常会制作两个属性文件:

  • one for app specifics (messages, internal "magic" words) embedded in the app, 一个用于应用程序中嵌入的应用程序细节(消息,内部“魔术”单词),
  • the other for environment specifics (db access, log levels & paths...) exposed on each server's classpath and "sticked" (not delivered with my app). 另一个用于环境细节(数据库访问,日志级别和路径......)暴露在每个服务器的类路径上并且“粘贴”(不随我的应用程序提供)。 Usually I "mavenise" or "anttise" these one to put specific values, depending on the target env. 通常我会将这些“mavenise”或“anttise”赋予特定值,具体取决于目标环境。
  • Cool guys use JMX to maintain their app conf (conf can be modified in realtime, without redeploying), but it's too complex for my needs. 酷人使用JMX维护他们的应用程序配置(conf可以实时修改,无需重新部署),但它太复杂,不能满足我的需求。

Server's (static ?) libraries: I strongly discourage server library use in my apps as it adds dependency to the server: 服务器的(静态?)库:我强烈反对在我的应用程序中使用服务器库,因为它增加了对服务器的依赖:

  1. IMO, my app must be "self-packaged": dropping my war, and that's all. IMO,我的应用必须“自我包装”:放弃我的战争,这就是全部。 I have seen wars with 20 Mbs of jars in it, and that's not disturbing for me. 我曾经看到过拥有20 Mbs罐子的战争,这对我来说并不令人不安。
  2. A common best-practice is to limit your external dependencies to what is offered by the J2EE dogma: the J2EE API (use of Servlets, Ejbs, Jndi, JMX, JMS...). 一种常见的最佳实践是将外部依赖性限制为J2EE教条提供的内容:J2EE API(使用Servlets,Ejbs,Jndi,JMX,JMS ......)。 Your app has to be "server agnostic". 您的应用必须是“服务器无关”。
  3. Putting dependencies in your app (war, ear, wathever) is self-documenting: you know what libraries your app depends on. 将依赖项放在您的应用程序(war,ear,wathever)中是自我记录的:您知道应用程序所依赖的库。 With server libs, you have to clearly document these dependencies as they are less obvious (and soon your developers will forget this little magic). 使用服务器库,您必须清楚地记录这些依赖关系,因为它们不太明显(很快您的开发人员就会忘记这个小小的魔力)。
  4. If you upgrade your appserver, chances that the server lib you depends on will also change. 如果升级您的appserver,您所依赖的服务器库的可能性也会发生变化。 AppServer editors are not supposed to maintain compatibility on their internal libs from version to version (and most of the time, they don't). AppServer编辑器不应该在版本之间保持内部库的兼容性(大多数情况下,它们不会)。
  5. If you use a widely-used lib embedded in your appServer (jakarta commons logging, aka jcl, comes to mind) and want to ugrade it's version to get the latest features, you take the huge risk that your appServer will not support it. 如果您使用appServer中嵌入广泛使用的lib(jakarta commons logging,又名jcl,并且想到了ugrade它的版本以获得最新功能),那么您将承担appServer不支持它的巨大风险。
  6. If you relies on a static server object (in a static field of a server class, eg a Map or a log), you'll have to reboot your appserver to clean this object. 如果依赖于静态服务器对象(在服务器类的静态字段中,例如Map或日志),则必须重新启动appserver以清除此对象。 You loose the ability to hot-redeploy your app (old server object will still exists between redeployments). 您失去了热重新部署应用程序的能力(旧服务器对象在重新部署之间仍然存在)。 Using appServer-wide objects (other than those defined by J2EE) can lead to subtle bugs, especially if this object is shared between multiple apps. 使用appServer范围的对象(除了J2EE定义的对象)可能会导致细微的错误,尤其是在多个应用程序之间共享此对象时。 That's why I strongly discourage the use of objects which resides in a static field of an appServer lib. 这就是为什么我强烈反对使用驻留在appServer lib的静态字段中的对象的原因。

If you absolutely need "this object in this appserver's jar", try to copy the jar in your app, hoping there's no dependency on other server's jar, and checking your app's classloading policy (I take the habit to put a "parent last" classloading policy on all my apps: I'm sure I won't be "polluted" by server's jars - but I don't know if it is a "best practice"). 如果您绝对需要“此appserver的jar中的此对象”,请尝试在您的应用程序中复制jar,希望不依赖于其他服务器的jar,并检查应用程序的类加载策略(我习惯于将“父级最后”类加载我所有应用程序的政策:我确信我不会被服务器的罐子“污染” - 但我不知道它是否是“最佳实践”)。

I put all configuration in the database. 我把所有配置都放在数据库中。 The container (Tomcat, WebSphere, etc) gives me access to the initial database connection and from then on, everything comes out of the database. 容器(Tomcat,WebSphere等)使我能够访问初始数据库连接,从那时起,所有内容都来自数据库。 This allows for multiple environments, clustering, and dynamic changes without downtime (or at least without a redeploy). 这允许多个环境,群集和动态更改,而无需停机(或至少没有重新部署)。 Especially nice is being able to change the log level on the fly (although you'll need either an admin screen or a background refresher to pick up the changes). 特别好的是能够动态更改日志级别(尽管您需要管理员屏幕或后台刷新才能获取更改)。 Obviously this only works for things that aren't required to get the app started, but generally, you can get to the database pretty quickly after startup. 显然,这仅适用于启动应用程序不需要的东西,但通常,您可以在启动后很快到达数据库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM