With the move to annotations for use of Spring, many projects have become based on component-scanning, auto-wiring and property-placeholder injection — an ‘implicit’ approach to configuration.

However, it can still be very useful to specify ‘explicit’ configuration. This gives us control of top-level application config & enables extensible configuration using the Strategy pattern.

Gaining control of configuration is crucial to enable per-customer/ per-application customization.

Implicit Configuration

Implicit configuration rests on three legs — annotations to mark Spring-managed beans, component-scanning to find them, and property-placeholder injection to customize values.

Many projects are built with pervasive use of @Service/ @Component annotation & auto-wiring to connect them all.

This however suffers the limitation, that only a single bean can match any autowired reference. Property files provide the only source of customization.

Powerful configuration requires use of the ‘Strategy’ and ‘Delegate’ patterns. However, these confuse auto-wiring. Rich subclassing & configuration of strategies also require stronger configuration than just placeholder injection.

How can we combine this with our existing code?

Explicit XML for Strategy-based Configuration

Spring’s XML configuration provides an ideal means of explicit bean control & instantiation. This is perfect for major project structures, as well as strategy/ subclass configuration.

Generally, XML-based configuration is best for:

core application configuration

major infrastructure/ startup components, such as your DB connection or Hibernate

any rich customization relying on subclassing/ or extensibility

Now, one of the key goals here is not to eliminate annotation-based configuration — but to extend & complement it. Many projects have hundreds of existing auto-scanned & auto-wired components, which we are going to retain compatibility with.

Approach

We’re going to introduce “explicit configuration” for just one or a few key beans, and have these seamlessly inter-operate with the rest of our project.

For this example I am showing an “App Config” bean, which provides a central place for key parameters to be picked up by library code & services.

For example, this enables shared mid-level layers (library code) to be identified & parameterized differently when used by different applications — despite the code being the same.

1. Define the bean class

Here, I’m defining a “central configuration” class to hold key mid-level parameters & identification. Other beans will reference this, to use the values..

/** AppConfig; * -- explicitly instantiated, not to be made @Component or @Service! SPEC. */ public class AppConfig { protected String businessChannel; protected String websiteRoot; protected ITaxCalculator taxCalculator; // Business Channel; web, mobile, email etc. public String getBusinessChannel() {return businessChannel;} public void setBusinessChannel (String businessChannel) {this.businessChannel = businessChannel;} // Website Root; base URL for redirects etc. public String getWebsiteRoot() {return websiteRoot;} public void setWebsiteRoot (String websiteRoot) {this.websiteRoot = websiteRoot;} // Tax Calculator; subclassed & configurable strategy public ITaxCalculator getTaxCalculator() {return taxCalculator;} public void setTaxCalculator (ITaxCalculator taxCalculator) {this.taxCalculator = taxCalculator;} }

2. Don’t use annotations on an ‘explicitly configured’ bean

Annotations such as @Component and @Service are matched by component-scanning, to instantiate an “implicitly configured” instance of your bean.

Since we’re defining it explicitly in XML, using annotations would cause a second (unconfigured) instance to be registered! This would cause a uniqueness error with auto-wiring.

So keep it off, and leave a comment for other developers.

3. Configure as ‘autowire-candidate’ in Spring XML application-context

I could specify a SalesTaxCalculator for the US — but here, I’m defining the tax strategy as GST with a 12.5% rate. This illustrates the usefulness, not just to select subclasses, but to parameterize & configure them. By selecting & implementing different strategies we can adapt the deployment/application to different states & countries.

Note that the bean has to be a candidate for autowiring. This can be filtered by the top-level element ‘default-autowire-candidates’ setting, so this may not be necessary in your project — but I’ll show it here as specified explicitly.

<!-- Application Config; major system-wide paramaters. - - enable app-specific configuration of shared library code, - - customer-specific 'website URLs', - - and customization of Tax strategy. --> <bean class="example.AppConfig" autowire-candidate="true"> <property name="businessChannel" value="WEB" /> <property name="websiteRoot" value="http://literatejava.com/" /> <property name="taxStrategy"> <bean class="example.tax.GstCalculator"> <property name="title" value="GST" /> <property name="ratePercent" value="12.5" /> </bean> </property> </bean>

4. Use annotations to reference the ‘explicitly configured’ bean

Now we have defined the AppConfig bean within our application context, our code (including shared and library code) is freely able to use it — including by auto-wiring.

@Service @Transactional(readOnly = true) public class OrderService { @Autowired protected AppConfig appConfig; // place an Order, using the defined business channel // public void placeOrder (Order order) { // ... } }

Conclusion

Annotation scanning & auto-wiring help us on big projects, where many hundreds or thousands of beans may need to be wired.

However, tend to lead to an “implicit” configuration model with property files & property-placeholder injection being the only source of configurability. This is a weaker & less flexible model than the full power of Spring.

Using Spring XML for key configuration enables more direct & explicit control over application configuration. Subclassed & extensible configuration can be supported, enabling richer & more powerful OO techniques such as the strategy & delegate patterns.

With an XML file per application, or per customer, this enables powerful application-/ customer-specific configuration. Large shared codebases can be enhanced with small sections of pluggable configuration, to deliver widely configurable applications.

How have you been configuring your Spring applications? Share your experiences.

References:

– Spring: Including/excluding a bean from autowiring

– Spring: Classpath scanning & managed components

– Spring: Property placeholder configuration

– Wikipedia: Strategy pattern

– Wikipedia: Delegate pattern