[原创]Spring: A Developer's Notebook笔记和小结(15)

/**
作者:Willpower
来源:Rifoo Technology(
http://www.rifoo.com
时间:2006-02-23
备注:转载请保留以上声明
**/

本书的应用程序的核心功能已经粗略的完成了,但是很难做到跟踪用户改动了什么数据以及什么时候改动的。本节的例子就是要建立一个审计跟踪来记录日志,当有人更改数据库的时候就会将其动作跟踪下来,并记录到日志文件中。我们不用在很多不同的地方添加冗余的相同的代码,我们之需要建立一个简单Spring service就可以完成这个任务了。我们将把焦点放在上一节完成的Hibernate实现上。

面向对象的语言能够很好的处理很多问题,但是它们不能很好的处理crosscutting concerns(在AOP里,是术语“横切关注点”的意思),但这个概念在企业的应用中是常见的。

下图是一个普通的企业服务方法在DAO和facade层里横切(crosscut )的示意图。




要处理横切关注点,可能大家决定使用一个容器来做。大多数容器只接受那些满足它们规范的组件,并且一旦这些组件被容器所接纳,那么容器就会给这些组件提供相应服务。 重量级的容器架构比如EJB1.X和2.X,都能够处理横切关注点,但是它们使得我们写出很多跟容器有强烈依赖关系的代码。离开了这个容器,我们就无法运行程序了。因为容器启动需要很久的时间来等待,因此测试起来也十分麻烦。

使用AOP技术的轻量级容器也能够接受组件,但是这个组件仅仅只是一个简单的POJO。我们可以使用AOP技术将服务(services)和POJO绑在一起。

拦截器技术使用到了三个对象:目标对象(target),一个由Spring为我们创建的代理对象(proxy object),和一个我们自己创建的拦截器对象(interceptor)。实际上,当我们要使用一个目标对象的实例时,这时候Spring会使用代理对象来代替目标对象。 然后代理对象要通过一系列我们在上下文中配置好的拦截器来调用相应的目标对象。按照不同的拦截器的类型,这个调用可能会在到达目标对象之前发生,或者是在到达目标对象之后发生,也可能是之前之后都会发生调用。

为此,我们需要做三件事情:
1 创建service,这个service我们将称呼为拦截器。另一个拦截器的叫法叫做advice。
2 配置以下bean:拦截器和目标对象。
3 配置代理对象proxy,标识proxy,目标对象和使用service的方法


要创建一个advice,我们只需要简单的实现一个接口。
在Spring中支持Around,Before,After returning和Throws四种Advice:

Before advice

在指定的目标方法之前会调用。 它实现了MethodBeforeAdvice接口。

After Returning advice

在指定的目标方法返回之后调用。它实现了AfterReturningAdvice接口。

Throws advice

当指定的目标方法抛出异常时调用。它实现了ThrowsAdvice接口。

Around advice


在指定的目标方法之前调用,并可以选择是否触发目标方法。在目标方法触发并返回后,可以添加额外的代码。 这个也被称为拦截器(interceptor)。

我们可以使用最简单的advice来解决我们的问题。比如,我们使用before advice,并且是建立在Hibernate接口上的。拦截器会实现MethodBeforeAdvice接口,它会做log方面的处理工作,即针对每次发生的事件做一些日志记录。下面的例子给出了这个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( );
    }
  }
}


现在,我们可以手工写一个测试例子来调用它。假设在数据库有表记录着log事件的记录数,我们只需要比较调用这个before advice之前的数量和调用完以后的数量就可以了。这里不涉及到针对某个具体的方法而做log处理,只是说明了某个操作过程结束后logger被激活并被调用过。

Example 6-2. ControllerTest.java
public void testLocal( ) throws Exception {
  LoggingBefore lb = new LoggingBefore( );
  SessionFactory factory =
      (SessionFactory)ctx.getBean("sessionFactory");

  // getCurEventsCount( ) 是一个私有方法,它负责从数据库种获取当前log事件的总个数
  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);
}


总结:本节我们仅仅只是建立了一个service。

service这种策略是代价微小的,它不需要大量的builder。

service是很容易测试的,因为它能够在容器外运行。

service能够被用到其他地方,只要和Aspect Alliance标准兼容的环境都可以使用。

当然了,目前来说,我们完成的这个service没有做任何事情。.我们需要将它依附在某些真实的东西上才能体现它的作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值