Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/359.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在主执行块之前和之后将代码注入方法_Java_Performance_Code Injection - Fatal编程技术网

Java 在主执行块之前和之后将代码注入方法

Java 在主执行块之前和之后将代码注入方法,java,performance,code-injection,Java,Performance,Code Injection,我有两个类实现了一个特定的接口,如下所示(这显然是一个非常简化的版本,但可以理解这一点): Talk的首次实现: import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SayHello implements Talk { static final Logger LOG = LoggerFactory.getLogger(SayHello.class); public SayHello() {}

我有两个类实现了一个特定的
接口
,如下所示(这显然是一个非常简化的版本,但可以理解这一点):

Talk
的首次实现:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SayHello implements Talk {

  static final Logger LOG = LoggerFactory.getLogger(SayHello.class);

  public SayHello() {}

  public void sayIt() {
    System.out.println("Hello");
  }
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SayGoodbye implements Talk {

  static final Logger LOG = LoggerFactory.getLogger(SayHello.class);

  public SayGoodbye() {}

  public void sayIt() {
    System.out.println("GoodBye");
  }

}
Talk
的第二次实现:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SayHello implements Talk {

  static final Logger LOG = LoggerFactory.getLogger(SayHello.class);

  public SayHello() {}

  public void sayIt() {
    System.out.println("Hello");
  }
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SayGoodbye implements Talk {

  static final Logger LOG = LoggerFactory.getLogger(SayHello.class);

  public SayGoodbye() {}

  public void sayIt() {
    System.out.println("GoodBye");
  }

}
现在在
sayIt()
方法中,我想实现一些跟踪级日志记录和一些方法执行计时器,我可以简单地执行以下操作:

public void sayIt() {
    long startTime = System.currentTimeMillis();
    LOG.trace("Executing sayIT for implementation {} , start time at {}.", this.getClass().getSimpleName(), startTime);
    System.out.println("Hello");
    LOG.trace("sayIT for implementation {} took {} milliseconds to execute.", this.getClass().getSimpleName(), System.currentTimeMillis() - startTime);
}
问题是我需要为每个实现
Talk
接口的
class
sayIt()
方法的每个实现都复制粘贴这个,我真的不想这样做,因为

  • 它造成了大量的重复
  • 随着实现的增多,您开始感到维护方面的头疼,尤其是当您决定稍微更改实现时
  • 我很懒,喜欢写尽可能少的代码,同时尽可能多地重用
  • 所以问题是。。。。我如何达到一次写作,多次使用的目标?方法计时是一个应用程序,但我真的只希望能够在方法的开头和结尾“注入”代码

    我真的在寻找一个可以工作的工作示例(不仅仅是指向更多链接的链接)(我猜是这样的,但我一直在为让它与Gradle一起工作而烦恼不已……可能只是尝试了一个Maven实现)

    哦,是的,我可以不将代码添加到
    sayIt()
    而是将其添加到调用
    sayIt()
    的代码中,例如:

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import java.util.ArrayList;
    import java.util.List;
    
    public class SomeOtherClass {
    
      static final Logger LOG = LoggerFactory.getLogger(SomeOtherClass.class);
    
      public SomeOtherClass() {}
    
      public void letsHaveAConversation() {
        List<Talk> talks = new ArrayList<>();
        talks.add(new SayHello());
        talks.add(new SayGoodbye());
        for (Talk talking : talks) { 
            long startTime = System.currentTimeMillis();
            LOG.trace("Executing sayIT for implementation {} , start time at {}.", talking.getClass().getSimpleName(), startTime);
            talking.sayIt();
            LOG.trace("sayIT for implementation {} took {} milliseconds to execute.", talking.getClass().getSimpleName(), System.currentTimeMillis() - startTime);
        }
      }
    
    }
    
    import org.slf4j.Logger;
    导入org.slf4j.LoggerFactory;
    导入java.util.ArrayList;
    导入java.util.List;
    公共类其他类{
    静态最终记录器日志=LoggerFactory.getLogger(SomeOtherClass.class);
    公共SomeOtherClass(){}
    公开会议{
    List talks=new ArrayList();
    添加(新的SayHello());
    talks.add(new saybaye());
    为了(谈话:谈话){
    long startTime=System.currentTimeMillis();
    trace(“为实现{}执行sayIT,开始时间为{}.”,talking.getClass().getSimpleName(),startTime);
    说话;
    LOG.trace(“sayIT for implementation{}花费了{}毫秒来执行。”,talking.getClass().getSimpleName(),System.currentTimeMillis()-startTime);
    }
    }
    }
    

    这将起作用,但如果我有多个调用
    sayIt()
    的位置,则不行

    为什么不将
    sayIt
    调用封装在抽象类公共方法中

    abstract class AbstractTalk implements Talk {
        public void sayIt() {
            trace();
            startMeasure();
    
            doSayIt();
    
            stopMeasure();
        }
    
        abstract protected doSayIt(); // here implement the logic
    }
    

    更广泛地说,是一个装饰师。@Kayaman,是的,你是100%正确的,这就是AspectJ试图做的。Spring也有一个AOP框架,但不幸的是,我没有在这个实现中使用Spring。如上所述,我正在寻找的是一个工作的例子。只是一个旁注。。。我已经修补了AspectJ,但是我一直很难让它正常工作。然而,我的问题有点宽泛的原因是我不希望它是一个具体的AspectJ实现问题,因为我对不同的建议感兴趣。很好的一点是,这个解决方案工作得相当好,而且它不具备代码注入的黑魔法。这将带来的唯一问题(至少在我的场景中)更多的是日志记录问题。日志输出将针对
    AbstractTalk
    ,而不是
    SayHello
    saybye
    。虽然我想人们总是可以使用类似于
    String callingThread=Thread.currentThread().getStackTrace()[2].getClassName()的东西
    获取该信息。您可以始终为受保护的构造函数提供
    logger
    参数,并在创建子类时提供适当的记录器实现yes,或者添加另一个返回
    logger