I seem to have run into an issue in what I am trying to do. I have been writing an automation app that is supposed to run a new instance of our Spring MVC application (on a newly created cloud server instance). I thought that if I just made this automation app unzip my .war after downloading it and then change the info in the spring.properties to match my datbase settings, etc then it should work fine. However, this seems to be causing some major problem as the app won't load using Tomcat after I do do this (gives errors about register JDBC and just hangs). It works fine if I put in the spring.properties settings I want before building the .war and then just run the .war normally within Tomcat.
I'm hoping someone could shed some light on why this issue may be occurring and / or what I can do so that I can dynamically set the properties in spring.properties before running a .war file without having to build the .war with new settings (as this would add more hassle to everything).
Option 1: Use context:property-placeholder and override values using System Property at run-time.
Option 2: Read run-time properties from a file external to the war
6 Tips for Managing Property Files with Spring
So, perhaps this is not the correct answer, but if you're trying to externalize your datasource, then you should use JNDI with Tomcat. It's much cleaner. You just use the jee namespace with spring then to lookup your datasource. This way the server admins can setup the datasource within server.xml :)
Related
I have one application using embedded Camunda engine 7.16, deployed in Wildfly 15, and it works fine.
for some weird architectural reasons, I now need to be able to deploy the same application a second time, in a different environment in which I would like to disable Camunda, because it’s not used there (and the underlying DB doesn’t have the Camunda tables).
In Spring Boot, we can easily disable the starter through properties, but how can we achieve the same in Wildfly ? I have the processes.yml file in the resources/META-INF folder, but is there a way to ignore it a startup ?
Otherwise, I will probably look at some options from Is there a quick way to delete a file from a Jar / war without having to extract the jar and recreate it? , and based on a property at startup, I would try to delete the processes.xml in the war file in the container before it actually starts the application, but that’s hack-ish to say the least
Thanks
I am new to spring. But here a concept is confusing me and am also not getting a clear answer. I am not sure what is the point of creating an external configuration file? Like, what is the point of application.properties ? We can also use the features via code right? Also, if we make a change to the configuration file then we also have to rerun the application right? Then what is the point of doing such a thing?
Thanks in advance.
The point of application.properties is to be able to change some properties without re-compiling your code. So in big companies no QA phase, delivery needed
You just change some properties, restart the application and ready to go.
The application.properties or application.yml file contains the environment variables. This is quite similar with constants in your application. The importance of externalizing it is to minimize updating the source code when some configuration changes.
Example: Your app's database migrated to another server.
You can just update your application.properties file instead of opening your DBConfig.java.
Another benefit is if your team is using Spring Cloud Config Server where your app connects and fetches the testing/staging/production configurations. This means that your configurations are not tightly coupled into your app's source code.
Whereas if you do it directly into your source code, then every time there's a change in the configuration (be it database connection, connection to other services, etc) you'll have to update your code then rebuild and deploy.
Our system is split up into different environments, each one as a separate Tomcat instance.
Development (Windows)
QA: Accessed by our QA department (Linux)
Production: Live site, accessible to customers. (Linux)
Each of these environments rely on separate databases, and several other web services. This means we need to keep track of the various URLs, usernames, and passwords that are all different. Many of these settings are shared across several apps, so it would be ideal to have them all in one place to remove duplication.
Right now we have config files in the application itself. We use Maven profiles to fill in the different config settings when we build the app. But this is clumsy because we have to build a different WAR for each environment.
Where is a good place to store the config files so that we can deploy the same WAR file to each server?
I've done a fair amount of research on this already. But I haven't found an solution that completely makes sense to me yet.
Separate Config Directory
Define a directory to hold config files. Such as /opt/config on linux.
I like this idea, but how do I tell Tomcat where this directory is? I see references to context.xml, but every example I've seen puts the context.xml in the META-INF folder inside the WAR. Is there a way to configure this outside the WAR?
System Property to define environment
This involves setting a system property, and then using some sort of if/else or switching logic to load the appropriate config file. This seems workable, but a bit messy. But where/how do you set this property? I typically start tomcat with ./startup.sh. Do I add arguments to that command or is there another configuration somewhere?
JNDI
I don't think this is an option for us. Every tutorial I've looked at for this seems to be dependent on LDAP or something similar. To my knowledge we don't have that available to us, and it seems like too much overhead to get set up for only a half-dozen config files.
Use system property that refers to the location where your configuration file or directory is located. In this case you can manage different environment easily and no if/else logic is needed.
You application can have hard coded value of config file path, that will allow running application without any additional system property. The application however should fail to start if mandatory data is not found.
Concerning to partial sharing of data among environments.
You can split your data into several files by categories. Some files will be shared, some other different for different environments. You can even develop your own mechanism of references between data files.
However better approach is using some ready-to-use packages. For example Spring framework supports very flexible configuration mechanism. However if you already have Spring-less application introducing this framework for configuration only seems like an overkill. In this case take a look on Apache Commons Configuration package.
Worked with my team on this and we came up with what we feel is a cleaner approach. While every tutorial I found put the context.xml inside the WAR, it can also be placed in the conf folder of the Tomcat directory.
This works for us as all our servers are Tomcat based. So each server can have it's own context.xml which has a property pointing to the config folder on that particular server.
I'm distributing a simple Java webapp as open source. The webapp needs to be configured before it can be run – a configuration file needs to be created, and the location of that configuration file needs to be made known to the webapp as a parameter in web.xml.
Now my question is how to best package and distribute the webapp in order to make it easy to install, and how to describe that installation process in the documentation. The options I can think of are:
Distribute the webapp as a WAR archive. Recommend that users deploy the WAR into their Tomcat/Jetty/whatever, then drop their configuration file into /webapps/myapp/WEB-INF, and modify /webapps/myapp/WEB-INF/web.xml accordingly
Distribute the webapp as source. Recommend that users should drop their configuration file into the /src/main/webapp/WEB-INF folder, then modify their /src/main/webapp/WEB-INF/web.xml accordingly, then build a WAR using Ant or Maven, and deploy that into their servlet container.
There are probably other options that I can't think of.
What setup is likely to be most convenient to users that need to install, configure and deploy the webapp?
Edit: I should add that the configuration file isn't just a few lines – it's a large file that contains a database schema and other stuff and is potentially generated using an external editor; so just providing good defaults isn't an option.
Externalize this configuration and maybe provide some default values. If you make a new version of your app, everybody will have to remember to back-up that configuration file, then redeploy and then copy back that file--> this is a nightmare.
There are many ways to put that configuration somewhere else. You can use Java Preferences for example.
I would say the WAR, although not requiring the configuration would likely be more convenient :)
What is it, loosely, that must be configured such that there isn't a sensible default value for everyone? URL string?
Providing an answer of my own, after more reading on the issue: JNDI seems to be the “official”, although somewhat heavyweight, way of solving this. With JNDI, a configuration option (like the location of the full config file I need) can be declared in the web.xml, and its actual value can be set in a per-webapp context.xml that lives in the /webapps directory of Tomcat (or the /contexts directory of Jetty). This setup has a bunch of advantages:
The big configuration file can live outside of the servlet container and webapp
The webapp can be updated without danger of losing the configuration
The distributed war doesn't need to be modified or rebuilt
Downside: It's sort of complicated, requires messing around with XML, and configuring JNDI on Tomcat works differently from Jetty (requiring twice as much documentation).
Maybe use a system property for the config file location. Can easily be passed on the command line as -Dorg.example.config.file=/foo/bar, in startup scripts or in Java code. I think I've seen some tools, e.g. logging frameworks, use system properties for similar things in webapps.
You might have a set of properties that is used on the developer machine, which varies from developer to developer, another set for a staging environment, and yet another for the production environment.
In a Spring application you may also have beans that you want to load in a local environment but not in a production environment, and vice versa.
How do you handle this? Do you use separate files, ant/maven resource filtering or other approaches?
I just put the various properties in JNDI. This way each of the servers can be configured and I can have ONE war file.
If the list of properties is large, then I'll host the properties (or XML) files on another server. I'll use JNDI to specify the URL of the file to use.
If you are creating different app files (war/ear) for each environment, then you aren't deploying the same war/ear that you are testing.
In one of my apps, we use several REST services. I just put the root url in JNDI. Then in each environment, the server can be configured to communicate with the proper REST service for that environment.
I just use different Spring XML configuration files for each machine, and make sure that all the bits of configuration data that vary between machines is referenced by beans that load from those Spring configuration files.
For example, I have a webapp that connects to a Java RMI interface of another app. My app gets the address of this other app's RMI interface via a bean that's configured in the Spring XML config file. Both my app and the other app have dev, test, and production instances, so I have three configuration files for my app -- one that corresponds to the configuration appropriate for the production instance, one for the test instance, and one for the dev instance.
Then, the only thing that I need to keep straight is which configuration file gets deployed to which machine. So far, I haven't had any problems with the strategy of creating Ant tasks that handle copying the correct configuration file into place before generating my WAR file; thus, in the above example, I have three Ant tasks, one that generates the production WAR, one that generates the dev WAR, and one that generates the test WAR. All three tasks handle copying the right config file into the right place, and then call the same next step, which is compiling the app and creating the WAR.
Hope this makes some sense...
We use properties files specific to the environments and have the ant build select the correct set when building the jars/wars.
Environment specific things can also be handled through the directory service (JNDI), depending on your app server. We use tomcat and our DataSource is defined in Tomcat's read only JNDI implementation. Spring makes the lookup very easy.
We also use the ant strategy for building different sites (differeing content, security roles, etc) from the same source project as well.
There is one thing that causes us a little trouble with this build strategy, and that is that often files and directories don't exist until the build is run, so it can make it difficult to write true integration tests (using the same spring set up as when deployed) that are runnable from within the IDE. You also miss out on some of the IDE's ability to check for the existence of files, etc.
I use Maven to filter out the resources under src/main/resources in my project. I use this in combination with property files to pull in customized attributes in my Spring-based projects.
For default builds, I have a properties file in my home directory that Maven then uses as overrides (so things like my local Tomcat install are found correctly). Test server and production server are my other profiles. A simple -Pproduction is all it then takes to build an application for my production server.
Use different properties files and use ant replace filters which will do the replacement based on environment for which the build is done.
See http://www.devrecipes.com/2009/08/14/environment-specific-configuration-for-java-applications/
Separate configuration files, stored in the source control repository and updated by hand. Typically configuration does not change radically between one version and the next so synchronization (even by hand) isn't really a major issue.
For highly scalable systems in production environments I would seriously recommend a scheme in which configuration files are kept in templates, and as part of the build script these templates are used to render "final" configuration files (all environments should use the same process).
I recently also used Maven for alternative configurations for live or staging environments. Production configuration using Maven Profiles. Hope it helps.
I use Ant's copy with a filter file.
In the directory with the config file with variables I have a directory with a file for each environment. The build script know the env and uses the correct variable file.
I have different configuration folders holding the configurations for the target deployment, and I use ANT to select the one to use during the file copy stage.
We use different ant targets for different environments. The way we do it may be a bit inelegant but it works. We will just tell certain ant targets to filter out different resource files (which is how you could exclude certain beans from being loaded), load different database properties, and load different seed data into the database. We don't really have an ant 'expert' running around but we're able to run our builds with different configurations from a single command.
One solution I have seen used is to configure the staging environment so that it is identical to the production environment. This means each environment has a VLAN with the same IP range, and machine roles on the same IP addresses (e.g. the db cluster IP is always 192.168.1.101 in each environment). The firewalls mapped external facing addresses to the web servers, so by swapping host files on your PC the same URL could be used - http://www.myapp.com/webapp/file.jsp would go to either staging or production, depending on which hosts file you had swapped in.
I'm not sure this is an ideal solution, it's quite fiddly to maintain, but it's an interesting one to note.
Caleb P and JeeBee probably have your fastest solution. Plus you don't have to setup different services or point to files on different machines. You can specify your environment either by using a ${user.name} variable or by specifying the profile in a -D argument for Ant or Maven.
Additionally in this setup, you can have a generic properties file, and overriding properties files for the specific environments. Both Ant and Maven support these capabilities.
Don't forget to investigate PropertyPlaceholderConfigurer - this is especially useful in environments where JNDI is not available