面向方面 vs 面向对象 3(AOP方法)

发表于:2007-05-25来源:作者:点击数: 标签:方法byNarayannbsp对象aop
byNarayananA.R.June15,2005 翻译zhangv(derekzhangv.at.hotmail.com) 原文: http://www.devx.com/Java/Article/28422/0/page/3 图3 图3中描述了AOP方法的设计以及在一个更抽象的层次上类间的交互.你可以通过对比图1和图3来更好地理解AOP. 程序的目的是通过B
 by Narayanan A.R. June 15, 2005
翻译zhangv (derekzhangv.at.hotmail.com)
原文:http://www.devx.com/Java/Article/28422/0/page/3


图3

图3中描述了AOP方法的设计以及在一个更抽象的层次上类间的交互.你可以通过对比图1和图3来更好地理解AOP.
程序的目的是通过BusinessUnit对象读取CSV文件中的记录然后 填入类BusinessUnitService 中的map.使用AOP来填充这个map有点类似后门(backdoor)方法 -- 控制被委派给BusinessUnit 来读取存储介质中的记录.

AOP就是定义一些point cut(?)和advice.一个point cut是源代码中一个执行点.前面的例子定义了一个pointcut 给类BusinessUnitService中的findBusinessUnits 方法.一个advice就是当执行到point cut时的一块代码.类BusinessUnitPersistentAspect 包括advice方法findAllBusinessUnits,该方法从存储介质中载入数据,然后使用工厂类创建BusinessUnit 对象.然后这个对象被加入map,map对象的引用通过BusinessUnitService 对象获得.point cut 和advice组成了所谓的"方面(Aspect)"

为了读取存储介质中的数据,OOP方法通过一个DAO类来做.而AOP中,你在作用域类中定义一个point cut和一个advice来读取数据.AOP框架会以advice的形式注入代码,既可以在执行期也可以在编译期.

总而言之,当类BusinessUnitService 中的findAllBusinessUnits 方法被调用时,AOP框架会注入advice方法并通过BusinessUnit 对象预先读取数据来填充map对象.这样,持久层方面的代码可以从业务模型中移出.

新方法里的方面

本节讨论如何用AOP为应用程序的各方面建模

操作资源

类BusinessUnitPersistenceAspect 的持久方法使用了一个buffered reader.你甚至可以定义方面的方面,但为了简单,这里的讨论只关注类的查找方法.
  1. @Aspect("perJVM")
  2. public class BufferedFileReaderAspect {
  3. @Expression("execution(* org.javatechnocrats.aop.withaop.aspects.BusinessUnitPersistenceAspect.find*(..))")
  4. Pointcut businessUnitPersistenceAspect;
  5. // 其他point cut 定义
  6. @Expression("businessUnitPersistenceAspect ||
  7. employeePersistenceAspect ||
  8. managerPersistenceAspect")
  9. Pointcut allPersistencePointcuts;
  10. private Map<ClassString> fileNames;
  11. public BufferedFileReaderAspect() {
  12. System.out.println("BufferedFileReaderAspect created");
  13. fileNames = new HashMap<ClassString>();
  14. fillFileNames();
  15. }
  16. @Before("allPersistencePointcuts")
  17. public void assignReader(JoinPoint joinPoint) throws Throwable {
  18. System.out.println("assignReader advice called");
  19. Object callee = joinPoint.getCallee();
  20. IBufferedFileReaderConsumable bufReaderConsumable = (IBufferedFileReaderConsumable)callee;
  21. Class persistenceClass = callee.getClass();
  22. String fileName = fileNames.get(persistenceClass);
  23. FileReader fileReader = new FileReader(fileName);
  24. BufferedReader bufferedReader = new BufferedReader(fileReader);
  25. bufReaderConsumable.setBufferedReader(bufferedReader);
  26. }
  27. @AfterFinally("allPersistencePointcuts")
  28. public void releaseReader(JoinPoint joinPoint) throws Throwable {
  29. //释放buffered reader等资源
  30. }
  31. //其他方法
  32. }


上面的代码试图为每一个方法名创建一个point cut -- 所有以find开头的方法.无论何时这些方法被调用,assignReader方法都会被提前执行.这里它获取被调用的类实例然后设置新建的buffered reader.

同样地,在releaseReader 方法里,代码会预先关闭buffered reader集合.本节只解释@before和@
AfterFinally 这两个point cut.(以J2SE 5.0的标记定义).另外,你也可以在方面定义的xml文件中声明他们.你可以查看那例程源代码中的aop.xml文件.

下载

持久化

前面提到,OOP方法使用BusinessUnit 来为应用的持久层填充Map.在下面的高亮代码中(@before一行,以及while循环代码 - 译者注),当BusinessUnitService 中的方法findAllBusinessUnits 被调用时advice方法findAllBusinessUnits 也将被调用.
  1. @Aspect("perJVM")
  2. public class BusinessUnitPersistenceAspect implements IBufferedFileReaderConsumable {
  3. private BufferedReader buffFileReader;
  4. @Before("execution(Collection org.javatechnocrats.aop.withaop.BusinessUnitService.findAllBusinessUnits())")
  5. public void findAllBusinessUnits(JoinPoint joinPoint) throws Throwable {
  6. System.out.println("findAllBusinessUnits advice called");
  7. Map<String, BusinessUnit> businessUnits =
  8. ((BusinessUnitService)joinPoint.getThis()).getBusinessUnits();
  9. String businessUnitRecord;
  10. while((businessUnitRecord = buffFileReader.readLine()) != null) {
  11. BusinessUnit businessUnit = BusinessUnitFactory.createBusinessUnit(businessUnitRecord);
  12. businessUnits.put(businessUnit.getId(), businessUnit);
  13. }
  14. }
  15. public void setBufferedReader(BufferedReader buffFileReader) {
  16. System.out.println("BusinessUnitPersistenceAspect.setBufferedReader called");
  17. this.buffFileReader = buffFileReader;
  18. }
  19. public BufferedReader getBufferedReader() {
  20. System.out.println("BusinessUnitPersistenceAspect.getBufferedReader called");
  21. return this.buffFileReader;
  22. }
  23. }

advice方法从数据存储中读取记录,使用工厂类创建一个BusinessUnit实例.然后这个实例被加入到Map.该Map掌管程序的所有持久化方面.

日志/b]
本文中的例子没有包含一个完整的日志AOP解决方案.但是,它为java.lang.Object类的toString方法定义了一个point cut来获取类的调试信息.因此,域中的类不需要实现toString方法.通常可能你可能需要为每一个类都要实现这个方法.

  1. @Aspect("perJVM")
  2. public class LoggingAspect {
  3. @Around("execution(String org.javatechnocrats.aop.withaop..*.toString())")
  4. public Object toStringAdvice(JoinPoint joinPoint) throws Throwable {
  5. System.out.println("toStringAdvice called");
  6. String toString = (String)joinPoint.proceed();
  7. Object target = joinPoint.getThis();
  8. Field fields[] = target.getClass().getDeclaredFields();
  9. List members = new ArrayList(fields.length + 1);
  10. members.add(toString);
  11. for(Field field : fields) {
  12. field.setAclearcase/" target="_blank" >ccessible(true);
  13. Object member = field.get(target);
  14. members.add(field.getName() + "=" + member);
  15. }
  16. return members.toString();
  17. }


你也可以用这个样例代码完成错误处理方面.

原文转自:http://www.ltesting.net