正 文

Aspectwerkz 2.0开发企业AOP快速入门


www.7dspace.com  更新日期:2006-2-24 4:43:25  七度空间


  注释与XML

  AspectWerkz在定义切入点(pointcut)时给出了两个选择:Java类文件中的注释,或使用名为aop.xml的外部文件中定义的XML。利用注释在代码中直接定义切入点非常好,但是如果不是使用JDK 5,就必须包含额外的构建步骤来产生aop.xml文件。当使用JDK 5时,我选择在XML中定义方面,并对切入点使用注释。这样,切入点就与代码结合起来了,而方面可以很容易地通过编辑aop.xml来更改或删除。我希望本文能对最大范围的读者有用,因此假定JDK 5不可用。

  因为我非常不喜欢在开发阶段需要编译时步骤,我选择直接在aop.xml中定义一切。这个决定使我们必须用aop.xml符号定义相当复杂的切入点,但我认为这比使开发周期变慢要好。本文将只使用aop.xml定义。

  在线与脱机编写

  AspectWerkz的很多灵活性是因为它能以在线和脱机两种方式运行。在在线方式下,AspectWerkz在运行时动态地编写类。在脱机方式下,需要一个额外的编译步骤来在构建阶段编写类。这种灵活性使开发人员能够为一个特定任务选择最优方式。

  例如,在程序开发阶段,在线方式较好。在开发周期中不需要编译或编写的步骤。同样,因为是开发阶段,您对JVM运行时具有完全的控制权,因此不必留意定制JVM启动,而这对于在线编写是必需的。

  需要的时候,可以切换为脱机方式。下面是您想这么做的两个主要原因。首先,预编写的类性能非常好,它们与包含同样功能的“普通”类执行起来是类似的。其次,没有必要改变JVM设置。这一点对于驻留环境或者对付保守的管理员很重要。脱机方式的缺点是,您只能把方面应用于自己打包的代码。这意味着您不能把方面应用于任何您可能正在使用的第三方库(除非您把它们重新打包)。

  我在开发阶段使用在线方式,然后在部署时切换为脱机方式。这使我省掉了额外的构建步骤,而且因为是开发阶段,不用担心性能或改变JVM设置。对于本文,脱机编写用于打包的WAR文件,以便读者不必再定制JVM来测试应用程序。
  为了使用AspectWerkz来脱机编写类,把下面的目标结合到ant脚本中:

<target name="weave">
  <property name="AW_LIB" 
      value="c:/opt/aspectwerkz-2.0/lib"/>
  <taskdef name="awc" 
    classname="org.codehaus.aspectwerkz.compiler.AspectWerkzCTask">
    <classpath>
      <pathelement 
          path="/aspectwerkz-2.0.jar"/>
      <pathelement 
          path="/aspectwerkz-core-2.0.jar"/>
      <pathelement 
          path="/aspectwerkz-extensions-2.0.jar"/>
    </classpath>
  </taskdef> 

  <awc verbose="true"
      targetdir="webWEB-INF asses">
    <classpath>
      <fileset dir="lib"/>
    </classpath>
  </awc>
</target>

  把日志记录方面应用于示例应用程序

  我们都看过早期的简单跟踪方面,它是AOP的雏形。它只是在每个方法调用之前和之后用一个对函数System.out.println()的调用把所有的方法调用包装起来。当然了,这对于生产环境是完全没有意义的。下面看一下Log4J的优点。

  正如在前面的示例代码中见到的,要用Log4J进行记录,需要用一个类别名来实例化记录器。惯例是用全限定类作为类别名,如下:

private static final Log log = Log.getLog(EntryHibernateDao.class);

  我们想要一个与上面的定义有相同特征的方面,也即:

  1.对每个类,Log被实例化一次,且只有一次。

  2.每个类有自己的Log,它使用全限定类名作为类别名。

  为了达到上面的要求,仅仅把日志记录方面应用于切入点是不够的。必须用一种mixin(混入)方法在类中“注入”日志定义。Mixin提供了给一组类增加额外功能的方法,这对于需要在多个类中实现样板文件代码的情况尤其有用。使用mixin,我们可以指示AspectWerkz对类进行修改以给类添加行为。在本例中,我们将让AspectWerkz修改类来实现一个Loggable接口,这个接口用来返回一个满足上述要求的Log实例。下面的代码定义了Loggable接口和它的实现:

public interface Loggable {
    Log getLog();
}

public class LoggableImpl implements Loggable {
    private final Log log;
    public LoggableImpl(Class targetClass) {
        log = Log.getLog(targetClass);
    } 

    public Log getLog() { return log; }
}

  现在我们想要指示AspectWerkz对类进行修改以实现Loggable接口。为此,我们把下面的XML定义添加到aop.xml中:

<mixin class="com.handyware.aop.LoggableImpl" 
  deployment-model="perClass"
  bind-to="within(com.tss..*) 
            AND avoidTrace"/> 

  这个mixin指示AspectWerkz向我们想要记录的系统中的每个类添加一个LoggableImpl域。要想看看这都做了什么,可以对产生的类进行反编译。下面就是编写的EntryHibernateDao类所包含的代码:

public class EntryHibernateDao 
         extends HibernateDaoSupport
         implements Loggable, IEntryDao
{
   private static final LoggableImpl aw; 
   public Log getLog() {
     return aw.getLog();
   }
   static {
     aw = Class.forName(
       "com.tss.blog.service.EntryHibernateDao");
     aw = (LoggableImpl)Mixins.mixinOf(
       "com.tss.blog.aop.LoggableImpl", 
       aw);
   } 

   ....
}

  正如你所看到的,AspectWerkz修改了初始的类以使它包含一个LoggableImpl静态域,并把它初始化成一个特定于类的Log实例。既然每个类都有了一个getLog()方法,定义Log4J日志记录方面就非常简单了:

public class LoggingIdiom {
    public Object traceWithParams(
                 JoinPoint jp, Loggable loggable)
                 throws Throwable {
        loggable.getLog().enter(enterTrace(jp));
        Object result = jp.proceed();
        loggable.getLog().exit(exitTrace(jp, result));
        return result;
    }
}

  为了把这个方面编入到代码中,我们把下面的内容添加到aop.xml定义中:

<aspect class="com.tss.aop.LoggingIdiom">
  <pointcut name="p2" 
      expression="execution(* com.tss..*.*(..))
                        AND avoidTrace" />
  <advice name="traceWithParams(JoinPoint jp, 
                 com.tss.aop.Loggable loggable)" 
               type="around" 
               bind-to="p2 AND target(loggable)" />
</aspect>

  您会注意到,在上面的日志记录方面定义中定义了一个avoidTrace切入点,它允许我们排除那些不想做日志记录的类。切入点模型模型非常强大,因为它使您可以自由选择如何应用方面。

  例如,Hibernate使用一种动态生成子类的技术,而且默认情况下,日志记录方面将应用于这些新类,而这可能并不是您想要的。可以把这些类排除在日志之外以更简化。为此,只需排除所有与Hibernate相关的切入点即可。其他的例子包括JavaBean存取器和日志记录方面本身——否则就会陷入日志记录记录器本身的死循环中。

4页,页码:[1] [2] [3] [4] 

上一篇:在J2ME中基于MIDP1.0实现组合按键
下一篇:功能完整!Win Vista本月CTP美图曝光
Aspectwerkz 2.0开发企业AOP快速入门 作者:David Teare 来源:BEA
收藏此页】【打印】【关闭
站 内 搜 索
 

热 点 导 读
特 别 推 荐