Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Dependency injection in Apache Geronimo, Part 2: The next generation

Neal Ford, Application Architect, ThoughtWorks Inc.
Neal Ford
Neal Ford is an application architect at ThoughtWorks, a global IT consultancy with an exclusive focus on end-to-end software development and delivery. He is also the designer and developer of applications, instructional materials, magazine articles, courseware, video/DVD presentations, and author of the books Developing with Delphi: Object-Oriented Techniques, JBuilder 3 Unleashed, and Art of Java Web Development. His primary consulting focus is the building of large-scale enterprise applications. He is also an internationally acclaimed speaker, having spoken at numerous developers conferences worldwide. Check out his Web site at http://www.nealford.com. He welcomes feedback and can be reached at nford@thoughtworks.com.

Summary:  Continue the exploration of dependency injection (DI) in Apache Geronimo that began in Part 1 of this two-part article series. Get an overview of the Geronimo architecture, discover how DI impacts Geronimo, and learn how to use the DI features in Geronimo to change the way you write code. This article also covers how GBeans work and how Geronimo handles both constructor and setter injection.

View more content in this series

Date:  14 Feb 2006
Level:  Intermediate
Also available in:   Japanese

Activity:  7894 views
Comments:  

The first article of this series discussed how DI works at the core level, separate from the particular implementation found in Geronimo. That article demonstrated why DI is an effective way to handle coupling points between classes that contain references to each other. This article expands on those ideas and puts them into the context of Geronimo. Along the way, you'll learn about uses for DI and understand how Geronimo implements it (both constructor and setter).

DI has real-world benefits for decoupling code. Here are a few examples. Say you have a human resources department that bases pay raises on the customer for which an employee works. To handle this, you implement customers as an abstract base class with many different subclasses (for example, financial, manufacturing, and so on). When you write the Human Resources class, you don't know which type of customer you'll process for a given employee. Thus, the Human Resources class depends on a specific implementation of a customer class. With DI, you can allow the container to inject the appropriate customer class either by configuring the container or implementing the injection in the code.

The second, and more typical, example is the use of a persistence framework. Your container knows that it wants to use a persistence framework (such as Hibernate, Java Data Objects [JDO], or iBATIS) and that each framework offers a common set of functions. Using DI, the container can inject the code for a particular persistence framework using container configuration. Having persistence this loosely coupled allows you to more easily switch one framework for another.

Geronimo's architecture

Geronimo isn't built like most traditional Java™ 2 Platform, Enterprise Edition (J2EE) application servers where the classes that make up the application server are tightly bound into the application server's code base. Geronimo defines a basic kernel where you can plug in desired behaviors. In fact, there is nothing that specifically makes Geronimo a J2EE application server if you haven't plugged in the components that define the behaviors from J2EE. Geronimo is a loose federation of components called GBeans, which are registered with the base kernel as they are deployed, and define the capabilities of the application server. The GBeans, in turn, may have dependencies on one another. For example, a persistence framework bean may rely on some facilities defined by a file management bean. Figure 1 shows this conceptual definition of Geronimo.


Figure 1. The architecture of Geronimo
architecture diagram

The arrows in Figure 1 imply references to other beans. Everything in Geronimo is a GBean: containers, connectors, adapters, applications, and so on. Even the applications you create and deploy are converted into GBeans when they are deployed in Geronimo. Geronimo's use of GBean components results in the following:

  • All parts of the container (whether core J2EE behavior or your applications) behave consistently.
  • It's easy to extend Geronimo by deploying new GBeans.
  • You can control the dependencies between components, because they all act the same.
  • GBeans contain state within the container (either persistent, via serialized GBeans, or nonpersistent).
  • GBeans contain logic that defines how they respond to events.

Ultimately, defining Geronimo in terms of simple interactions between simple components makes the container both more robust and easy to modify. To understand Geronimo, you must understand GBeans.


GBeans

GBean components adhere to a particular life cycle as the kernel creates them, performs DI on them, calls their methods, and sends events to them. The items of interest in this article are the creation and destruction life cycle events and DI.

GBean life cycle

To register themselves as interested in participating in the normal life cycle operations, GBeans implement the GBeanLifecycle interface. This interface defines a contract with three methods, as shown in Listing 1.


Listing 1. The GBeanLifecycle methods
public class Customer implements GBeanLifecycle {
    public void doStart() throws Exception {

    }

    public void doStop() throws Exception {

    }

    public void doFail() {

    }
}

As you can discern from their names, the methods in Listing 1 are callback methods that the container calls at the life cycle stages for your GBean. These methods allow you to plug your GBean in to the kernel and receive notifications of interesting events.

GBean information

To use your GBean, the kernel must be able to ask it what it can do. This information resides in a BeanInfo class, which is typically provided by your bean when the bean's class is loaded via a static initializer. Listing 2 shows a typical static initializer.


Listing 2. The static initializer for GBean initialization
private static final GBeanInfo GBEAN_INFO;
    static {
        GBeanInfoBuilder infoFactory = new GBeanInfoBuilder(
                Customer.class.getName(),
                        Customer.class);

        // attributes
        infoFactory.addAttribute("name", String.class, true);
        infoFactory.addAttribute("salary", double.class, true);

        infoFactory.addOperation("setName",
                new Class[]{String.class});
        infoFactory.addOperation("getName");
        infoFactory.addOperation("setSalary", 
                new Class[] {double.class});
        infoFactory.addOperation("getSalary");

        GBEAN_INFO = infoFactory.getBeanInfo();
    }

    public static GBeanInfo getGBeanInfo() {
        return GBEAN_INFO;
    }

The static initializer in Listing 2 shows the registration process for a Customer class that contains two properties: name and salary. The infoFactory class has methods that allow your class to register interesting attributes and operations. Notice that you're never required to register all the public properties or methods of the class -- you can choose which ones you want to expose to the container. The class includes a static method, getGBeanInfo(), to return the GBean information created in the static initializer.

The initialization code in Listing 2 is part of a class that uses setter injection for DI. In the first article of this series, I defined setter injection as the container (in this case, Geronimo) calling a setXXX() method on your code to inject some dependent property value or class. To facilitate this setter injection, I've registered set methods for both my properties. Listing 3 shows the complete listing for the Customer class.


Listing 3. The setter-injectable Customer class
package com.nealford.articles.di_geronimo;

import org.apache.geronimo.gbean.GBeanLifecycle;
import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.geronimo.gbean.GBeanInfoBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Customer implements GBeanLifecycle {
    private static Log log = LogFactory.getLog(Customer.class);
    private String name;
    private double salary;

    private static final GBeanInfo GBEAN_INFO;
    static {
        GBeanInfoBuilder infoFactory = new GBeanInfoBuilder(
                Customer.class.getName(),
                        Customer.class);

        // attributes
        infoFactory.addAttribute("name", String.class, true);
        infoFactory.addAttribute("salary", double.class, true);

        infoFactory.addOperation("setName",
                new Class[]{String.class});
        infoFactory.addOperation("getName");
        infoFactory.addOperation("setSalary", 
                new Class[] {double.class});
        infoFactory.addOperation("getSalary");

        GBEAN_INFO = infoFactory.getBeanInfo();
    }

    public void doStart() throws Exception {
        log.info("Starting Customer GBean");
    }

    public void doStop() throws Exception {
        log.info("Stopping Customer GBean");
    }

    public void doFail() {
        log.info("customer GBean failure!");
    }

    public static GBeanInfo getGBeanInfo() {
        return GBEAN_INFO;
    }

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(final double salary) {
        this.salary = salary;
    }

}


Starting and stopping GBeans

One more life cycle topic deserves attention before moving on to more DI: starting and stopping beans. If you want to load a GBean programmatically, you can. Listing 4 shows how to programmatically load a GBean whose name is defined via a Java Management Extension (JMX) interface.


Listing 4. Manually handling GBean's life cycle
GBeanMBean gmb = new GBeanMBean(Customer.getGBeanInfo());
gmb.setAttribute("name","Homer");
gmb.setAttribute("salary", 2500.00);
ObjectName myGbeanName = ObjectName.newInstance(
        "Geronimo.my:Customer=customer1");
kernel.loadGBean(myGbeanName, gmb);
kernel.startGBean(myGbeanName);

//do some work with Customers

kernel.stopGBean(myGbeanName);
kernel.unloadGBean(myGbeanName);

Of course, you don't have to do this for most GBeans you create -- the container loads them for you based on the deployment plan you provide. As you can see, nothing prevents you from loading, starting, and stopping your own GBean references in your code.

GBean states

GBeans, like other object references, hold state information in the form of either attributes or references to other GBeans. An attribute for a GBean is a value held by one of the properties of the GBean object. In other words, an attribute corresponds to a combination of an accessor/mutator pair of methods in the GBean class (for example, getter and setter). A reference is like an object reference in a normal JavaBean, only in this case it explicitly refers to another GBean. References are covered in more detail later.

Attributes are either persistent or nonpersistent. Persistent attributes retain their values between instances of the GBean. They are stored permanently by serializing the GBean or by another mechanism, such as storing them in a database. Nonpersistent attributes retain their value during the life of the GBean instance and disappear when the instance goes away.

Magic attributes

The Geronimo architecture defines special types of attributes called magic attributes. The values loaded for magic attributes are dependent on the environment in which the GBean is loaded. For example, the magic attribute kernel refers to the kernel, which is automatically injected into the class by the framework. Similarly, the ClassLoader attributes inject the current class loader, and the ObjectName attributes inject the current name into the GBean. Listing 4 shows the use of the kernel attribute that is automatically injected into the class that defines the life cycle code. A complete list of all magic attributes resides in the GBeanMBean class in the kernel. Magic attributes are not persistent, because they are bound with the startup environment.


DI in GBeans

The customer class shown in Listing 3 is a good example of a class that uses setter injection. Next, you see an example of constructor injection and how Geronimo's deployment plans define how the container injects code. As explained in the first article of this series, constructor injection implies that the framework supplies constructor parameters required by the class upon instantiation.

Single references

Many proponents of DI prefer constructor injection, because it means that the injected class never exists in a state where its dependencies aren't present. Listing 5 shows a GBean that's defined to use constructor injection to provide a Customer reference.


Listing 5. The constructor-injectable Human Resources class
package com.nealford.articles.di_geronimo;

import org.apache.geronimo.gbean.GBeanLifecycle;
import org.apache.geronimo.gbean.GBeanInfoBuilder;
import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class HumanResources implements GBeanLifecycle {
    private static Log log = LogFactory.getLog(HumanResources.class);
    private Customer customer1;
    private static final GBeanInfo GBEAN_INFO;

    static {
        GBeanInfoBuilder infoFactory = new GBeanInfoBuilder(
                "HumanResources",
                 HumanResources.class);

        // attributes
        infoFactory.addReference("Customer", Customer.class);

        // operations
        infoFactory.setConstructor(new String[]{"Customer1"});
        GBEAN_INFO = infoFactory.getBeanInfo();
    }

    public HumanResources(Customer customer1) {
        this.customer1 = customer1;
    }


    public void doStart() throws Exception {
        log.info("Starting HR GBean");
    }

    public void doStop() throws Exception {
        log.info("Stopping HR GBean");
    }

    public void doFail() {
        log.info("HR GBean failure!");
    }
}


The GBean in Listing 5 looks similar in format to the Customer GBean defined in Listing 3. However, notice that this class does not have any get or set methods. Instead, the lone constructor is designed to accept a Customer object. Also, in the attributes section, I define a reference to the Customer class. The reference established in Listing 5 is an example of the references between GBeans represented by the arrows in Figure 1.

The creator of this GBean (that is, whoever fires the constructor on this class) must provide a reference to a Customer object. In most cases, the constructing entity is the Geronimo container itself. The next section shows you how the constructing entity knows to provide a customer and which customer to provide.

Deployment plans

Information about references and dependencies in Geronimo resides in deployment plans. Deployment plans are XML documents that define which GBeans are constructed and resolve their dependencies. The deployment plan for both the Customer and Human Resources classes appears in Listing 6.


Listing 6. Deployment plan
<?xml version="1.0" encoding="UTF-8"?>
<configuration
    xmlns="http://geronimo.apache.org/xml/ns/deployment"
    configId="test/HRPlan">
    
    
    <gbean name="test:Customer=customer1" class="Customer">
        <attribute name="name">Homer</attribute>
        <attribute name="salary">2500.00</attribute>
        
    </gbean>
    
    <gbean name="test:HR=HumanResources" class="HumanResources">
        <reference name="customer1">
            test:Customer=customer1
        </reference> 
        </gbean>
</configuration>

The deployment plan defines both types of GBeans. For the Customer GBean, it defines values to be injected into the attributes of the Customer instance. For the HumanResources class, it creates the reference Geronimo needs to inject the Customer instance into the HumanResources class as it is instantiated.

This example is clearly a simple one -- two GBeans, each using a different type of DI. Frequently, setting up one-to-one mappings between dependencies is more complex than this. For example, what if there are a variety of different Customer subclasses, and the environment needs to decide which one to inject in a given situation?

Reference patterns

Geronimo uses reference patterns to handle multiple dependency situations. Using a reference pattern, you can specify a family of legal dependency types that can be injected. You create reference patterns using wildcards in the name of the class to inject, and they may appear either in code or in deployment plans. The following code shows how to create a reference that allows any customer subclass to be injected:

bean.setReferencePattern("Geronimo.my:*");



Summary

This series of articles demonstrates what a powerful code reuse mechanism DI is. Geronimo is the first J2EE server written entirely as a DI container. This allows a tremendous level of flexibility in building components designed for Geronimo. DI is a code reuse technique that has existed for years, but only now are programmers starting to reap the real benefits of the extremely loose coupling that it provides.


Resources

Learn

Get products and technologies

Discuss

About the author

Neal Ford

Neal Ford is an application architect at ThoughtWorks, a global IT consultancy with an exclusive focus on end-to-end software development and delivery. He is also the designer and developer of applications, instructional materials, magazine articles, courseware, video/DVD presentations, and author of the books Developing with Delphi: Object-Oriented Techniques, JBuilder 3 Unleashed, and Art of Java Web Development. His primary consulting focus is the building of large-scale enterprise applications. He is also an internationally acclaimed speaker, having spoken at numerous developers conferences worldwide. Check out his Web site at http://www.nealford.com. He welcomes feedback and can be reached at nford@thoughtworks.com.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source, Java technology, WebSphere
ArticleID=103559
ArticleTitle=Dependency injection in Apache Geronimo, Part 2: The next generation
publish-date=02142006
author1-email=nford@thoughtworks.com
author1-email-cc=nford@thoughtworks.com

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers