java - 无需AOP框架即可动态添加方面的软件设计

标签 java design-patterns decorator interceptor aop

我编写了一个小示例程序来测量java方法的执行时间。 我想设计一个低耦合并且可以动态添加到其他方法的解决方案,这意味着如果我用其他方法编写其他类,我想< em>将我的性能测量模块包装在我的业务逻辑模块上并测量方法的执行时间,而业务逻辑类不依赖于性能测量模块

我当前的解决方案如下所示

  • 我有一个抽象类,它定义了一些列表操作。
  • 我有定义具体列表操作的子类
  • 我有一个性能测量类,它扩展了要测量的类

    public abstract class ListOperations<T> {
    
      private List<T> list;
    
      public ListOperations() {
         initList();
      }
    
      /**
       * Initializes the list. Clients can decide which list type shall be used (e.g LinkedList, ArrayList etc.)
       */
      public abstract void initList();
    
      public abstract void addLast(final T element);
    
      public List<? super T> getList() {
          return list;
      }
    
      protected void setList(final List<T> list) {
          this.list = list;
      }
    }
    
    
    
    
    public class LinkedListOperations<T> extends ListOperations<T> {
    
    public LinkedListOperations() {
        super();
    }
    
    @Override
    public void addLast(final T element) {
        getList().addLast(element);
    }
    
    @Override
    public void initList() {
        setList(new LinkedList<T>());
    }
    
    @Override
    public LinkedList<? super T> getList() {
        return (LinkedList<? super T>) super.getList();
    }
    }
    
    
    
    public class PerformanceMeassuredLinkedListOperations<T> extends LinkedListOperations<T> {
    
    private static final String START_PERFORMANCE_MEASSURE_FOR_METHOD = "Start Performance Meassure for method: ";
    private static final String STOP_PERFORMANCE_MEASSURE_FOR_METHOD = "Stop Performance Meassure for method: ";
    private static final String TIME_EXECUTION_IN_MILLIS = "Time Execution in Millis: ";
    
    /**
     * Used to printout the name of the method from the stack. in depth 2 the real business logic method is located
     */
    private static final int DEPTH_IN_STACKTRACE = 2;
    // depth 0 = printStopMeassurement
    // depth 1 = stopPerformanceMeassure
    // depth 2 = method for which performance is measured (e.g addLast)
    
    private long startCurrentTimeMillis;
    
    @Override
    public void initList() {
        startPerformanceMeassure();
        super.initList();
        stopPerformanceMeassure();
    }
    
    public void meassureAddLast(final int numberOfElements, final T testElement) {
        startPerformanceMeassure();
        for (int i = 0; i < numberOfElements; i++) {
            addLast(testElement);
        }
        stopPerformanceMeassure();
    }
    
    protected void startPerformanceMeassure() {
        printStartMeassurement();
        startCurrentTimeMillis = System.currentTimeMillis();
    }
    
    private void printStartMeassurement() {
        System.out.println(START_PERFORMANCE_MEASSURE_FOR_METHOD + getNameOfCurrentExecutedMethod());
    }
    
    protected void stopPerformanceMeassure() {
        System.out.println(TIME_EXECUTION_IN_MILLIS + (System.currentTimeMillis() - startCurrentTimeMillis));
        printStopMeassurement();
    }
    
    private void printStopMeassurement() {
        System.out.println(STOP_PERFORMANCE_MEASSURE_FOR_METHOD + getNameOfCurrentExecutedMethod());
    }
    
    private String getNameOfCurrentExecutedMethod() {
        final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
        return ste[ste.length - DEPTH_IN_STACKTRACE].getMethodName();
    }
    
    }
    
    
    
    public class Main {
    
    public static void main(String[] args) {
        PerformanceMeassuredLinkedListOperations<String> listOperations = new PerformanceMeassuredLinkedListOperations<String>();
        listOperations.meassureAddLast(50000, "Hello");
    }
    }
    

使用此解决方案,我必须扩展每个业务逻辑模块并以静态方式添加我的时间测量代码。

现在我想设计一个性能测量模块,可以动态添加到任何业务逻辑模块并测量所调用方法的性能。我不想为此使用任何 AOP 框架。我认为这种动态方面的添加可以通过某种装饰器和拦截器模式的混合来完成,但我不知道如何实现。

最佳答案

您所描述的是 cross cutting concern 你的需求完全属于某个方面的范围。您希望能够记录代码中各个切点的延迟。

考虑:

方法一

  • 您需要拦截对所述业务模块的所有调用。
  • 您可以定义一个 BussinessModule 接口(interface)。创建一个委托(delegate)类来拦截此常见调用,然后包装一个抽象方法并记录延迟(或其他)。
  • 虽然有限制,但只要付出一些努力就可以实现,而且是最简单的实现方式。

方法2

  • 开发某种表达语言来说明您想要在哪些类上拦截哪些方法
  • 找出一种方法来拦截这些方法调用(不使用 AspectJ,或编写自己的类加载器,我无法想象如何)并执行它们

方法 1 根本不是动态的。您必须对整个系统的实现有严格的控制。任何未包含在委托(delegate)/代理方案中的类都不会获得此行为。必须有人确保每个实现的类都有这个包装器

方法 2 是 super 动态的。通过具有表达性的语言/语法,您可以描述代码以获取包装器,然后,即使它不是您的代码或者您正在与懒惰的人一起工作,它仍然会被包装。缺点是实现起来非常困难且耗时。 不过好新! Spring AOP 和 AspectJ 已经做到了这一点!

所以,你的问题是

how do I do this without Spring AOP or AspectJ

我相信我已经给出了答案。但要完全明确的是:大量的授权将是最简单的途径。

也就是说:没有充分的、可解释的理由来推出自己的。我实际上有一个方面和 Spring 的 bean 配置来完成此任务。如果是时间问题,我可以简单地将其粘贴进去,您可以将其撕下来并运行。

关于java - 无需AOP框架即可动态添加方面的软件设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23723720/

相关文章:

java - 从子类调用方法导致运行时 ClassCastException

java - 测试安卓应用程序。试图模拟 getSystemService。

Java 在没有 IDE 的情况下运行外部 jar 吗?

python - 设计我的票务 API

c++ - 是否有将 'methods' 与成员隔离的设计模式?

qt - 单例模式语法错误静态字段未命名非静态数据成员或基类

python - 装饰器将实例方法转换为类函数

java - Ant 最佳实践的好例子

python - 在装饰器的包装器中访问 kwargs 和 args

python - 装饰 Python 类方法的最佳方式是什么?