Spring 4方法拦截器并使用自定义实现

时间:2018-02-07 21:48:10

标签: java spring spring-aop spring-aspects

我有以下课程和界面

interface abc {
 public A do();
}

package x;
public Impl1 implements abc{
  public A do(){
  }
}

package y;
public Impl2 implements abc{
  public A do(){
  }
}

我没有Impl1或Impl2的源代码。但是想拦截对do()方法的任何调用并使用我自己的实现。同样基于某些条件可能会调用实际的do()实现,其他情况下它不会被委托给原始实现。

请您告诉我这是否可以实现。如果是,如何实现这个?

我使用的是Spring 4和JDK 7.

2 个答案:

答案 0 :(得分:3)

我将提供一个独立的AspectJ解决方案,但是在Spring AOP中它会以同样的方式,只有方面和目标类需要是Spring bean /组件,所以不要忘记像@Component这样的注释,如Ian Mc所示。

帮助程序类+接口+实现:

package de.scrum_master.app;

public class A {
  private String name;

  public A(String name) {
    this.name = name;
  }

  @Override
  public String toString() {
    return "A [name=" + name + "]";
  }
}
package de.scrum_master.app;

public interface MyInterface {
  public A doSomething();
}
package de.scrum_master.app;

public class FirstImpl implements MyInterface {
  @Override
  public A doSomething() {
    return new A("First");
  }
}
package de.scrum_master.app;

public class SecondImpl implements MyInterface {
  @Override
  public A doSomething() {
    return new A("Second");
  }
}

驱动程序应用程序:

package de.scrum_master.app;

public class Application {
  private static MyInterface myInterface;

  public static void main(String[] args) {
    myInterface = new FirstImpl();
    for (int i = 0; i < 5; i++) {
      System.out.println(myInterface.doSomething());
    }

    myInterface = new SecondImpl();
    for (int i = 0; i < 5; i++) {
      System.out.println(myInterface.doSomething());
    }
  }
}

没有方面的控制台日志:

A [name=First]
A [name=First]
A [name=First]
A [name=First]
A [name=First]
A [name=Second]
A [name=Second]
A [name=Second]
A [name=Second]
A [name=Second]

到目前为止,太无聊了。

<强>方面:

现在让我们实现一个愚蠢的小方面,随机决定方法执行与跳过并提供另一个返回值(因为我不知道会导致你跳过方法执行的真实条件):

package de.scrum_master.aspect;

import java.util.Random;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import de.scrum_master.app.A;

@Aspect
public class MyAspect {
  private static Random random = new Random();

  @Around("execution(A de.scrum_master.app.MyInterface.*(..))")
  public A interceptCalls(ProceedingJoinPoint thisJoinPoint) throws Throwable {
    if (random.nextBoolean())
      return (A) thisJoinPoint.proceed();
    else
      return new A("Aspect"); 
  }
}

具有有效方面的控制台日志:

A [name=Aspect]
A [name=First]
A [name=Aspect]
A [name=Aspect]
A [name=First]
A [name=Aspect]
A [name=Second]
A [name=Second]
A [name=Aspect]
A [name=Second]

答案 1 :(得分:0)

您的请求可以使用Spring AOP完成,更具体地说,使用@Around建议。 @Around建议,除其他外,允许您将呼叫直接传递给原始实现,或者将呼叫短路,而是调用您的实现。您需要提供选择其中一个的逻辑。

@Around方法传递给ProceedingJoinPoint。要调用原始实现,请使用“proceed”方法。如果你想短路,那么你不要打电话继续;而是调用自己的方法创建一个'A'对象。

以下代码显示了一个基于@Aspect的类,它演示了这两种技术。您必须注入自己的实现,以便可以根据需要创建自己的A对象。

你应该对Spring AOP进行一些阅读,更具体地说是关于切入点(拦截呼叫所需的)和@Around建议。值得注意的是,您可以组合切入点并使用通配符,因此如果您使切入点足够通用以捕获所有实现的do方法,则可能使用@Aspect类中的有限数量的方法实现所需的功能。 / p>

示例代码显示传递到原始实现,以及调用您自己的短路。

@Aspect
@Component
public class DoAspects {

   @Autowired
   @Qualifier("YourQualifier")
   private abc p3;

   @Around("execution(* pkg1.Pkg1AImpl.do())")
   public A p1(ProceedingJoinPoint  jp) throws Throwable {
     // Some logic determines to call the original implementation (i.e. proceed)
     A a = (A)jp.proceed();  // Let the other implementation create A
     return a;
   }

   @Around("execution(* pkg2.Pkg2AImpl.do())")
   public A p2(ProceedingJoinPoint jp) {
     // Some logic determines to short-circuit, and call own implementation
     A a = p3.do();  // You create A
     return a;
   }

}