【问题标题】:Writing custom annotations in java - TimeCounter annotation example用java编写自定义注解——TimeCounter注解示例
【发布时间】:2021-08-06 22:37:01
【问题描述】:

基本上,我需要使用自定义注释来跟踪在方法中花费的时间。 (我知道 spring AOP 可以用于此,但我们不能在我们的产品中使用它)。

public class TimeCounterDemo {
    
    @TimeCounter
    public void trackMyTimeSpentUsingAnnotation()
    {
        //some heavy processing stuff
    }   
}

public @interface TimeCounter {
  //need help with this implementation.
}

所以,我的要求是完成TimeCounter注解。 要求很简单 -

  1. 方法启动的记录时间。
  2. 方法结束的记录时间。
  3. 记录方法花费的总时间。
  4. 执行的方法名称

有人可以帮助了解如何根据上述要求实现此注释。

提前致谢。

【问题讨论】:

    标签: java java-8 annotations java-annotations


    【解决方案1】:

    已经有很多库提供了这样的注释。 如果您想要自己的实现,其中一种方法是使用dynamic proxies:

    您的TimeCounterDemo 可能如下所示:

    TimeCounter(注解)

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface TimeCounter {
    
    }
    

    ITtimerCounterDemo(接口)

    public interface ITimerCounterDemo {
        @TimeCounter
        public void trackMyTimeSpentUsingAnnotation();
    
        public void someOtherMethod(int a);
    }
    

    TimerCounterDemo(上述接口的实现)

    
    public class TimerCounterDemo implements ITimerCounterDemo {
        
        public void trackMyTimeSpentUsingAnnotation() {
            System.out.println("TimerCounterDemo:: Going to sleep");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
            System.out.println("TimerCounterDemo:: Completed.");
        }
    
        public void someOtherMethod(int a) {
            System.out.println("In someothermethod with value:: " + a);
        }
    }
    

    TimerProxy

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.time.Duration;
    import java.time.LocalDateTime;
    import java.util.Objects;
    
    public class TimerProxy implements InvocationHandler {
    
        private Object targetObj;
    
        public static Object newInstance(Object targetObj) {
            Objects.requireNonNull(targetObj);
            return Proxy.newProxyInstance(
                          targetObj.getClass().getClassLoader(), 
                          targetObj.getClass().getInterfaces(),
                          new TimerProxy(targetObj)
                   );
        }
    
        private TimerProxy(Object targetObj) {
            this.targetObj = targetObj;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.isAnnotationPresent(TimeCounter.class)) {
    
                LocalDateTime start = LocalDateTime.now();
                Object returnObj = method.invoke(targetObj, args);
    
                System.out.println(method.getName() + " executed in "
                        + Duration.between(start, LocalDateTime.now()).getSeconds() + " seconds");
                return returnObj;
            }
    
            return method.invoke(targetObj, args);
        }
    
    }
    

    测试计时器:

    public class TimerTest {
        public static void main(String[] args) throws InterruptedException {
            ITimerCounterDemo t = (ITimerCounterDemo) TimerProxy.newInstance(new TimerCounterDemo());
            t.someOtherMethod(10);
            t.trackMyTimeSpentUsingAnnotation();
        }
    }
    
    

    输出:

    In someothermethod with value:: 10
    TimerCounterDemo:: Going to sleep
    TimerCounterDemo:: Completed.
    trackMyTimeSpentUsingAnnotation executed in 2 seconds
    

    您可以在here 和here 阅读更多相关信息

    【讨论】:

    • 精彩的实现 +1。因此,您的实现使用您链接的动态代理。正确的?并且是通过实现类继承的接口方法的注释。这篇文章说反了 - Why java classes do not inherit annotations from implemented interfaces
    • @joven,正确,我们正在使用代理。我们没有将@TimerCounter 放在接口上以便子类继承;这样我们就可以在invoke 方法中检查注释。代理与接口一起工作(因此命名为动态代理。)为了简单起见,我把它放在接口上。您也可以将注释放在类内声明的方法中。你有targetObj 并且可以检查其方法的注释(例如:targetObj.getClass().getMethods())并采取相应的行动。
    • @joven 请注意,我们仍然(当我们将@TimeCounter 放在TimerCounterDemo 内的方法def 上时)需要ITimerCounterDemo。这是因为代理使用接口。我们不能有TimerCounterDemo t = (TimerCounterDemo) TimerProxy.newInstance(new TimerCounterDemo());。强制转换和赋值类型必须是TimerCounterDemo 实现的接口之一。
    【解决方案2】:

    您无需编写注释,而是直接在您的方法中实现时间跟踪。 方法中的前 2 行必须是

    long startTime = System.currentTimeMillis();
    logger.info("Method started at = " + new Date(startTime);
    

    现在您必须记录该方法所花费的总时间。这可以通过将以下语句写入相同的方法来完成

    logger.info("Total time taken by the method is = " + (System.currentTimeMillis() - startTime));
    

    【讨论】:

    • 我知道这个..你能删除你的答案吗?我正在考虑删除这个 Q
    猜你喜欢
    • 2013-11-25
    • 2014-01-13
    • 1970-01-01
    • 2011-06-12
    • 2018-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    相关资源
    最近更新 更多