One of the things I wish to do on this blog is to show you realistic examples of using the Spring Framework in Enterprise Application Development. The Spring Framework is very popular for building large scale applications. When you build an e-commerce website that might have 50,000 users on it at any given time the scope of the application you are building changes. This type of site quickly outgrows the traditional 3 tier architecture (web server/app server/database server). The ‘website’ is no longer a simple war file being deployed to Tomcat. You have a data center, with a small server farm. Load balancers, application clusters, message queuing, ‘cloud computing’, micro-services. The Spring Framework was not only built for this type of application environment, but it also thrives in it.
When you start developing enterprise class applications, you will need to support multiple deployment environments. You’re no longer going to be testing code on your laptop, then deploying it to the production server. Frequently in the enterprise, as a developer, you won’t even have access to the production environment. Companies which need to comply with regulations such as SOX, PCI and/or SAS-70 will have specialized teams which will manage code deployments to their testing (QA/UAT) and production environments. This is known as segregation of duties. A very common business practice. From my personal experience, it is more stringent in large financial enterprises than it is in retail organizations. Less so in smaller companies, because they simply don’t have the resources to support specialized IT staffs.
More modern development cultures will be performing CI builds and automated deployments. Teams on the bleeding edge of modern software development might even be doing continuous deployments I feel continuous deployment is probably the holy grail of software engineering, but in reality, it is as rare as a great white buffalo in the wild. I do hope to see more organizations adopt continuous deployments, but it does take a very disciplined organization to get there.
Each of these environments will have its own configuration needs. As the scope of your application grows, chances are the uniqueness of each environment will grow too. The Spring Framework has some outstanding tools which are used to manage the complexities of modern enterprise application development. First, let’s consider some common challenges in the types of environments you will need to support in a large enterprise application.
This is your development environment, running from your laptop. This is an area I often see companies absolutely fail at. Your code should be able to run locally, without the need to connect to other servers in the enterprise. Ideally, you should be able to run the code on a plane at 30,000 without a wi-fi connection.
- You cannot use an external database. You’re not going to use the Oracle development database.
- No interaction with other web services.
- No JMS (MQ Series, Active MQ, Oracle AQ, etc)
- Your build artifacts need to be locally cached (hello Maven, Ivy!!)
The Grails team does an outstanding job of supporting a local development environment of of the box. When you run Grails in dev mode, it will automatically create an in memory H2 database. Hibernate is used to generate the database tables based on your domain classes.
Continuous Integration servers can be tricky little beasts to configure for because of the different types of testing software they accommodate. You may have a project the produces a JAR file, which only has unit tests which will zip right along. You may have integration tests, like Grails does, which bring up an embedded Tomcat instance an H2 in-memory database. Your tests might even perform functional tests using something like Spock and Geb to interact with the embedded Tomcat instance. Its also not uncommon for CI servers to have automated deployment jobs – to another specialized environment.
Each of these scenarios is likely to drive special configuration needs into your application.
Some companies elect to have a development environment. This is typically a production like server environment that the development team has control over. When you deploy into this environment, you will need to configure the application to interact with servers within that environment.
QA / UAT
QA or “Quality Assurance” and UAT “User Acceptance Testing” are environments for non-developer resources to test the software. In some organizations, you may have both QA and UAT, or you might have one or the other. If you have both, chances are the organization has formal QA Engineers which work with the QA Environment, and Business Analysts which work with the UAT environment. These environments are often managed by a configuration management team. Sometimes developers will have access to the environment, but often they will not.
Pre-Production or Stage
Pre-Production or Stage (Staging) is an application environment that works with all the production services and supporting databases. This is an environment that allows the deployment of application code, but limits the access to that code. For a website, you might see a special URL or access restricted to specific IPs, or throttled by load balancers.
This environment is not as common, but some organizations use it. Facebook deploys code something along this line.
Production is the environment you end users will utilize. This is the main transactional environment and the one your business partners wish to keep operational at all times.
You can see each of these environments will have its own unique requirements. You’re going to have different database servers, different database versions, often different database vendors. You’ll have different supporting services. For example in an e-commerce website, you might have a payment gateway. In dev, it might be a mock, in test you might be using a testing gateway supplied by your payments provider, and then a different payment gateway for production.
Spring Framework Multi-Environment Support
The Spring Framework was developed from the ground up to support the challenges of supporting complex enterprise environments. You have a number of mature features in the Spring Framework to use in supporting the challenges of enterprise class applications.
The Spring Framework has excellent support of externalizing properties. “Properties” are simple string values which are externalized from your application. In the Spring Framework properties can be set the following ways:
- In a traditional properties file. This is typically kept in the resources folder and is often named ‘application.properties’. It is by convention to use <filename>.properties.
- Using Operating System Environment variables. Java can read values set in the Operating System as environment variables. I’ve used this in the past for things like database settings, which worked out nicely. In this case, my build artifact was easily portable between environments. Once set up, it was effectively ‘drag and drop’ for the support staff.
- Command line variables. When starting any Java application, you have the opportunity to pass command line variables into the program. This is a handy way to make your build artifact portable. One word of caution, when examining running processes on a system, you can sometimes see the command line information which started the process. So this solution may not be the best option for password strings.
The Spring Framework Support has a number of options for sourcing in property values. One way is using the Spring Expression Language (SpEL). You can see some examples of this in my recent post here.
Changing property values is great for things like connecting to a different database server. But often in enterprise class applications you will need behavioral changes which are beyond simple property changes. One of the core features of the Spring Framework is the support of Dependency Injection. Once you become accustomed to development with Dependency Injection with in the Spring Framework, you will see how your code becomes more modular. Your classes will naturally adhere to the Single Responsibility Principle. If you’re doing Dependency Injection against Interfaces, it becomes very easy to swap out components.
Let’s say you have an application which needs to send a JMS message on an event such as a customer purchase. This may trigger an email to the customer about their order, and the data warehouse group might want the purchase information for their analytics. For your unit tests and your integration tests, you might be using Mockito to provide a mock. In your deployed environments you might be using the corporate standard of MQSeries for messaging. But what about doing CI builds? An embedded instance of ActiveMQ just might be perfect solution.
So, in summary, this example has:
- A Mockito Mock object;
- 3 different MQ Series configurations;
- And embedded ActiveMQ.
The MQSeries configurations are easy to handle with property settings. The only thing changing here is the connection parameters. This is the perfect use case for externalized properties.
For your unit tests, if you want to keep them true unit tests (as I defined here), you’ll need to manage the dependency injection yourself. Testing frameworks such as Mocktio and Spock make this easy to do.
If you’re performing integration tests an easy way to manage the Spring Context is through configuration composition. But you may wish to favor using Spring Profiles instead. Each is easy to use, as I explain in the sections below.
Inexperienced Spring developers will place all their configuration into single xml files or configuration packages. This is often a mistake since it limits your configuration options. In our example, all of our configuration options could be supported through configuration composition. You would need to place each configuration into a separate xml file, or configuration package. Then selectivity import it into a parent configuration. You basically import the configuration you wish to use into a parent configuration, then load the parent into your Spring Context at run time. This is still a very popular technique to use for testing where it is very easy to specify the Spring context to use at runtime.
For a long time this was the only option Spring developers had to use. In Spring 3.1, Profiles were introduced to help manage different configurations. As you’ll see in the next section this a very powerful feature of Spring.
Spring Framework Profiles
If you do not mark your Spring Been with a profile, it will always be loaded into the Spring Context.
When you do mark your Spring Bean with a profile, then that profile must be set to active for that bean to be loaded into the Spring Context. This makes management of the environment easy, since you can simply mark the different options with the appropriate profile, then when you set that profile option to active, Spring will wire up the appropriate Spring Beans into your application.
There is one special profile that is rather poorly documented, but very nice to use. And that is the
default profile. When you mark a Spring Bean using
default , this bean is loaded into the context only if no other profile has been set to active. If it there is an active profile, Spring will attempt to find a bean matching that profile first.
What I like about using this option is you don’t have to set an active profile in production. While this is easy to use, from experience it can cause some friction and confusion with the configuration management team. Through the use of default profiles, your application can be deployed into production without an active profile being set.
Going back to the example we’ve been using, I would probably use a CI build profile for the CI build where I wanted to use an embedded instance of ActiveMQ, then setup the MQSeries option using the default profile. Having control over the CI build environment it’s easy for me to specify an active profile, so my CI build profile objects will get loaded into the Spring context. When my example application gets deployed elsewhere, no profile is set to active, so the default profile objects with the MQSeries configuration get loaded into the Spring Context. While we are supporting 3 different environments with MQSeries, this can be managed (and should be) with properties. This is because the MQSeries objects remain the same, except for the configuration of the environment the application is connecting to.
As an application developer, the Spring Framework offers you a lot of options on how you can compose your application. If you’re used to smaller scale development, the plethora of configuration options in the Spring Framework will probably seem like overkill to you. Why would you need such flexibility? Right? No, Wrong. As I’ve shown here, when developing applications in the enterprise you are going to be challenged with supporting the needs of many different environments. You are not just developing code on your laptop. No longer is the production environment the only environment you need to be concerned with. In a large enterprise you will need to support multiple environments, with different configurations and different needs. The Spring Framework has evolved over the years to support the challenging needs of enterprise application development. It’s no wonder that the Spring Framework is the most popular framework to use for developing enterprise class Java applications.