Enterprise Spring Framework Best Practices – Part 3 – XML Config
The best thing about Spring is that there are several ways 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. That 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 can cause grievous mental confusion down the road.
Spring NamespacesWe have no version numbers in schema references.
<?xml ?> <beans > ... </beans>
USE This Config:
<?xml ?> <beans > ... </beans>
Spring automatically picks the highest version available from the project dependencies (jars). As a project evolves, the Spring version will be updated, and we won’t have to maintain all the XML config files to see the new features.
One Bootstrap XML File
A myriad of examples of use 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 /> to include other config files.
Always use classpath: prefix
When importing resources, XML config, properties, etc., always use the classpath: or the classpath*: prefix.
This provides consistency and clarity to the location of the resource. Not every feature of Spring behaves the same way, and 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.
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.
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 ?> <beans > <beans > <bean id="dataSource" class="..."/> <bean id="messagingProvider" class="..."/> </beans> <beans > <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 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.
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 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 is injected with this implementation when Spring starts.
<bean id="accountRepository" class="com.gordondickens.repository.internal.AccountRepositoryImpl"> <constructor-arg /> </bean> <!-- Spring's In-Memory DB Config, using HSQLDB --> <!-- Note the HSQLDB driver must be in the project dependencies --> <jdbc:embedded-database id="dataSource" > <jdbc:script /> <jdbc:script /> </jdbc:embedded-database>
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 /> </bean>
Any Java class can be used in the Spring framework. Infrastructure beans, such as ActiveMQ’s ConnectionFactory or Oracle’s OracleDataSource is possible.
With 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.
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 /> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" > <property /> <property /> <property /> <property /> </bean>
Check out Enterprise Spring Best Practices – Part 1 – Project Configuration for 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" /> <bean class="org.slf4j.bridge.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 it is 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 /> <property /> <property > <list> <!-- Set log level for System.out --> <util:constant /> <!-- Set log level for System.err --> <util:constant /> </list> </property> </bean>
Maven Dependency for SysOutOverSLF4J
<dependency> <groupId>uk.org.lidalia</groupId> <artifactId>sysout-over-slf4j</artifactId> <version>1.0.2</version> </dependency>
- DO NOT use version numbers with the Spring schema namespaces
- Always use the 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
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)