Реализации метода обтекания интерфейсов Java - PullRequest
0 голосов
/ 14 декабря 2018

У меня есть несколько интерфейсов, каждый из которых определяет несколько методов, как показано ниже:

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
        }
    }

Для каждой реализации интерфейса мне нужнооберните реализацию метода блоком try-with-resource, как показано ниже:

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

С моим ограниченным представлением об АОП, я считаю, что мы можем сделать что-то до и после метода JoinPoint ie в этом случае, но какмы можем обернуть реализацию, как указано выше?Я смотрю, чтобы увидеть, можно ли это сделать, используя аннотации или лямбду, то есть то, что мне не нужно менять каждый метод в отдельности.

Любая мысль о том, как это можно сделать, будет принята с благодарностью.

Ответы [ 2 ]

0 голосов
/ 14 декабря 2018

С моим ограниченным представлением об АОП, я считаю, что мы можем сделать что-то до и после метода JoinPoint, т.е. в этом случае, но как мы можем обернуть реализацию, как указано выше?

Есть ли у васВы когда-нибудь читали очень хорошее руководство Spring AOP ?Одним из первых вещей, которые вы заметите, будет объяснение типов советов и то, что есть не только до и после, но также вокруг совета .Это то, что вы хотите использовать.

Вот как это работает:

Вспомогательные классы 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 {}
}

Интерфейсы:

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);
}

Реализация интерфейса + приложение драйвера:

Я реализовал пример в 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 позже.

Aspect:

В Spring AOP вы можете пропустить часть execution(* *(..)) &&, я простоиспользуйте его здесь, чтобы избежать перехвата других точек соединения, таких как call() и вздутие журнала.Поскольку Spring AOP не знает ничего другого, кроме execution(), в этом нет необходимости.Скобки вокруг блока ... || ... pointcut также могут исчезнуть.

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,Но если вам нужен более мощный подход для захвата других типов pointcut или, например, внутренних вызовов вложенных методов, вы должны использовать AspectJ через ткачество времени загрузки (LTW) .

0 голосов
/ 14 декабря 2018

Возможно, что-то вроде этого:

public abstract class ResourceProcessingService {
    protected <T> T processResource(Resource resource, Function<Reader, T> function) {
        try (InputStream fileInputStream = resource.getInputStream()) {
            Reader reader = new BufferedReader(new InputStreamReader(fileInputStream, StandardCharsets.UTF_8));
            return function.apply(reader);
        } catch (IOException e) {
            throw new YourRuntimeException("Could not process resource: " + resource.getFilename() + ", " + e.getMessage());
        }
    }
}

В ваших конкретных реализациях вы можете теперь сделать что-то вроде этого:

public class XImpl extends ResourceProcessingService implements X {

    public double performSomeResourceProcessing() {
        return processResource(yourResource, (reader) -> readTheResource(reader));
    }

    private double readTheResource(Reader reader) {
        // perform the resource reading
    }
}
...