Spring AOP бессилен для классов с интерфейсами - PullRequest
0 голосов
/ 03 октября 2018

Я понимаю, что Spring AOP очень ограничен в своих возможностях (он может разрезать только открытые методы классов, которые являются бобами Spring, и только тогда, когда эти методы вызываются извне класса).Но теперь я обнаружил еще одно ограничивающее ограничение, когда задействованы интерфейсы.

Обычно, если класс находится в подклассах, у Spring AOP нет проблем с разрезанием всех их методов (даже переопределенных):

public class A {
    public void methodA() { } //OK, can cut in
}

public class B extends A {
    @Override
    public void methodA() { } //OK, can cut in

    public void methodB() { } //OK, can cut in
}

Но когда мы добавляем интерфейс в микшер, для Spring AOP все становится очень плохо:

public interface I {
    public void methodA();
}

public class A implements I {
    @Override
    public void methodA() { } //OK, can cut in

    public void methodB() { } //Fail, cannot see or cut into this method
}

public class B extends A {
    @Override
    public void methodA() { } //Fail, cannot see or cut into this method

    public void methodC() { } //Fail, cannot see or cut into this method
}

Прежде всего, Spring AOP может разрезать только методы, которые есть в интерфейсе, и все остальное.- он не может видеть.Во-вторых, он может врезаться только в метод, который непосредственно реализует метод интерфейса - A.methodA().Он не может быть разрезан на тот же метод, переопределенный с помощью B.

Я использую универсальное выражение pointcut "execution(* method*(..))", чтобы разрезать все возможные методы, поэтому это не проблема с выражением.

Есть ли какие-либообойти это ограничение?Или я должен просто забыть о Spring AOP и использовать другой подход?

ОБНОВЛЕНИЕ: Хорошо, я нашел реальную причину проблемы.Я на самом деле полагался на плагин Intellij IDEA AOP, чтобы проверить это.Предполагается связать pointcut со всеми задействованными методами.Но он использовал «старую», динамическую JDK-прокси-стратегию вместо новой CGLIB-стратегии.Так что это не связывало его со всеми методами, но когда я фактически запустил свою программу, она правильно обрезала все методы.

Я использую Spring Boot 2, который использует «новую» стратегию CGLIB.Но на SB1 он все еще может использовать «старую» динамическую стратегию JDK-прокси, поэтому он все еще может там не работать.

1 Ответ

0 голосов
/ 03 октября 2018

Spring будет использовать динамический прокси или cglib для реализации AOP.

Cglib выбирается, если нет интерфейса, тогда он будет эффективно создавать подкласс целевого класса и переопределять все методы в целевом классе.,Таким способом могут быть включены все методы, кроме final и static.

В случае, если целевой класс имеет интерфейс, Spring может использовать динамический прокси-сервер, использующий один из интерфейсов, и, очевидно, это повлияет только наметоды, объявленные в интерфейсе.

До Spring-Boot 2.0 динамический прокси является стратегией по умолчанию.Теперь Cglib является стратегией по умолчанию после весенней загрузки 2.0.

Мне кажется, что весна, вероятно, использует динамический прокси-подход в вашем случае.Вы можете добавить spring.aop.proxy-target-class: true в ваш application.yaml, чтобы принудительно использовать Cglib.

Если у вас все еще есть проблема, лучше выложить более полный кодфрагмент, показывающий, как вызывается метод.

...