Section 6.1. Building a Service

team bbl


6.1. Building a Service

The core functions of your application are roughly complete, but it's going to be hard to trace what changes a user made, and when. In this example, you'll build an audit trail that records a log record whenever someone takes an action that changes the database. Rather than add the same code in many different places, you'll build a simple Spring service to do the job. You'll focus on the Hibernate implementation that you built earlier.

Object-oriented languages handle some problems pretty well, but they don't handle crosscutting concerns, common in enterprise developments, very well. Figure 6-1 shows a method with some common enterprise services that crosscut many methods in DAO and façade layers.

Figure 6-1. Some classic enterprise crosscutting concerns


To handle crosscutting concerns, you might decide to use a container. Most containers accept only components that match their specification, and provide services to components once they're in the container. Heavyweight container architectures, like EJB 1.x and 2.x, handle crosscutting concerns, but they force you to write code that depends on your given container. You can't take the code out of the container and expect it to run, and since the container takes too long to start, the result is difficult to test.

Lightweight containers that use AOP technologies accept components too, but the component is a simple POJO. You can then use AOP to attach services to the POJO. We'll get into how this works later in the chapter, but for now, think of this feature as the ability to add declarative services to POJO. In Spring, you implement declarative services with configuration rather than code, so you can change services on the fly through changes in the context.

6.1.1. How do I do that?

The interceptor strategy uses three objects: the target (our façade), a proxy object that Spring creates for you, and an interceptor, which you'll build. Essentially, the proxy imitates the targetwherever you would use an instance of the target object, Spring will use the proxy instead. The proxy will pass all calls to the object through a series of interceptors that you'll configure in the context. Depending on the type of interceptors, the call might pass through the interceptor before reaching the target, on the way back from the target, or both.

You've got to do three things:

  1. Create your service, which we'll call an interceptor. Another word for interceptors is advice.

  2. Configure the beans: the interceptor and the target object.

  3. Configure the proxyidentify the proxy, the target object, and the methods that will use our service.

To build advice, you'll simply implement an interface. Think of advice as something that will happen at some event in a program's execution. Spring has four types of advice:


Before advice

Spring fires this type of advice before it invokes a method that you specify, called the target method. This type of advice implements the MethodBeforeAdvice interface.


After Returning advice

Spring fires this type of advice after returning from your target method. After Returning advice implements the AfterReturningAdvice interface.


Throws advice

Spring fires this type of advice when your target method throws an exception. This type of advice implements the ThrowsAdvice interface.


Around advice

Spring fires this type of advice before a method, and allows you to choose whether to invoke the target method. After the target method returns, you can add additional code. This is also called an interceptor.

In general, you should use the simplest type of advice that will solve your problem. For this example, you'll use before advice, and you'll build on the Hibernate interface. The interceptor will implement the MethodBeforeAdvice interface. It will do the logging. Don't worry about how it gets invoked just yet. Example 6-1 gives the advice.

Example 6-1. LoggingBefore.java
public class LoggingBefore implements MethodBeforeAdvice {     private SessionFactory factory;     public SessionFactory getFactory( ) {         return factory;     }     public void setFactory(SessionFactory factory) {         this.factory = factory;     }     public void before(Method method, Object[] objects, Object o)             throws Throwable {         Session s = null;         LogEvent le = new LogEvent(method.getName( ), new Date( ));         try {             s = factory.openSession( );             s.save(le);         } catch (Exception ex) {             //log the exception         } finally {             s.close( );         }     } }

For now, you can manually invoke it in a test case. In this case, you can simply count the number of events that exist in the database prior to running the advice, then compare that to the number of events in the database after running it. For the test in Example 6-2, it doesn't matter which method is being logged, just that the logger is activated.

Example 6-2. ControllerTest.java
public void testLocal( ) throws Exception {     LoggingBefore lb = new LoggingBefore( );     SessionFactory factory =             (SessionFactory)ctx.getBean("sessionFactory");     // getCurEventsCount( ) is a private utility method that     // gets the current number of log events in the database     int initialCount = getCurEventsCount( );     lb.setFactory(factory);     try {           lb.before((Method)this.getClass( ).getMethods( )[0], null, null);     } catch (Throwable t) {            fail(t.getMessage( ));     }     int afterCount = getCurEventsCount( );     assertEquals("Should add one event to log",             initialCount, afterCount - 1); }

6.1.2. What just happened?

You've just built a service. Unlike other container architectures, Spring does not define the complete package of services that components in the container can use. The services are ideal for our purposes:

  • The clean programming model defines exactly how a service must be packaged.

  • The services strategy is minimal, requiring very little of the service builder.

  • The services are easy to test, since they can run outside of the container.

  • The services can be used elsewhere; they are compatible with a standard called the Aspect Alliance.

Of course, right now, the service doesn't do anything. You need to attach it to something real.

    team bbl



    Spring. A developer's Notebook
    Spring: A Developers Notebook
    ISBN: 0596009100
    EAN: 2147483647
    Year: 2005
    Pages: 90

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net