代码之家  ›  专栏  ›  技术社区  ›  Debopam

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

  •  1
  • Debopam  · 技术社区  · 8 年前

    我有以下类和接口

    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 回复  |  直到 8 年前
        1
  •  3
  •   kriegaex    8 年前

    我将提供一个独立的AspectJ解决方案,但在spring AOP中也是这样,只有aspect和您的目标类需要是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]
    
        2
  •  0
  •   Ian Mc    8 年前

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

    @Around方法被传递一个ProceedingJoinPoint。要调用原始实现,请使用' proceed '方法。如果要短路,则不调用继续;而是调用您自己的方法来创建“A”对象。

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

    一般来说,您应该阅读一下Spring AOP,更具体地说,应该阅读切入点(拦截调用所需的切入点)和@Around建议。需要注意的是,您可以组合切入点,并使用通配符,因此如果您将切入点设置为足够通用,以捕获所有实现的do方法,那么您很可能可以使用@方面类中数量有限的方法实现所需的功能。

    示例代码显示了对原始实现的传递和自己调用的短路。

    @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;
       }
    
    }
    
    推荐文章