A business component architecture with Spring 3.0/3.1 - Part 1: Structure - ...

:

This is the first post in a series describing a business component architecture using Spring 3.0/3.1 features like Java based configuration, the environment abstraction, bean definition profiles and property sources. Check here for part two on resources and here for part three on properties.

Today we’re gonna step down from the cloud(s) to a rather traditional, old fashioned software development environment: a big company with several hundred application developers working in different IT departments, not for developing a product, but for supporting the business of the company. They are each responsible for a certain aspect of the overall functionality. Every IT department is producing components that can be used by other departments. Those business components shall be usable in different contexts, for example online and batch. To be able to react to future requirements, the usability should be restricted the least possible. Vendor-lock-in shall be avoided. A very important aspect is a good testability.
How could such a business component architecture look like?

A business component consists of a public interface describing the contract the component is offering and a hidden implementation.
Technically the public part is a collection of interfaces, DTO classes and exceptions, while the hidden part includes the implementation of the interfaces. Of course the business logic can be divided in sub components.
To keep the example clear we’ll have two business components containing one service each. The first one is the PartnerService and a DTO:

public interface PartnerService {
 
	public Partner getPartner(long id);
 
}
 
public class Partner {
 
	private long id;
	private String name;
 
	// getters and setters omitted for readability
 
}

public interface PartnerService {public Partner getPartner(long id);}public class Partner {private long id; private String name;// getters and setters omitted for readability}

The second one is the CashingService with a DTO:

public interface CashingService {
 
	public void doBooking(BookingInfo bookingInfo);
 
}
 
public class BookingInfo {
 
	private long partnerId;
	private BigDecimal amount;
	private String subject;
 
	// getters and setters omitted for readability
 
}

public interface CashingService {public void doBooking(BookingInfo bookingInfo);}public class BookingInfo {private long partnerId; private BigDecimal amount; private String subject;// getters and setters omitted for readability}

This was the public part of the business components. The hidden part, the implementation of the services, is one class each:

public class PartnerServiceImpl implements PartnerService {
 
	@Override
	public Partner getPartner(long id) {
		Partner partner = null;
		// TODO do something to get partner
		return partner;
	}
 
}

public class PartnerServiceImpl implements PartnerService {@Override public Partner getPartner(long id) { Partner partner = null; // TODO do something to get partner return partner; }}

The implementation of the CashingService has a dependency on the PartnerService injected through the constructor.

public class CashingServiceImpl implements CashingService {
 
	private PartnerService partnerService;
 
	public CashingServiceImpl(PartnerService partnerService) {
		this.partnerService = partnerService;
	}
 
	@Override
	public void doBooking(BookingInfo bookingInfo) {
		// TODO validate bookingInfo
		Partner partner = partnerService.getPartner(bookingInfo.getPartnerId());
		// TODO use partner to do the booking
	}
 
}

public class CashingServiceImpl implements CashingService {private PartnerService partnerService;public CashingServiceImpl(PartnerService partnerService) { this.partnerService = partnerService; }@Override public void doBooking(BookingInfo bookingInfo) { // TODO validate bookingInfo Partner partner = partnerService.getPartner(bookingInfo.getPartnerId()); // TODO use partner to do the booking }}

Dependency structure interface and implementation

Dependency structure interface and implementation


We use Maven for build and dependency management.
We divide interface and implementation of a business component in two separate projects. Alternatively we can have one project producing two artifacts, that would be a similar solution. In the following I will always refer to the different projects approach. Well, an implementation project is always depending on its own interface project, but can depend on as many other interface projects as needed. In the example the cashing implementation project depends on the partner interface project. The important thing is that implementation projects never depend on other implementation projects, even not transitive, and it can never happen, that the developer of one business component accidentally uses implementation details of another business component. Every business component defines itself only through the interface, implementation details can be replaced at any time. Business logic can be tested easily by unit tests.

Now we have two projects with POJOs containing business logic implementation and interfaces. Still missing is the configuration connecting the components via dependency injection. I suggest Spring’s Java based configuration (for a German article comparing the different DI styles see here). For the partner business component such a configuration looks like this:

@Configuration
public class PartnerConfig {
 
	@Bean
	public PartnerService partnerService() {
		return new PartnerServiceImpl();
	}
 
}

@Configuration public class PartnerConfig {@Bean public PartnerService partnerService() { return new PartnerServiceImpl(); }}

This configuration gets its own project having a dependency on the implementation project. In this way we separate configuration and infrastructure strongly from business logic, for example we have no dependency on Spring in the interface and the implementation project. The configuration of the cashing component has a dependency on the configuration project of the partner business component:

@Configuration
@Import(PartnerConfig.class)
public class CashingConfig {
 
	@Autowired
	private PartnerConfig partnerConfig;
 
	@Bean
	public CashingService cashingService() {
		return new CashingServiceImpl(partnerConfig.partnerService());
	}
 
}

@Configuration @Import(PartnerConfig.class) public class CashingConfig {@Autowired private PartnerConfig partnerConfig;@Bean public CashingService cashingService() { return new CashingServiceImpl(partnerConfig.partnerService()); }}

Complete dependency structure including configuration

Complete dependency structure including configuration


The CashingConfig imports the PartnerConfig, which is used to inject the PartnerService into the CashingServiceImpl.
Though my Javamagazin article already mentions advantages of this type of configuration I want to point out the most important features here, especially for a distributed development environment:
  1. Navigation in Spring configurations (even over jar boundaries)
  2. Being able to navigate through the configuration with standard IDE functionality makes it easy to understand it. In the example it’s one click from the definition of the CashingService to the definition of the PartnerService, even if it’s in a bound jar and not as source in the workspace. That’s not possible in XML.

  3. Locating configuration files in bound jars
  4. The configuration file being a Java class makes it possible to find it via “Open Type”. Being an XML file it cannot be found via “Open Resource”.

  5. Detecting usage of a certain class or interface in configuration files
  6. Again, no problem in Java, even in bound jars. With XML at least not possible in jars in the classpath.

Explicit configuration with JavaConfig supports understandability and traceability, key features for error prevention, bugfixing and maintainability.

Using a business component

We got the configuration of a business component in Spring’s JavaConfig. To use the component we need an instantiated ApplicationContext with the configuration bound to it.
So, what are our options? It’s easy when the application wanting to use the business component itself is a Spring application. Then we can import the configuration into the existing configuration. For example for binding the cashing business component into the application we just need to import the CashingConfig class into the existing ApplicationContext. All configurations CashingConfig is depending on get imported automatically.
If that’s not the case we need to have an infrastructure unit managing the ApplicationContext and offering the services to external clients. It could be a web application offering restful services. It could be an EJB accessing the ApplicationContext. Or it could be an application listening to a queue. There are a lot of options.

Conclusion

The business component architecture presented here divides the necessary parts of a business component in three projects / artifacts:
– interface
– implementation
– configuration
Through the defined dependencies between the projects / artifacts we achieve a strong separation of public interface and hidden implementation and business logic and infrastructure. The usage of explicit, Java based configuration supports an easy handling in every IDE and understandability and traceability which leads to maintainability. Through consequent application of dependency injection we achieve an easy testability. The fact that implementation projects may not reference other implementation projects enforces dependency injection. Last, but not least: a business component does not need a certain runtime environment, it can be used in different functional and technical contexts.

What now?

Of course there are still a lot of open questions, for example handling properties, resources and environment specific configurations. Spring 3.1’s environment abstraction offers new possibilities here, I will talk about them in follow-up blog posts:
A business component architecture with Spring 3.0/3.1 – Part 2: Resources
A business component architecture with Spring 3.0/3.1 – Part 3: Properties

One final word regarding explicit and implicit configuration

Definition explicit configuration: Dependency injection between components is configured explicitly via XML snippets or Java code.
Definition implicit configuration: Dependency injection between components is done either by conventions or by classpath scanning and autowiring with annotations.

Definition explicit / implicit configuration

Convention over configuration is the talk of the town, and through all the recent XML bashing explicit configuration has become pretty uncool. Nevertheless I present an approach here with explicit configuration playing an important part. Why?

  1. The preconditions
  2. We have hundreds of stakeholders, different IT business departments, central architecture departments and operations. The application’s configuration MUST be easy to understand and follow. And explicit configuration is easier to follow then automatic scanning and instantiation of components in the classpath. And, being honest, how much time does it take to do a configuration for a component? Two minutes?

  3. Explicit configuration does not mean XML
  4. There is no XML in my concept, Spring’s Java based configuration has a lot to offer. Honestly, I wouldn’t do explicit configuration in XML anymore.

  5. This is enterprise, coolness is not important
  6. I don’t present the concept here because I think it’s some cool hype thing, but because I think it works. And that’s still the most important thing in software development.