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

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

上一节我们完成了一个审计服务来帮助我们跟踪程序的改变情况。现在,我们将把这个服务加到我们的代码里,在我们的实验里配置该服务。

那么我们如何去做呢?
拦截器策略使用了三个对象:目标(这里是我们的facade),Spring为我们创建的代理对象(proxy object)和一个我们自己创建的拦截器(interceptor)。我们要做三件事情:

术语说明一下:
通知(Advice):如何将before通知、afterReturning通知和afterThrowing通知声明为bean。
切入点(Pointcut):如何声明静态切入点逻辑以将XML Spring Bean Configuration文件中的所有内容联系在一起。
Advisor:关联切入点定义与通知bean的方式。

1 配置通知(advice)对象

2 配置advisor对象,包括目标对象,目标方法和通知对象

3 配置目标对象(target object)

4 配置使用这个advise的代理对象

目标对象现在已经存在:就是我们前面完成的facade类。proxy代理对象也存在,因为我们使用它来完成事务。因此,我们只需要配置通知(advice)对象, 并将它加到我们的proxy中。参看下面的范例代码:

Example 6-3. RentABike-servlet.xml
<beans>  
  <bean id="transactionManager"
  class="org.springframework.orm.hibernate.HibernateTransactionManager">
    <property name="sessionFactory">
      <ref local="sessionFactory"/>
    </property>
  </bean>

<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
    <property name="transactionManager">
      <ref local="transactionManager"/>
    </property>
    <property name="transactionAttributeSource">
      <value>
        com.springbook.HibernateRentABike.save*=PROPAGATION_REQUIRED
      </value>
    </property>
  </bean>

<bean id="loggingBeforeInterceptor"
    class="com.springbook.interceptors.LoggingBefore">
    <property name="factory">
      <ref local="sessionFactory"/>
    </property>
  </bean>


  <bean id="rentaBikeTarget" class="com.springbook.HibRentABike">
    <property name="storeName">
      <value>Bruce's Bikes</value>
    </property>
    <property name="sessionFactory">
      <ref local="sessionFactory"/>
    </property>
  </bean>

<bean id="rentaBike"
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces">
      <value>com.springbook.RentABike</value>
    </property>
    <property name="interceptorNames">
      <list>
        <value>loggingBeforeInterceptor</value>
        <value>transactionInterceptor</value>
        <value>rentaBikeTarget</value>
      </list>
    </property>
  </bean>

  <!-- etc. -->
</beans>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName">
    <value>com.mysql.jdbc.Driver</value>
  </property>
  <property name="url">
    <value>jdbc:mysql://localhost/bikestore</value>
  </property>
  <property name="username"><value>bikestore</value></property>
</bean>


我们这个例子使用了简单的before advice。现在,我们来看看最复杂的around advice。如果我们能够理解最高级的流程,那么其他的都将变成很简单了。下图告诉我们advice在在Spring中是如何运作的。BikeDAO是一个目标对象(target object)。它有很多业务代码。要配置一个拦截器,我们这里要指定一个代理(proxy)。这个代理负责维护一串拦截器(即拦截器链)。一个对象通过代理去调用方法而不是直接通过目标对象去调用。当我们调用代理上的一个方法或引发一个异常时,代理对象会调用拦截器链中的第一个拦截器。每个拦截器会做它们自己的工作并唤醒下一个拦截器。最后一个拦截器会去调用目标对象的方法或异常。.在目标对象处理完调用后,拦截器们仅仅只是返回。




在本例中,我们在目标对象上配置了一个代理,并告诉代理将应用我们的拦截器到目标对象的所有方法。但是我们也能够仅仅使用正则表达式来指定一个方法的子集。下面是拦截器的代码:

Example 6-4. LoggingAround.java
public class LoggingAround implements MethodInterceptor {
  private SessionFactory factory;

  public SessionFactory getFactory( ) {
    return factory;
  }

  public void setFactory(SessionFactory factory) {
    this.factory = factory;
  }

  private void logEvent(String methodName, String message)
      throws Exception {

    Session s = null;
    LogEvent le = new LogEvent(methodName, new Date( ), message);
    try {
        s = factory.openSession( );
        s.save(le);
    } catch (Exception ex) {
        //log the exception
    } finally {
        s.close( );
    }
  }

  public Object invoke(MethodInvocation methodInvocation)
      throws Throwable {
    logEvent(methodInvocation.getMethod( ).getName( ), "Entering call.");
    Object result = methodInvocation.proceed( );
    logEvent(methodInvocation.getMethod( ).getName( ), "Leaving call.");
    return result;
  }
}


下图显示新的配置文件:

Example 6-5. RentABike-servlet.xml
<bean id="loggingAround" class="com.springbook.interceptors.LoggingAround">
  <property name="factory"><ref local="sessionFactory"/></property>
</bean>

<bean id="saveAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  <property name="advice">
    <ref local="loggingAround"/>
  </property>
  <property name="patterns">
    <list>
      <value>.*save.*</value>
    </list>
  </property>
</bean>

<bean id="rentaBikeTarget" class="com.springbook.HibRentABike">
  <property name="storeName"><value>Bruce's Bikes</value></property>
  <property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>

<bean id="rentaBike"
  class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="proxyInterfaces">
    <value>com.springbook.RentABike</value>
  </property>
  <property name="interceptorNames">
    <list>
      <value>transactionInterceptor</value>
      <value>saveAdvisor</value>
      <value>rentaBikeTarget</value>
    </list>
  </property>
</bean>


下表显示了before和after advice仅仅被save的相关方法调用后的结果。

Example 6-6. Examining the contents of the logging table
+---------+--------------+------------+----------------+
| eventId | methodName   | dateTime   | message     |
+---------+--------------+------------+----------------+
|     14 | saveBike   | 2004-10-13 | Entering call. |
|     15 | saveBike   | 2004-10-13 | Leaving call. |
|     16 | saveCustomer | 2004-10-13 | Entering call. |
|     17 | saveCustomer | 2004-10-13 | Leaving call. |
|     18 | saveBike   | 2004-10-13 | Entering call. |
|     19 | saveBike   | 2004-10-13 | Leaving call. |
+---------+--------------+------------+----------------+


最后的结果确实是我们想得到的。每一次指定的一个方法调用目标对象时,advice就会被触发。我们已经完成了这个声明式的审计功能(declarative auditing)。实际上,我们能够编写任何服务并使它成为声明型的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值