Enterprise Spring Best Practices Series
In part 3, Spring XML Configuration.
The best thing about Spring is that there are several way to solve a problem, the worst thing about Spring is that there are several ways to solve a problem!
One of the greatest challenges when using Spring is choosing the best way to implement solutions. As most of us developers do, we hit Google or grab books on Spring, which can get us moving in the right direction. Many times we find conflicting configurations between implementation approaches. For Spring newcomers, this can be challenging and cause grievous mental confusion down the road.
Sections
- Spring Namespaces
- One Bootstrap XML File
- Always use
classpathPrefix - Bean Naming
- Dependency Injection
- Third Party Beans
- Externalize Properties
- Logging Beans
- Best Practices
- Further Reading
- Social Me
Spring Namespaces
Instead of:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
...
</beans>
USE This Config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
...
</beans>
WHY?
Spring automatically picks the highest version available from the project dependencies (jars). As a project evolves, the Spring version will be updated, we won’t have to maintain all the XML config files to see the new features.
One Bootstrap XML File
There are many examples of using multiple XML configuration files. An application usually has several XML configuration files, but there should only be ONE bootstrap file. This bootstrap file should use the
<import resource=""/> to include other config files.
Classpath Prefix
Always use
classpath: prefixWhen importing resources, XML config, properties, etc. Always use the
classpath: or classpath*: prefix.This provides consistency and clarity to the location of the resource. Not every feature of Spring behaves the same,
classpath: guarantees consistency.The classpath is determined by the build tool and IDE. Usually this is
src/main/java for java code, src/main/resources for non-java dependencies and for tests, src/test/java for java code and src/test/resources for non-java resources.
Example:
<import resource="classpath:/META-INF/spring/applicationContext-security.xml"/>
Bean Naming
The Spring Context is the container for the application’s beans. Each bean is uniquely identified by its name. The xml attribute “id” is most commonly used to define the bean’s name. The “id” attribute is great because it is, by XML Law, unique per file.
<bean id="accountService" class="com.gordondickens.services.AccountService/>
However, if we want to use special symbols in the name or provide aliases to the name, we can use the Spring provided “name” attribute.
<bean name="accountService,services/account" class="com.gordondickens.services.AccountService/>
Spring 3.1 added the profile feature, providing the ability to configure beans by category or region.
With 3.1, Spring overloads the XML “id” attribute allowing multiple beans with the same “id” in an XML file by profile.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<beans profiles="dev,qa">
<bean id="dataSource" class="..."/>
<bean id="messagingProvider" class="..."/>
</beans>
<beans profiles="prod">
<bean id="dataSource" class="..."/>
<bean id="messagingProvider" class="..."/>
</beans>
</beans>
For more detail on Spring 3.1 profiles, see my blog Spring 3.1 Environment Profiles
Dependency Injection
Dependency Injection is one of the basic tenets of the Spring Framework. DI provides developers the ability to “wire together” bean relationships in configuration instead of coding the relationships.
The two ways to perform di are either by Constructor injection or Setter Injection.
In Enterprise Spring Best Practices – Part 2 – Application Architecture, describes the layered application approach. In this layered approach, we can expect to inject beans together between layers.
For example, wiring from the bottom up:
DataSource, the common JDBC class for database connectivity, is injected into our persistence beans- The persistence beans are injected into our service beans
- The service beans are injected into our controller beans
Constructor Injection
Constructor injection is performed using the <bean/> node <constructor-arg.
Thread safety, is a strong case for using constructors. Making beans immutable, is the cheapest thread-safety we can code.
In the following example, we see configuration of an in-memory HSQLDB database with an “id” of “dataSource”. The bean AccountRepositoryImpl bean is injected with this implementation when Spring starts.
<bean id="accountRepository"
class="com.gordondickens.repository.internal.AccountRepositoryImpl">
<constructor-arg ref="dataSource"/>
</bean>
<!-- Spring's In-Memory DB Config, using HSQLDB -->
<!-- Note the HSQLDB driver must be in the project dependencies -->
<jdbc:embedded-database
id="dataSource" type="HSQL">
<jdbc:script
location="classpath:/mySchema.sql"/>
<jdbc:script
location="classpath:/mySampleData.sql"/>
</jdbc:embedded-database>
Setter Injection
Setter injection, provides the capability of injecting beans via a setter method. Traditionally, this has been the preferred choice for many developers, because the configuration is easier to read.
<bean id="accountRepository"
class="com.gordondickens.repository.internal.AccountRepositoryImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
Third Party Beans
Any Java class can be used in the Spring framework. Infrastructure beans, such as ActiveMQ’s
ConnectionFactory or Oracle’s OracleDataSource is possible.
Third party beans, where we don’t have the source, or do not wish to tamper with the source, the choice for DI is made for us.
Externalize Properties
Deployment configuration requires setting environmental parameters, such as database connection properties.
Since XML can be brittle, it is best to externalize settings into property files. This makes it easier for the deployment team to change resource configuration with less risk.
Spring provides a PropertyPlaceholderConfigurer for that purpose.
Property Replacement Config
<context:property-placeholder
location="classpath*:META-INF/spring/*.properties"/>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName"
value="${database.driverClassName}"/>
<property name="url"
value="${database.url}"/>
<property name="username"
value="${database.username}"/>
<property name="password"
value="${database.password}"/>
</bean>
Properties File
database.driverClassName=org.hsqldb.jdbcDriver database.url=jdbc\:hsqldb\:mem\:mydb database.username=sa database.password=
Logging Beans
Following up on Enterprise Spring Best Practices – Part 1 – Project Configuration logging configuration.
Java Util Logging
To Enable handling of java.util.logging classes with SLF4J. Register the following in your Spring configuration:
<!-- Enable handling of java.util.logging through SLF4J --> <bean id="slf4JBridgeHandler" class="org.slf4j.bridge.SLF4JBridgeHandler" init-method="removeHandlersForRootLogger"/> <bean class="org.slf4j.bridge.SLF4JBridgeHandler" init-method="install" depends-on="slf4JBridgeHandler"/>
System.out and System.err
To Enable handling of System.out and System.err messages. Register the following in your Spring configuration:
NOTE: This is NOT recommended for ongoing development, but for migrating poor code to use logging.
<!-- System.out.println & System.err.println handling through SLF4J -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J"/>
<property name="staticMethod"
value="uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J.sendSystemOutAndErrToSLF4J"/>
<property name="arguments">
<list>
<!-- Set log level for System.out -->
<util:constant
static-field="uk.org.lidalia.sysoutslf4j.context.LogLevel.DEBUG"/>
<!-- Set log level for System.err -->
<util:constant
static-field="uk.org.lidalia.sysoutslf4j.context.LogLevel.ERROR"/>
</list>
</property>
</bean>
Maven Dependency for SysOutOverSLF4J
<dependency> <groupId>uk.org.lidalia</groupId> <artifactId>sysout-over-slf4j</artifactId> <version>1.0.2</version> </dependency>
Best Practices
- DO NOT use version numbers with the Spring schema namespaces
- Always use
classpath:/prefix for consist resource referencing - Always use a single XML config file to bootstrap the application or tests
- Use the XML “id” attribute to identify a bean
- Use Constructor injection to promote thread safety
- Use Properties for configurable resources
- DO NOT use the SysOutOverSLF4J for anything other than migration
Further Reading
- Enterprise Spring Best Practices – Part 1 – Project Configuration
- Enterprise Spring Best Practices – Part 2 – Application Architecture
- Enterprise Spring Best Practices – Source Code
- SLF4J
- SysOut Over SLF4J
- FREE Spring Framework PDF (848 pages)
Social Me
Twitter – twitter.com/gdickens
LinkedIn – linkedin.com/in/gordondickens
GitHub: github.com/gordonad
gordon@gordondickens.com
Pingback: Enterprise Spring Best Practices – Part 1 – Project Config | Technophile Blog
Pingback: Enterprise Spring Best Practices – Part 2 – Application Architecture | Technophile Blog
Enjoying the articles, Gordon. Keep ‘em coming!
Thank you @Gardon the the information about Best Practices for Spring Configurations.
Concise and educating.
Can you share your best practice for the properties file read by PropertyPlacholderConfig? Specifically, how do you use a different set of properties per deployment env?