java - Java 接口(interface)的包装方法实现

标签 java methods wrapper spring-aop

我有多个接口(interface),每个接口(interface)定义多个方法,如下所示:

public interface X {
    void methodX1;

    void methodX2(String s);
}

public interface Y {
    void methodY1;

    void methodY2(int i);

    void methodY3(SomeType s);
}

....

目前该方法的实现如下所示:

public class XImpl implements X {
        public void methodX1() {
            // method implementation
        }
    }

对于接口(interface)的每个实现,我需要使用 try-with-resource block 包装方法实现,如下所示:

public class XImpl implements X {
    public void methodX1() {
        try (SomeResource res = new SomeResource()) {
            // method implementation
        }
    }
}

由于我对 AOP 的有限概念,我相信我们可以在 JoinPoint 之前和之后做一些事情,即本例中的方法,但是我们如何才能像上面那样包装实现呢?我想看看是否可以使用注释或 lambda 来完成,即我不必单独更改每个方法。

任何关于如何做到这一点的想法将不胜感激。

最佳答案

With my limited notion of AOP, I believe we can do things before and after the JoinPoint i.e. method in this case, but how can we wrap implementation as above?

你读过很好的Spring AOP manual吗? ?您首先会注意到的事情之一就是对建议类型的解释,不仅有之前和之后,还有周围建议。这就是您想要使用的。

这基本上是它的工作原理:

Java 帮助器类:

package de.scrum_master.app;

public class SomeType {}
package de.scrum_master.app;

public class SomeResource implements AutoCloseable {
  @Override public void close() throws Exception {}
}

接口(interface):

package de.scrum_master.app;

public interface X {
  void methodX1();
  int methodX2(String s);
}
package de.scrum_master.app;

public interface Y {
  void methodY1();
  String methodY2(int i);
  void methodY3(SomeType s);
}

接口(interface)实现+驱动应用:

我在 AspectJ 中实现了该示例,而不是在 Spring AOP 中。因此,您看不到应用程序上下文,但您知道如何做到这一点,不是吗?

package de.scrum_master.app;

import org.springframework.stereotype.Component;

@Component
public class MyImpl implements X, Y {
  @Override public void methodY1() { System.out.println("Y1"); methodX2("bar"); }
  @Override public String methodY2(int i) { System.out.println("Y2"); return "dummy"; }
  @Override public void methodY3(SomeType s) { System.out.println("Y3"); }
  @Override public void methodX1() { System.out.println("X1"); methodY1(); }
  @Override public int methodX2(String s) {  System.out.println("X2"); return 42; }

  public static void main(String[] args) {
    MyImpl myImpl = new MyImpl();
    myImpl.methodX1();
    myImpl.methodX2("foo");
    myImpl.methodY1();
    myImpl.methodY2(11);
    myImpl.methodY3(new SomeType());
  }
}

请注意,methodX1()methodY1() 都在内部调用方法。这对于后面关于 Spring AOP 和 AspectJ 之间的区别很重要。

方面:

在 Spring AOP 中,你可以省略 execution(* *(..)) && 部分,我只是在这里使用它,以避免其他连接点,例如 call() code> 被拦截并且日志变得臃肿。由于 Spring AOP 除了 execution() 之外不知道太多其他内容,因此没有必要。 两边的括号... || ... 切入点 block 也可以消失。

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import de.scrum_master.app.SomeResource;

@Component
@Aspect
public class WrapMethodsAspect {
  @Around("execution(* *(..)) && (within(de.scrum_master.app.X+) || within(de.scrum_master.app.Y+))")
  public Object wrapperAdvice(ProceedingJoinPoint thisJoinPoint) throws Throwable {
    System.out.println("Wrapping " + thisJoinPoint);
    try (SomeResource res = new SomeResource()) {
      return thisJoinPoint.proceed();
    }
    finally {
      System.out.println("Unwrapping " + thisJoinPoint);
    }
  }
}

使用 AspectJ 进行控制台输出:

Wrapping execution(void de.scrum_master.app.MyImpl.main(String[]))
Wrapping execution(void de.scrum_master.app.MyImpl.methodX1())
X1
Wrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Y1
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Unwrapping execution(void de.scrum_master.app.MyImpl.methodX1())
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Y1
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Wrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Y2
Unwrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
Y3
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
Unwrapping execution(void de.scrum_master.app.MyImpl.main(String[]))

您在这里注意到两件事:

  • 记录静态 main(..) 方法的执行情况。使用 Spring AOP 就不会发生这种情况。
  • 记录内部方法调用。使用 Spring AOP 也不会发生这种情况。

使用 Spring AOP 进行控制台输出:

Wrapping execution(void de.scrum_master.app.MyImpl.methodX1())
X1
Unwrapping execution(void de.scrum_master.app.MyImpl.methodX1())
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Y1
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Wrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Y2
Unwrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
Y3
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))

大多数情况下,Spring AOP 对于 Spring 用户来说已经足够了。但是,如果您需要更强大的方法来捕获其他类型的切入点或例如内部嵌套方法调用,您可以使用 AspectJ via load-time weaving (LTW) .

关于java - Java 接口(interface)的包装方法实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53770725/

相关文章:

java - 如何为 tomcat keystore 安装 SSL 证书

java - 没有按钮的 JOptionPane

Java-如何检查文件夹中的任何文件是否已完成下载

javascript - Meteor:定义可用于方法的服务器功能

c++ - 在 C++ 中声明可见性/访问的方式有何不同?

c++11:模板化包装函数

java - 在Java中正确比较code_verifier和code_challenge

java - 编译器错误和 Money 类分配

python - 成员函数装饰器和 self 参数

c - 非托管结构作为托管的返回值