Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Spring Framework Best Practices


Published on

Spring is a powerful Java application framework, used in a wide range of Java applications. It provides enterprise services to Plain Old Java Objects (POJOs). Spring uses dependency injection to achieve simplification and increase testability. Spring beans, dependencies, and the services needed by beans are specified in configuration files, which are typically in an XML format. The XML configuration files, however, are verbose and unwieldy. They can become hard to read and manage when you are working on a large project where many Spring beans are defined.
In this article, I will show you 12 best practices for Spring XML configurations. Some of them are more necessary practices than best practices. Note that other factors, such as domain model design, can impact the XML configuration, but this article focuses on the XML configuration's readability and manageability.

Published in: Software

Spring Framework Best Practices

  1. 1. 1 | P a g e Spring Framework Best Practices Spring is a powerful Java application framework, used in a wide range of Java applications. It provides enterprise services to Plain Old Java Objects (POJOs). Spring uses dependency injection to achieve simplification and increase testability. Spring beans, dependencies, and the services needed by beans are specified in configuration files, which are typically in an XML format. The XML configuration files, however, are verbose and unwieldy. They can become hard to read and manage when you are working on a large project where many Spring beans are defined. In this article, I will show you 12 best practices for Spring XML configurations. Some of them are more necessary practices than best practices. Note that other factors, such as domain model design, can impact the XML configuration, but this article focuses on the XML configuration's readability and manageability. 1. Avoid using autowiring Spring can autowire dependencies through introspection of the bean classes so that you do not have to explicitly specify the bean properties or constructor arguments. Bean properties can be autowired either by property names or matching types. Constructor arguments can be autowired by matching types. You can even specify the autodetect autowiring mode, which lets Spring choose an appropriate mechanism. As an example, consider the following: <bean id="orderService" class="com.lizjason.spring.OrderService" autowire="byName"/> The property names of the OrderService class are used to match a bean instance in the container. Autowiring can potentially save some typing and reduce clutter. However, you should not use it in real-world projects because it sacrifices the explicitness and maintainability of the configurations. Many tutorials and presentations tout autowiring as a cool feature in Spring without mentioning this implication. In my opinion, like object-pooling in Spring, it is more a marketing feature. It seems like a good idea to make the XML configuration file smaller, but this will actually increase the complexity down the road, especially when you are working on a large project where many beans are defined. Spring allows you mix autowiring and explicit wiring, but the inconsistency will make the XML configurations even more confusing.
  2. 2. 2 | P a g e 2. Use naming conventions This is the same philosophy as for Java code. Using clear, descriptive, and consistent name conventions across the project is very helpful for developers to understand the XML configurations. For bean ID, for example, you can follow the Java class field name convention. The bean ID for an instance of OrderServiceDAO would be orderServiceDAO.For large projects, you can add the package name as the prefix of the bean ID. 3. Use shortcut forms The shortcut form is less verbose, since it moves property values and references from child elements into attributes. For example, the following: <bean id="orderService" class="com.lizjason.spring.OrderService"> <property name="companyName"> <value>lizjason</value> </property> <constructor-arg> <ref bean="orderDAO"> </constructor-arg> </bean> can be rewritten in the shortcut form as: <bean id="orderService" class="com.lizjason.spring.OrderService"> <property name="companyName" value="lizjason"/> <constructor-arg ref="orderDAO"/> </bean> The shortcut form has been available since version 1.2. Note that there is no shortcut form for <ref local="...">. The shortcut form not only saves you some typing, but also makes the XML configuration files less cluttered. It can noticeably improve readability when many beans are defined in a configuration file. 4. Prefer type over index for constructor argument matching
  3. 3. 3 | P a g e Spring allows you to use a zero-based index to solve the ambiguity problem when a constructor has more than one arguments of the same type, or value tags are used. For example, instead of: <bean id="billingService" class="com.lizjason.spring.BillingService"> <constructor-arg index="0" value="lizjason"/> <constructor-arg index="1" value="100"/> </bean> It is better to use the type attribute like this: <bean id="billingService" class="com.lizjason.spring.BillingService"> <constructor-arg type="java.lang.String" value="lizjason"/> <constructor-arg type="int" value="100"/> </bean> Using index is somewhat less verbose, but it is more error-prone and hard to read compared to using the type attribute. You should only use index when there is an ambiguity problem in the constructor arguments. 5. Reuse bean definitions, if possible Spring offers an inheritance-like mechanism to reduce the duplication of configuration information and make the XML configuration simpler. A child bean definition can inherit configuration information from its parent bean, which essentially serves as a template for the child beans. This is a must-use feature for large projects. All you need to do is to specify abstract=true for the parent bean, and the parent reference in the child bean. For example: <bean id="abstractService" abstract="true" class="com.lizjason.spring.AbstractService"> <property name="companyName" value="lizjason"/> </bean> <bean id="shippingService" parent="abstractService" class="com.lizjason.spring.ShippingService"> <property name="shippedBy" value="lizjason"/> </bean>
  4. 4. 4 | P a g e The shippingService bean inherits the value lizjason for the companyName property from the abstractService bean. Note that if you do not specify a class or factory method for a bean definition, the bean is implicitly abstract. 6. Prefer assembling bean definitions through ApplicationContext over imports Like imports in Ant scripts, Spring import elements are useful for assembling modularized bean definitions. For example: <beans> <import resource="billingServices.xml"/> <import resource="shippingServices.xml"/> <bean id="orderService" class="com.lizjason.spring.OrderService"/> <beans> However, instead of pre-assembling them in the XML configurations using imports, it is more flexible to configure them through the ApplicationContext. Using ApplicationContext also makes the XML configurations easy to manage. You can pass an array of bean definitions to the ApplicationContext constructor as follows: String[] serviceResources = {"orderServices.xml", "billingServices.xml", "shippingServices.xml"}; ApplicationContext orderServiceContext = new ClassPathXmlApplicationContext(serviceResources); 7. Use ids as bean identifiers You can specify either an id or name as the bean identifier. Using ids will not increase readability, but it can leverage the XML parser to validate the bean references. If ids cannot be used due to XML IDREF constraints, you can use names as the bean identifiers. The issue with XML IDREF constraints is that the id must begin with a letter (or one of a few punctuation characters defined in the XML specification) followed by letters, digits, hyphens, underscores, colons, or full stops. In reality, it is very rare to run into the XML IDREF constraint problem. 8. Use dependency-check at the development phase You can set the dependency-check attribute on a bean definition to a value other than the default none, such as simple, objects, or all, so that the container can do the dependency validation for you. It is useful when all of the properties (or certain categories of properties) of a bean must be set explicitly, or via autowiring.
  5. 5. 5 | P a g e <bean id="orderService" class="com.lizjason.spring.OrderService" dependency-check="objects"> <property name="companyName" value="lizjason"/> <constructor-arg ref="orderDAO"/> </bean> In this example, the container will ensure that properties that are not primitives or collections are set for the orderService bean. It is possible to enable the default dependency check for all of the beans, but this feature is rarely used because there can be beans with properties that don't need to be set. 9. Add a header comment to each configuration file It is preferred to use descriptive ids and names instead of inline comments in the XML configuration files. In addition, it is helpful to add a configuration file header, which summarizes the beans defined in the file. Alternatively, you can add descriptions to the description element. For example: <beans> <description> This file defines billing service related beans and it depends on baseServices.xml,which provides service bean templates... </description> ... </beans> One advantage of using the description element is that it is easy to for tools to pick up the description from this element. 10. Communicate with team members for changes When you are refactoring Java source code, you need to make sure to update the configuration files accordingly and notify team members. The XML configurations are still code, and they are critical parts of the application, but they are hard to read and maintain. Most of the time, you need to read both the XML configurations and Java source code to figure out what is going on. 11. Prefer setter injection over constructor injection
  6. 6. 6 | P a g e Spring provides three types of dependency injection: constructor injection, setter injection, and method injection. Typically we only use the first two types. <bean id="orderService" class="com.lizjason.spring.OrderService"> <constructor-arg ref="orderDAO"/> </bean> <bean id="billingService" class="com.lizjason.spring.BillingService"> <property name="billingDAO" ref="billingDAO"> </bean> In this example, the orderService bean uses constructor injection, while the BillingService bean uses setter injection. Constructor injection can ensure that a bean cannot be constructed in an invalid state, but setter injection is more flexible and manageable, especially when the class has multiple properties and some of them are optional. 12. Do not abuse dependency injection As the last point, Spring ApplicationContext can create Java objects for you, but not all Java objects should be created through dependency injection. As an example, domain objects should not be created through ApplicationContext. Spring is an excellent framework, but, as far as the readability and manageability are concerned, the XML-based configuration can become an issue when many beans are defined. Overuse of dependency injection will make the XML configuration more complicated and bloated. Remember, with powerful IDEs, such as Eclipse and IntelliJ, Java code is much easier to read, maintain, and manage than XML files! Conclusion XML is the prevailing format for Spring configurations. XML-based configuration can become verbose and unwieldy when many beans are defined. Spring provides a rich set of configuration options. Appropriately using some of the options can make the XML configurations less cluttered, but other options, like autowiring, may reduce readability and maintainability. Following good practices discussed in the article may help you to create clean and readable XML configuration files! On a sweltering June morning more than 15 years ago, I climbed into an old fiberglass kayak. It was so old that splinters would break off into my fingers, and the paddle was about twice as long as conventional whitewater paddles. I swam more than I boated, but it didn't matter. Fifteen years later, I am still hooked.
  7. 7. 7 | P a g e About two years ago, I tried out that Spring project that was prominently mentioned on the Hibernate site. It felt just like that old kayak: it fit me perfectly. For hardcore enterprise development, Spring became so deeply woven into my programming that I made it the topic of my fourth Java book, Spring: A Developer's Notebook. In this article, I'll tell you why. 1. Spring Provides Better Leverage On a river, I've learned to paddle with more of my waist and back, because my arm muscles can't hold up to whole days of paddling on the river. I'm more efficient; I get better leverage. With Spring, I can do more work with each line of code. You'll find extra leverage in many places with Spring, but the biggest is in persistence. Here's a method from the Hibernate data access object: public List getReservations( ) { return getHibernateTemplate( ).find("from Reservation"); } Notice what you don't see. There's no transaction processing. Spring lets you build configuration code to handle that. You don't have to manage resources by closing the session. You don't have to do your own configuration. You don't have to manage exceptions at this level, because the exceptions are unchecked. You're free to manage them at the most appropriate place. Here's how another Hibernate method would look, without Spring: public List getBikesOldWay( ) throws Exception { List bikes = null; Session s = null; try { s = mySessionFactory.openSession( ); bikes = s.find("from Bike"); }catch (Exception ex) { //handle exception gracefully }finally { s.close( ); } return bikes; } Spring gives me leverage. I code faster, and maintain less. 2. Spring Enables POJO Programming
  8. 8. 8 | P a g e After the EJB 2.x debacle, we all look to find ways to express enterprise services without invading each and every bean with a cumbersome model. Sure, we need transactions, security, persistence, and sometimes, remoting. With EJB, I had to learn an extensive API and work through the new tools and deployment process. I was a slave to the services provided by the container. With Spring, I can choose my own services and persistence framework. I program in POJOs and add enterprise services to them with configuration files. In Spring: A Developer's Notebook, I built a RentaBike application. Instead of a session bean or an entity bean, I called my POJO hibRentaBike; it serves as my data access object. I add the services elsewhere. The Spring configuration file, called a context, is an XML file with all of the beans in the container, along with their properties and the services the beans need. Here's a look. The target: <bean id="rentaBikeTarget" class="com.springbook.HibRentABike"> <property name="storeName"> <value>Bruce's Bikes</value> </property> <property name="sessionFactory"> <ref local="sessionFactory"/> </property> <property name="transactionManager"> <ref local="transactionManager"/> </property> </bean> The interceptor: <bean name="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"> <ref local="transactionManager"/> </property> <property name="transactionAttributeSource"> <value> com.springbook.RentABike.transferReservation= PROPAGATION_REQUIRED,-ReservationTransferException*=PROPAGATION_REQUIRED com.springbook.RentABike.*=PROPAGATION_REQUIRED,readOnly
  9. 9. 9 | P a g e </value> </property> </bean> The proxy: <bean id="rentaBike" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>com.springbook.RentABike</value> </property> <property name="interceptorNames"> <value>transactionInterceptor,rentaBikeTarget</value> </property> </bean> Notice three different beans: the proxy, the target, and the interceptors. The proxy will call the POJO, and also any services needed by the POJO. Interceptors contain glue code that invokes the service. They also specify how to treat each method in the target. Anyone needing to access RentaBike calls the proxy, which calls the transactional interceptor, which begins a transaction, and calls the target (the POJO). The target does its thing, returns to the interceptor (which commits the transaction), and returns to the proxy and the caller of the proxy. Figure 1. POJO programming in action You build your program out of POJOs and configure it, and Spring hides the rest from you. I'm a POJO programmer. 3. Dependency Injection Helps Testability Spring greatly improves your testability through a design pattern called Dependency Injection (DI). When a consumer depends on a dependency (we'll call it a service), you'll create a property on the consumer. Spring will create the consumer and the service, and set the consumer's property to the value of the service. Said another way, Spring manages the lifecycle of the beans in the context, and resolves
  10. 10. 10 | P a g e dependencies. Here's an example of dependency injection, without Spring. First, here's the consumer, which serves as a primitive view for the application: public class CommandLineView { private RentABike rentaBike; public CommandLineView( ) {rentaBike = new ArrayListRentABike("Bruce's Bikes"); } public void setRentABike(RentABike rentABike){ this.rentABike = rentABike; } public void printAllBikes( ) { System.out.println(rentaBike.toString( )); Iterator iter = rentaBike.getBikes().iterator( ); while(iter.hasNext( )) { Bike bike = (Bike) ); System.out.println(bike.toString( )); } } public static final void main(String[] args) { CommandLineView clv = new CommandLineView( ); clv.printAllBikes( ); } } Next, here's the service, which is the model. It's a simple implementation with an array list. It has a dependency upon the model (RentaBike): interface RentABike { List getBikes( ); Bike getBike(String serialNo); } public class ArrayListRentABike implements RentABike { private String storeName;
  11. 11. 11 | P a g e final List bikes = new ArrayList(); public ArrayListRentABike(String storeName) { this.storeName = storeName; bikes.add(new Bike("Shimano", "Roadmaster", 20, "11111", 15, "Fair")); bikes.add(new Bike("Cannondale", "F2000 XTR", 18, "22222",12,"Excellent")); bikes.add(new Bike("Trek","6000", 19, "33333", 12.4, "Fair")); } public String toString() { return "RentABike: " + storeName; } public List getBikes() { return bikes; } public Bike getBike(String serialNo) { Iterator iter = bikes.iterator(); while(iter.hasNext()) { Bike bike = (Bike); if(serialNo.equals(bike.getSerialNo())) return bike; } return null; } } Here's an assembler. The code in bold is the dependency injection. The assembler instantiates the service and the consumer, and resolves the dependency by setting the rentaBike property: public class RentABikeAssembler { public static final void main(String[] args) { CommandLineView clv = new CommandLineView( ); RentABike rentaBike = new ArrayListRentABike("Bruce's Bikes"); clv.setRentaBike(rentaBike); clv.printAllBikes( ); } } Of course, Spring will eventually fill the role of the assembler. If you wrap the service in an interface, then you'll be able to inject any implementation of the interface into the container. Dependency injection lets you code a production dependency and a test dependency. For example, this example creates a stub object that makes testing the view easier. (For more about stubs and mocks, read "Mocks Aren't Stubs.") You've already seen the Hibernate implementation of RentaBike, and the array list version. I may not want to run all of my user interface tests on the full Hibernate
  12. 12. 12 | P a g e implementation. Instead, I simply implement the interface another way, with an array list. Dependency injection lets me wire up a production version (with HibRentaBike), a development version (with an ArrayListRentaBike list), and a test version (with a mock object). When I'm coding in Java, I've got to have Dependency Injection to get those mocks into hard-to-reach places. 4. Inversion of Control Simplifies JDBC JDBC applications are ugly, verbose, and tedious. A good abstraction layer can help. Spring lets you customize a default JDBC method with a query and an anonymous inner class to eliminate much of the drudge work. Here's a simple JDBC example: JdbcTemplate template = new JdbcTemplate(dataSource); final List names = new LinkedList(); template.query("SELECT USER.NAME FROM USER", new RowCallbackHandler() { public void processRow(ResultSet rs) throws SQLException { names.add(rs.getString(1)); } } ); Think of the template.query method as a default JDBC method. Spring will execute the processRow method in the anonymous inner class for each line in the result set. You configure the data source in the context. You don't have to worry about opening or closing the statement or connection, configuring the data source, or managing transactions. You don't specify an outer result set, or manage exceptions at the lowest levels, because Spring folds your SQLException to a common set of unchecked exceptions. Other languages like Ruby and Smalltalk often use inversion of control with code blocks, but it's not very common in Java. Inversion of control simply rocks. 5. Spring's Community Thrives Some open source projects don't need to be particularly active to be useful. JUnit, for example, does a targeted job, and has basically everything that you need, if you like the programming model. Lightweight containers like Spring need a vibrant community. Spring has one of the most active communities you can find, and you get lots of benefits:
  13. 13. 13 | P a g e  Services: With Spring, you can find hundreds of different services, from security, to systems management, to workflow. For persistence, you can plug in JDO, Hibernate, Top Link, JDBC, or OJB.  Support and education: Dozens of independent consultants offer Spring services, and you can get exceptional training around the world.  Enhancements: Spring puts out several major releases a year. The excellent testing within the framework and the cleanly factored extensions mean that each release is of good quality. Spring already has support for Hibernate 3 underway, and offers a new powerful web flow framework, all in the last major release.  Commercial support: Authors like me write books on Spring. To date, you can find five books on Spring, and several more with some Spring content. Several product vendors also support Spring. Dozens of open source frameworks, such as Geronimo and Hibernate, have special support for Spring. The Spring community makes using the framework much easier. I can hire Spring developers and get them training. I can read books to supplement my knowledge, and get components for just about everything I need to do. I can't find a community for any other lightweight container that comes close.