C H A P T E R  2

Spring Framework Fundamentals

The Spring Framework evolved from the code written for Expert One-on-One J2EE Design and Development by Rod Johnson (Wrox, 2002). The framework combines best practices for Java Enterprise Edition (JEE) development from the industry and integration with the best-of-breed third-party frameworks. It also provides easy extension points to write your own integration if you need one that doesn’t yet exist. The framework was designed with developer productivity in mind, and it makes it easier to work with the existing, sometimes cumbersome Java and JEE APIs.

Before we start our journey into Spring MVC and Spring Web Flow, we will provide a quick refresher course on Spring Core (formerly known as the Spring Framework). Spring is now a longtime de-facto standard for Java enterprise software development. It introduced many of us to concepts such as dependency injection, aspect-oriented programming (AOP), and programming with plain-old-Java-objects (POJOs).

In this chapter, we will cover dependency injection and AOP. Specifically, we will cover how the Spring Framework helps us implement dependency injection and how to use programming to our advantage. To be able to do the things mentioned here, we will explore the Inversion of Control (IoC) container; the application context.  

We will only touch on the necessary basics of the Spring Framework here. If you want more in-depth information about it, we suggest the excellent Spring Reference guide (www.springsource.org) or books such as Pro Spring 3 (Apress, 2012) or Spring Recipes, 2nd Edition (Apress, 2011).

Let’s begin by taking a quick look at the Spring Framework and the modules that comprise it.

Image Tip  You can find the sample code for this chapter in the chapter2-samples project. Different parts of the sample contain a class with a main method, which you can run to execute the code.

The Spring Framework

In the introduction, we mentioned that the Spring Framework evolved from code written for the book Expert One-on-One J2EE Design and Development by Rod Johnson. This book was written to explain some of the complexities in JEE and how to overcome them. And while many of the complexities and problems in JEE have been solved in the newer JEE specifications (especially since JEE 6), the Spring Framework remains very popular.

It remains popular due to its simple (not simplistic!) approach to building applications. It also offers a consistent programming model for different kinds of technologies, be they for data access or messaging infrastructure. The framework allows developers to target discrete problems and build solutions specifically for them.

The framework consists of several modules (see Figure 2-1) that work together and build on each other. We can pretty much cherry pick the modules we want to use.

Image

Figure 2-1. Overview of the Spring Framework

All of the modules from Figure 2-1 are represented as jar files that we can include on the classpath if we need a specific technology. In Table 2-1, we list all the modules coming with Spring 3.1 and give a brief description of the content of each module, as well as any artifact names that might be used for dependency management. The name of the actual jar file might differ, depending on how one obtains the module. The downloadable distribution contains jars in this form: org.springframework.[module-name]-[version].jar. Jars that come from the maven repositories use this form: spring-[artifact].jar. See table 2-1.

Image

Image

Most of the modules have a dependency on some other module in the Spring Framework. The core module is an exception to this rule. Figure 2-2 gives an overview of the commonly used modules and their dependencies on other modules. Notice that the instrumentation, aspect, and test modules are missing from the figure; this is because their dependencies depend on the project and what other modules are used. The Spring Framework has only one required dependency: commons-logging, a logging abstraction framework. The other dependencies differ based on the needs of the project.

Image

Figure 2-2. The Spring Framework Module dependencies

Dependency Injection

The concept of dependency injection (DI), objects are given their dependencies at construction time, is one of the foundations of the Spring Framework. You have also probably heard of Inversion of Control (IoC)1. IoC is a broader, more general concept that can be addressed in different ways. IoC lets developers decouple and focus on what is important for a given part of an enterprise application, but without having to think about what other parts of the system do. Programming to interfaces is one way to think about decoupling.

Almost every enterprise application consists of multiple components that need to work together. In the early days of Java enterprise development, we simply put all the logic of constructing those objects (and the objects those objects needed) in the constructor (see Listing 2-1). At first sight, there is nothing wrong with that approach; however, as time progressed, object construction became slow, and objects had a lot of knowledge they shouldn’t have had (see the Single Responsibility Principle2). Those classes became hard to maintain, and they were also quite hard to unit and/or integration test.

Listing 2-1. A MoneyTransferService implementation with hardcoded dependencies

package com.apress.prospringmvc.moneytransfer.simple;

import java.math.BigDecimal;

import com.apress.prospringmvc.moneytransfer.domain.Account;
import com.apress.prospringmvc.moneytransfer.domain.MoneyTransferTransaction;
import com.apress.prospringmvc.moneytransfer.domain.Transaction;
import com.apress.prospringmvc.moneytransfer.repository.AccountRepository;
import com.apress.prospringmvc.moneytransfer.repository.MapBasedAccountRepository;
import com.apress.prospringmvc.moneytransfer.repository.MapBasedTransactionRepository;
import com.apress.prospringmvc.moneytransfer.repository.TransactionRepository;
import com.apress.prospringmvc.moneytransfer.service.MoneyTransferService;

public class SimpleMoneyTransferServiceImpl implements MoneyTransferService {

    private AccountRepository accountRepository = new MapBasedAccountRepository();
    private TransactionRepository transactionRepository = new MapBasedTransactionRepository();

    public SimpleMoneyTransferServiceImpl() {
        super();
        ((MapBasedAccountRepository) this.accountRepository).initialize();

    }

    @Override
    public Transaction transfer(String source, String target, BigDecimal amount) {
        Account src = this.accountRepository.find(source);
        Account dst = this.accountRepository.find(target);


        src.credit(amount);
        dst.debit(amount);

        MoneyTransferTransaction transaction = new MoneyTransferTransaction(src, dst, amount);
        this.transactionRepository.store(transaction);
        return transaction;
    }
}

____________

The class from Listing 2-1 programs to interfaces, but it still needs to know about the concrete implementation of an interface simply to do object construction. Applying IoC by decoupling the construction logic (collaborating objects) makes the application easier to maintain and increases testability. There are seven ways to decouple this dependency construction logic:

  1. Factory pattern
  2. Service locator pattern
  3. Dependency injection
    1. Constructor based
    2. Setter based
    3. Interface based
    4. Annotation driven
  4. Contextualized lookup

When using the factory pattern, service locator pattern, or contextualized lookup, the class that needs the dependencies still has some knowledge about how to obtain the dependencies. This can make things easier to maintain, but it can still be hard to test. Listing 2-2 shows a contextualized lookup from JNDI (Java Naming and Directory Interface). The constructor code would need to know how to do the lookup and handle exceptions.

Listing 2-2. MoneyTransferService implemenation with contextualized lookup

package com.apress.prospringmvc.moneytransfer.jndi;

import javax.naming.InitialContext;
import javax.naming.NamingException;

//other import statements ommitted.
public class JndiMoneyTransferServiceImpl implements MoneyTransferService {

    private AccountRepository accountRepository;
    private TransactionRepository transactionRepository;

    public JndiMoneyTransferServiceImpl() {
        try {
            InitialContext context = new InitialContext();
            this.accountRepository = (AccountRepository) context.lookup("accountRepository");
            this.transactionRepository = (TransactionRepository) context.lookupimages
("transactionRepository");

        } catch (NamingException e) {
            throw new IllegalStateException(e);
        }
    }

    //transfer method omitted, same as Listing 2-1
}

The immediately preceding code isn’t particularly clean; for example, imagine if there were multiple dependencies from different contexts. The code would quickly become messy and increasingly hard, if not impossible, to unit test (see Chapter 9 for more information on testing).

To solve the problem of the construction/lookup logic in the constructor of an object, we can use dependency injection. We simply pass the object the dependencies it needs to do its work. This makes our code clean, decoupled, and easy to test (see Listing 2-3). Dependency injection is a process where objects specify the dependencies they work with. The IoC container uses that specification; when it constructs an object, it also injects its dependencies. This way our code is cleaner, and we no longer burden our class with construction logic. It is easier to maintain and also easier to unit and/or integration test. Testing is easier because we could inject a stub or mock object to verify the behavior of our object.

Listing 2-3. A MoneyTransferService implementation with constructor-based dependency injection

package com.apress.prospringmvc.moneytransfer.constructor;

// import statements ommitted

public class MoneyTransferServiceImpl implements MoneyTransferService {

    private AccountRepository accountRepository;
    private TransactionRepository transactionRepository;

    public MoneyTransferServiceImpl(AccountRepository accountRepository,
                                    TransactionRepository transactionRepository) {
        super();
        this.accountRepository = accountRepository;
        this.transactionRepository = transactionRepository;
    }
//transfer method omitted, same as Listing 2-1
}

As the name implies, constructor-based dependency injection uses the constructor to inject the dependencies in the object. Listing 2-3 uses constructor-based dependency injection. It has a constructor that takes two objects as arguments: com.apress.prospringmvc.moneytransfer.repository.AccountRepository and com.apress.prospringmvc.moneytransfer.repository.TransactionRepository. When we construct an instance of com.apress.prospringmvc.moneytransfer.constructor .MoneyTransferServiceImpl, we need to hand it the needed dependencies.

Setter-based dependency injection uses a setter method to inject the dependency. The JavaBeans specification defines both setter and getter methods. If we have a method named setAccountService, then we set a property with the name, accountService. The property name is created using the name of the method, minus the “set” and with the first letter lowercased (the full specification can be found in the JavaBeans specification3). Listing 2-4 shows an example of setter-based dependency injection.

Listing 2-4. A MoneyTransferService implementation with setter-based dependency injection

package com.apress.prospringmvc.moneytransfer.setter;

// imports ommitted

public class MoneyTransferServiceImpl implements MoneyTransferService {

    private AccountRepository accountRepository;
    private TransactionRepository transactionRepository;

    public void setAccountRepository(AccountRepository accountRepository) {
        this.accountRepository = accountRepository;
    }

    public void setTransactionRepository(TransactionRepository transactionRepository) {
        this.transactionRepository = transactionRepository;
    }
//transfer method omitted, same as Listing 2-1
}

Finally, there is annotation-based dependency injection (see Listing 2-5). For this to work, we do not need to specify a constructor argument or a setter method to set the dependencies. We begin by defining a class-level field that can hold the dependency. Next, we put an annotation on that field to express our intent to have that dependency injected into our object. Spring accepts several different annotations: @Autowired, @Resource, and @Inject. All these annotations more or less work in the same way. It isn’t within the scope of this book to explain the differences among these annotations in depth, so we suggest the Spring Reference Guide or Pro Spring 3 (Apress, 2012) if you want to learn more. The main difference among them is that the @Autowired annotation is from the Spring Framework, whereas @Resource and @Inject are Java standard annotations.

____________

Listing 2-5. A MoneyTransferService implementation with annotation-based dependency injection

package com.apress.prospringmvc.moneytransfer.annotation;

import org.springframework.beans.factory.annotation.Autowired;

//other imports ommitted

public class MoneyTransferServiceImpl implements MoneyTransferService {

    @Autowired
    private AccountRepository accountRepository;

    @Autowired
    private TransactionRepository transactionRepository;

    //transfer method ommitted, same as listing 2.1
}

Image Note @Autowired and @Inject can be placed on methods and constructors to express dependency injection configuration, even in cases where there are multiple arguments!

Note that interface-based dependency injection isn’t supported by the Spring Framework. This means that we need to specify which concrete implementation to inject for a certain interface.

Image Note  Google Guice4 supports interface-based injection out of the box.

To sum things up, we want to use dependency injection for the following reasons:

  1. Cleaner code
  2. Decoupled code
  3. Easier code testing

The first two reasons make our code easier to maintain. The fact that the code is easier to test should allow us to write unit tests to verify the behavior of our objects—and thus, our application.

After seeing three different approaches to dependency injection, you may wonder which one we should use. That is more or less a philosophical discussion, but here’s a rule of thumb we can use: if a dependency is mandatory for the object to function correctly, we should use constructor- or annotation-based dependency injection. If we use annotation-based dependency injection and the dependency wouldn’t be injected, we would get an exception at the startup of our application. This is because, by default, the dependencies are mandatory when using annotation-based dependency injection. In light of recent developments and additions to Java and JEE, the authors of this book believe that the annotation-based approach is the best way to go. The addition of the javax.annotation.Resouce annotation to Java and JSR-330 (Dependency Injection for Java) indicates quite clearly that that is the future envisioned by the Java Community Process (JCP).

____________

In this book, we will use a Java-based configuration approach wherever possible. If a Java-based configuration option isn’t possible or available, we will fall back to an XML-based configuration. This is the case when we cover web flow. At the time of writing, web flow hasn’t been updated so it can benefit from a Java-based configuration approach.

ApplicationContexts

To be able to do dependency injection in Spring, we need an application context. In Spring, this is an instance of the org.springframework.context.ApplicationContext interface. The application context is responsible for managing the beans defined in it. It also enables more elaborate things like applying AOP to the beans defined in it.

The ApplicationContext interface can be configured in different ways. The most well-known way is to use one or more XML files; however, we could also use a properties file or Java classes. We could even mix-and-match different configuration approaches. In general, it is best to stick with a single approach. Doing so makes it easier to understand and figure out what your configuration is. This also removes the need to hunt down Java, XML, and properties files.

Spring provides several different ApplicationContext implementations (see Figure 2-3). Each of these implementations provides the same features, but differs in how it loads the application context configuration. Figure 2-3 also shows us the org.springframework.web.context.WebApplicationContext interface, which is a specialized version of the ApplicationContext interface used in web environments.

Image

Figure 2-3. Various ApplicationContext implementations (simplified)

As mentioned previously, the different implementations have different configuration mechanisms (i.e., XML or Java). Table 2-2 shows the default configuration options and indicates the resource loading location.

Image

Let’s take a look at a Java-based configuration file, the com.apress.prospringmvc.moneytransfer.annotation.ApplicationContextConfiguration class (see Listing 2-6). There are two annotations used in the class: org.springframework.context.annotation.Configuration and org.springframework.context.annotation.Bean. The first stereotypes our class as a configuration file, while the second indicates that the result of the method is to be used as a factory to create a bean. The name of the bean is, by default, the method name. In Listing 2-6, we have three beans. They are named accountRepository, transactionRepository, and moneyTransferService. We could also explicitly specify a bean name by setting the name attribute on the Bean annotation.

Listing 2-6. The ApplicationContextConfiguration configuration file

package com.apress.prospringmvc.moneytransfer.annotation;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.apress.prospringmvc.moneytransfer.repository.AccountRepository;
import com.apress.prospringmvc.moneytransfer.repository.MapBasedAccountRepository;
import com.apress.prospringmvc.moneytransfer.repository.MapBasedTransactionRepository;
import com.apress.prospringmvc.moneytransfer.repository.TransactionRepository;
import com.apress.prospringmvc.moneytransfer.service.MoneyTransferService;

@Configuration
public class ApplicationContextConfiguration {

    @Bean
    public AccountRepository accountRepository() {
        return new MapBasedAccountRepository();
    }

    @Bean
    public TransactionRepository transactionRepository() {
        return new MapBasedTransactionRepository();
    }

    @Bean
    public MoneyTransferService moneyTransferService() {
        return new MoneyTransferServiceImpl();
    }
}

Image Caution Configuration classes can be abstract; however, they cannot be final. To parse the class, Spring will create a dynamic subclass of the configuration class.

Having a class with only the Configuration annotation isn’t enough. We also need something to bootstrap our application context. We use this to basically launch our application. In the sample project, this is the responsibility of the MoneyTransferSpring class (see Listing 2-7). This class bootstraps our configuration by creating an instance of org.springframework.context.annotation.AnnotationConfigApplicationContext and passes it the class containing our configuration (see Listing 2-6). The process is similar for an XML-based approach, which loads the XML file from the classpath. The result for both is the same. We included both approaches to highlight the differences between the XML- and Java-based configurations; however, nothing changes in the resulting application or its execution.

Listing 2-7. The MoneyTransferSpring class

package com.apress.prospringmvc.moneytransfer.annotation;

import java.math.BigDecimal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.apress.prospringmvc.ApplicationContextLogger;
import com.apress.prospringmvc.moneytransfer.domain.Transaction;
import com.apress.prospringmvc.moneytransfer.service.MoneyTransferService;

public class MoneyTransferSpring {

    private static final Logger logger = LoggerFactory.getLogger(MoneyTransferSpring.class);

public static void main(String[] args) {

        ApplicationContext ctx1 = new AnnotationConfigApplicationContextImage
(ApplicationContextConfiguration.class);
        transfer(ctx1);

        ApplicationContext ctx2 = new ClassPathXmlApplicationContext(
                "/com/apress/prospringmvc/moneytransfer/annotation/application-context.xml");
        transfer(ctx2);

        ApplicationContextLogger.log(ctx1);
        ApplicationContextLogger.log(ctx2);
    }

    private static void transfer(ApplicationContext ctx) {
        MoneyTransferService service = ctx.getBean("moneyTransferService",Image
 MoneyTransferService.class);
        Transaction transaction = service.transfer("123456", "654321", newImage
 BigDecimal("250.00"));
        logger.info("Money Transfered: {}", transaction);
    }
}

Finally, note that application contexts can be in a hierarchy. We can have an application context that serves as a parent for another context (see Figure 2-4). An application context can only have a single parent, but it can have multiple children. Child contexts can access beans defined in the parent context; however, parent beans cannot access beans in the child contexts. For example, if we enable transactions in the parent context, this won’t apply to child contexts (see the “Enabling Features” section later in this chapter).

Image

Figure 2-4. The ApplicationContext Hierarchy

This feature allows us to separate our application beans (e.g., services, repositories, and infrastructure) from our web beans (e.g., request handlers and views). It can be quite useful to have this separation. For example, assume that multiple servlets need to reuse the same application beans. Instead of recreating them for each servlet, we can simply reuse the already existing instances. This can be the case when there is one servlet handling the web UI and another that is handling the web services.

Resource Loading

Table 2-2 provided an overview of the different ApplicationContext implementations and the default resource loading mechanisms. However, this doesn’t mean that we are restricted to loading resources only from the default locations. We also have the option to load resources from specific locations by including the proper prefix (see Table 2-3).

Image

Listing 2-7 shows bootstrapping code that uses an application context implementation that loads from the classpath by default. We could also have used an implementation that loads from the file system by default, but loads from the classpath when the proper prefix is used (see Listing 2-8).

Listing 2-8. Using prefixes to load resources in MoneyTransferSpringFileSystem

package com.apress.prospringmvc.moneytransfer.annotation;

import org.springframework.context.support.FileSystemXmlApplicationContext;

// Other imports ommitted see Listing 2-7

public class MoneyTransferSpringFileSystem {

    private static final Logger logger = LoggerFactory.getLoggerImage
(MoneyTransferSpringFileSystem.class);

public static void main(String[] args) {

        ApplicationContext ctx1 = new AnnotationConfigApplicationContext(                                     ApplicationContextConfiguration.class);
        transfer(ctx1);

        ApplicationContext ctx2 = new FileSystemXmlApplicationContext(
                "classpath:/com/apress/prospringmvc/moneytransfer/annotationImage
/application-context.xml");
        transfer(ctx2);

        ApplicationContextLogger.log(ctx1);
        ApplicationContextLogger.log(ctx2);
    }
  // transfer method ommitted see Listing 2-7
}

In addition to being able to specify where to load files from, we can also use ant-style regular expressions to specify which files to load. An ant-style regular expression is a resource location containing ** and/or * characters. A * character indicates “on the current level” or “a single level,” whereas ** characters indicate “this and all sub levels.” Table 2-4 shows some examples. This technique will only work when dealing with file resources on the classpath or file system; it will not work for web resources or package names.

Image

Component-Scanning

Spring also has something called component-scanning. In short, this feature enables Spring to scan your classpath for classes that are annotated with org.springframework.stereotype.Component (or one of the specialized annotations like org.springframework.stereotype.Service, org.springframework.stereotype.Repository, org.springframework.stereotype.Controller, or org.springframework.context.annotation.Configuration). If we want to enable component-scanning, we need to instruct the application context to do so. The org.springframework.context.annotation.ComponentScan annotation enables us to accomplish that. This annotation needs to be put on our configuration class to enable component-scanning. Listing 2-9 shows the modified configuration class.

Listing 2-9. Implementing component-scanning with ApplicationContextConfiguration

package com.apress.prospringmvc.moneytransfer.scanning;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {
        "com.apress.prospringmvc.moneytransfer.scanning",
        "com.apress.prospringmvc.moneytransfer.repository" })
public class ApplicationContextConfiguration {}

A look at Listing 2-9 reveals that the class has no more content. There are just two annotations. One annotation indicates that this class is used for configuration, while the other enables component-scanning. The component-scan annotation is configured with a package to scan.

Image Caution It is considered bad practice to scan the whole classpath by not specifying a package or to use too broad a package (like com.apress). This can lead to scanning a large part or even all classes, which will severely impact the startup time of your application.

If we’re using component-scanning and a class with the Configuration annotation is found, then it will be used to add more beans to the context. In general, these are beans that cannot be automatically created, like datasources or JMS configuration.

Scopes

By default, all beans in a Spring application context are singletons. As the name implies, there is a single instance of a bean, and it is used for the whole application. This doesn’t typically present a problem because our services and repositories don’t hold state; they simply execute a certain operation and (optionally) return a value.

However, a singleton would be problematic if we wanted to keep state inside our bean. We are developing a web application that we hope will attract thousands of users. If we have a single instance of a bean and all those users operate on the same instance, then the users will see and modify each other’s data or data from several users combined. Obviously, this is not something we want. Fortunately, Spring provides several scopes for beans that we can use to our advantage (see Table 2-5).

Image

Profiles

Spring introduced the concept of profiles in version 3.1. Profiles make it easy to create different configurations of our application for different environments. For instance, we can create separate profiles for our local environment, for testing, and for our deployment to CloudFoundry. Each of these environments requires some environment-specific configuration or beans. One can think of database configuration; messaging solutions; and for testing environments, stubs of certain beans.

To enable a profile, we need to tell the application context which profiles are active. To activate certain profiles, we need to set a system property called spring.profiles.active (in a web environment, this can be a servlet initialization parameter or web context parameter). This is a comma-separated string containing the names of the active profiles. If we now add some (in this case static inner) classes (see Listing 2-10) with the org.springframework.context.annotation.Configuration and org.springframework.context.annotation.Profile annotations, then only the classes that match one of the active profiles will be processed. All other classes will be ignored.

Listing 2-10. ApplicationContextConfiguration with profiles

package com.apress.prospringmvc.moneytransfer.annotation.profiles;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

import com.apress.prospringmvc.moneytransfer.annotation.MoneyTransferServiceImpl;
import com.apress.prospringmvc.moneytransfer.repository.AccountRepository;
import com.apress.prospringmvc.moneytransfer.repository.MapBasedAccountRepository;
import com.apress.prospringmvc.moneytransfer.repository.MapBasedTransactionRepository;
import com.apress.prospringmvc.moneytransfer.repository.TransactionRepository;
import com.apress.prospringmvc.moneytransfer.service.MoneyTransferService;

@Configuration
public class ApplicationContextConfiguration {

    @Bean
    public AccountRepository accountRepository() {
        return new MapBasedAccountRepository();
    }

    @Bean
    public MoneyTransferService moneyTransferService() {
        return new MoneyTransferServiceImpl();
    }

    @Configuration
    @Profile(value = "test")
    public static class TestContextConfiguration {
        @Bean
        public TransactionRepository transactionRepository() {
            return new StubTransactionRepository();
        }
    }

    @Configuration
    @Profile(value = "local")
    public static class LocalContextConfiguration {

        @Bean
        public TransactionRepository transactionRepository() {

            return new MapBasedTransactionRepository();
        }
    }
}

Listing 2-11 shows some example bootstrap code. In general, we will not be setting the active profiles from our bootstrap code. Instead, we will set up our environment using a combination of system variables. This enables us to leave our application unchanged, but still have the flexibility to change our runtime configuration.

Listing 2-11. MoneyTransferSpring with profiles

package com.apress.prospringmvc.moneytransfer.annotation.profiles;

import java.math.BigDecimal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.apress.prospringmvc.ApplicationContextLogger;
import com.apress.prospringmvc.moneytransfer.domain.Transaction;
import com.apress.prospringmvc.moneytransfer.service.MoneyTransferService;

public class MoneyTransferSpring {

    private static final Logger logger = LoggerFactory.getLogger(MoneyTransferSpring.class);

    public static void main(String[] args) {

        System.setProperty("spring.profiles.active", "test");

        AnnotationConfigApplicationContext ctx1 = new AnnotationConfigApplicationContext(
                ApplicationContextConfiguration.class);
        transfer(ctx1);
        ApplicationContextLogger.log(ctx1);

        ApplicationContext ctx2 = new ClassPathXmlApplicationContext(
                "/com/apress/prospringmvc/moneytransfer/annotation/profilesImage
/application-context.xml");
        transfer(ctx2);

        ApplicationContextLogger.log(ctx2);

        System.setProperty("spring.profiles.active", "local");
        AnnotationConfigApplicationContext ctx3 = new AnnotationConfigApplicationContext(
                ApplicationContextConfiguration.class);
        transfer(ctx3);
        ApplicationContextLogger.log(ctx3);


        ApplicationContext ctx4 = new ClassPathXmlApplicationContext(
                "/com/apress/prospringmvc/moneytransfer/annotation/profilesImage
/application-context.xml");
        transfer(ctx4);
        ApplicationContextLogger.log(ctx4);

    }

    private static void transfer(ApplicationContext ctx) {
        MoneyTransferService service = ctx.getBean("moneyTransferService",Image
 MoneyTransferService.class);
        Transaction transaction = service.transfer("123456", "654321", newImage
 BigDecimal("250.00"));
        logger.info("Money Transfered: {}", transaction);
    }
}

You might wonder why we should use profiles, anyway. One reason is that it allows for flexible configurations. This means that our entire configuration is under version control and in the same source code, instead of being spread out over different servers, workstations, and so on. Of course, we can still load additional files containing some properties (like usernames and passwords). This can prove useful if a company’s security policy won’t allow us to put these properties into version control. We are going to use profiles extensively when we cover testing and deploying to the cloud because the two tasks require different configurations for the datasource.

Enabling Features

The Spring Framework gives us a lot more flexibility than just dependency injection; it also provides a lot of different features we can enable. We can enable these features using annotations (see Table 2-6). Note that we won’t use all of the annotations mentioned in this table; however, our sample application will use transactions, and we will use some AOP. The largest part of this book is about the features provided by the org.springframework.web.servlet.config.annotation.EnableWebMvc annotation.

Image

Image

Image Note  For more information on these features, we recommend that you examine the Java documentation of the different annotations, as well as the dedicated reference guide chapters.

Aspect-Oriented Programming

To enable the features listed in Table 2-4, Spring uses aspect-oriented programming (AOP). AOP is another way of thinking about the structure of software. It enables you to modularize things like transaction management or performance logging, features that span multiple types and objects (crosscutting concerns). In AOP, there are a couple important concepts to keep in mind (see Table 2-7).

Image

Now let’s take a look at transaction management and how Spring uses AOP to apply transactions around methods. The transaction advice, or interceptor, is org.springframework.transaction.interceptor.TransactionInterceptor. This advice is placed around methods with the org.springframework.transaction.annotation.Transactional annotation. To do this, Spring creates a wrapper around the actual object, which is known as a proxy (see Figure 2-5). A proxy acts like an enclosing object, but it allows (dynamic) behavior to be added (in this case the transactionality of the method).

Image

Figure 2-5. A proxy method invocation

The org.springframework.transaction.annotation.EnableTransactionManagement annotation will register the beans containing the pointcut (acting on the org.springframework.transaction.annotation.Transactional annotation). At this point, the interceptor is ready for us to use. The other annotations for enabling features work in a similar way; they register beans to enable the desired feature, including AOP (and thus proxy creation) for most features.

Web Applications

So how does all the aforementioned technology apply to a web application? For example, how do application contexts play a role? And what about all the other things mentioned?

When developing a web application, we have our actual business logic (e.g., our services, repositories, and infrastructure information), and we have our web-based beans. These things should be separated, so we need to have multiple application contexts and have a relationship between them.

We also need code that bootstraps our application, or else nothing will happen. In this chapter’s examples, we used a class MoneyTransferSpring with a main method to start the application context. This is not something we can do in a web environment. Spring ships with two components that can bootstrap an application: org.springframework.web.servlet.DispatcherServlet and org.springframework.web.context.ContextLoaderListener. Both components will bootstrap and configure an application context.

Let’s take a look at the class that configures DispatcherServlet. This is the com.apress.prospringmvc.bookstore.web.BookstoreWebApplicationInitializer class (see Listing 2-12). This class is detected by our Servlet 3.0 container, and it’s used to initialize our application (see Chapter 3 for more information on this topic). We create the DispatcherServlet and pass it org.springframework.web.context.support.AnnotationConfigWebApplicationContext. Next, we map the servlet to everything (the “/”) and tell it to load on startup.

Listing 2-12. The BookstoreWebApplicationInitializer class

package com.apress.prospringmvc.bookstore.web;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import com.apress.prospringmvc.bookstore.web.config.WebMvcContextConfiguration;

public class BookstoreWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(final ServletContext servletContext) throws ServletException {
        registerDispatcherServlet(servletContext);
    }

    private void registerDispatcherServlet(final ServletContext servletContext) {
        WebApplicationContext dispatcherContext = createContextImage

(WebMvcContextConfiguration.class);
        DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext);
        ServletRegistration.Dynamic dispatcher = servletContext.addServletImage
("dispatcher", dispatcherServlet);
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }

private WebApplicationContext createContext(final Class<?>... annotatedClasses) {
        AnnotationConfigWebApplicationContext context = newImage
 AnnotationConfigWebApplicationContext();
        context.register(annotatedClasses);
        context.getEnvironment().setActiveProfiles("local");
        return context;
    }
}

Let’s make things a bit more interesting by adding a ContextLoaderListener class, so that we can have a parent context and a child context (see Listing 2-13). The newly registered listener will use com.apress.prospringmvc.bookstore.config.InfrastructureContextConfiguration (see Listing 2-14) to determine which beans to load. The already configured DispatcherServlet automatically detects the application context loaded by ContextLoaderListener.

Listing 2-13. The modifcation for the BookstoreWebApplicationInitializer class

package com.apress.prospringmvc.bookstore.web;

import org.springframework.web.context.ContextLoaderListener;
import com.apress.prospringmvc.bookstore.config.InfrastructureContextConfiguration;

// other imports ommitted see Listing 2-12

public class BookstoreWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(final ServletContext servletContext) throws ServletException {
        registerListener(servletContext);
        registerDispatcherServlet(servletContext);
    }

// registerDispatcherServlet method ommitted see Listing 2-12

    private void registerListener(final ServletContext servletContext) {
        AnnotationConfigWebApplicationContext rootContext =Image
 createContext(InfrastructureContextConfiguration.class);
        servletContext.addListener(new ContextLoaderListener(rootContext));
    }

private AnnotationConfigWebApplicationContext createContext(final Class<?>...Image
 annotatedClasses) {
        AnnotationConfigWebApplicationContext context = newImage
 AnnotationConfigWebApplicationContext();

        context.getEnvironment().setActiveProfiles("local");
        context.register(annotatedClasses);
        return context;
    }

}

Listing 2-14 is our main application context. It contains the configuration for our services and repositories. This listing also shows our JPA entity manager, including its annotation-based transaction support.

Listing 2-14. The InfrastructureContextConfiguration source file

package com.apress.prospringmvc.bookstore.config;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = {       "com.apress.prospringmvc.bookstore.service",
        "com.apress.prospringmvc.bookstore.repository",         "com.apress.prospringmvc.bookstore.domain.support" })
public class InfrastructureContextConfiguration {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private EntityManagerFactory entityManagerFactory;

    @Bean
    public FactoryBean<EntityManagerFactory> entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean emfb;         emfb = new LocalContainerEntityManagerFactoryBean();
        emfb.setDataSource(this.dataSource);
        emfb.setJpaVendorAdapter(jpaVendorAdapter());

        return emfb;
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        return new HibernateJpaVendorAdapter();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(this.entityManagerFactory);
        txManager.setDataSource(this.dataSource);
        return txManager;
    }

    @Bean
    public DataSource dataSource() {
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        builder.setType(EmbeddedDatabaseType.H2);
        return builder.build();
    }
}

Summary

In this chapter, we covered the bare basics of Spring Core. We reviewed the concept of dependency injection and briefly covered three different versions of dependency injection. We also covered constructor-based, setter-based, and annotation-based dependency injection.

Next, we stepped into the Spring world and examined org.springframework.context.ApplicationContexts, including the role they play in our application. We also explained the different types of application contexts (e.g., XML or Java based) and the resource loading in each of them. In our web environment, we use a specialized version of an application context in an implementation of the org.springframework.web.context.WebApplicationContext interface. We also covered how, by default, beans in an application context are singleton scoped. Fortunately, Spring provides us with additional scopes, such as request, session, globalSession, prototype, application, and thread.

To be able to use different configurations in different environments, Spring also includes profiles. We briefly explained both how to enable profiles and how to use them. We will use profiles in our sample application when we test it (see Chapter 9) and when we deploy it to Cloud Foundry (see Appendix A).

We also delved into the way several enabling annotations are required for Spring to enable certain features. These annotations register additional beans in the application context that enable the desired feature. Most of these features rely on AOP to be enabled (e.g., to do declarative transaction management). Spring creates proxies to apply AOP to beans registered in our application contexts.

In the next chapter, we will look at the architecture of an MVC web application, the different layers, and what roles they play in our application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset