Понятия

Модель срезов из Spring позволяет повторно использовать срезы независимо от типов советов. Можно ориентировать разные типы советов с помощью одного и того же среза.

Интерфейс org.springframework.aop.Pointcut является центральным интерфейсом, используемым для ориентирования советов на определенные классы и методы. Ниже приведен полный интерфейс:

public interface Pointcut {
    ClassFilter getClassFilter();
    MethodMatcher getMethodMatcher();
}

Разделение интерфейса Pointcut на две части позволяет повторно использовать части сопоставляемых классов и методов, а также производить тонкие операции компонования (например, выполнять "объединение" с другим средством сопоставления методов (method matcher)).

Интерфейс ClassFilter используется для ограничения среза заданным набором целевых классов. Если метод matches() всегда возвращает true, то совпадают все целевые классы. В следующем листинге показано определение интерфейса ClassFilter:

public interface ClassFilter {
    boolean matches(Class clazz);
}

Интерфейс MethodMatcher обычно более важен. Ниже приведен полный интерфейс:

public interface MethodMatcher {
    boolean matches(Method m, Class<?> targetClass);
    boolean isRuntime();
    boolean matches(Method m, Class<?> targetClass, Object... args);
}

Метод matches(Method, Class) используется для того, чтобы проверить, соответствует ли данный срез данному методу в целевом классе. Это вычисление может быть выполнено при создании прокси АОП, чтобы избежать необходимости проведения проверки при каждом вызове метода. Если метод matches с двумя аргументами возвращает true для данного метода, а метод isRuntime() возвращает true для MethodMatcher, то метод соответствия с тремя аргументами будет вызван при каждом вызове метода. Это позволяет срезу просматривать аргументы, переданные в вызов метода непосредственно перед началом выполнения целевого совета.

Большинство реализаций MethodMatcher являются статическими, что означает, что их метод isRuntime() возвращает false. В этом случае метод matches с тремя аргументами никогда не вызывается.

Если возможно, постарайтесь сделать срезы статичными, позволив АОП-фреймворку кэшировать результаты вычисления срезов при создании прокси АОП.

Операции над срезами

Spring поддерживает операции (в частности, объединение и пересечение) над срезами.

Объединение означает методы, которые совпадают с любым из срезов. Пересечение означает методы, которые совпадают с обоими срезами. Объединение обычно более практичная операция. Вы можете компоновать срезы с помощью статических методов класса org.springframework.aop.support.Pointcuts или с помощью класса ComposablePointcut из того же пакета. Однако использование выражений срезов из AspectJ обычно является более простым подходом.

Срезы выражений AspectJ

Начиная с версии 2.0, наиболее важным типом среза, используемым Spring, является org.springframework.aop.aspectj.AspectJExpressionPointcut. Это срез, который использует библиотеку, поставляемую AspectJ, для синтаксического анализа строки выражения среза из AspectJ.

Обсуждение поддерживаемых срезов-примитивов из AspectJ см. в предыдущей главе.

Удобные реализации срезов

Spring предоставляет несколько удобных реализаций срезов. Некоторые из них можно использовать напрямую; другие предназначены для построения подклассов в специфических для приложения срезах.

Статические срезы

Статические срезы основаны на методе и целевом классе и не могут учитывать аргументы метода. Для большинства случаев использования достаточно статических срезов - и они лучше всего. Spring может вычислить статический срез только один раз, если метод вызывается впервые. После этого нет необходимости повторно вычислять срез при каждом вызове метода.

В остальной части этого раздела описаны некоторые реализации статических срезов, которые включены в Spring.

Срезы регулярных выражений

Одним из очевидных способов задания статических срезов являются регулярные выражения. Несколько АОП-фреймворков, помимо Spring, позволяют осуществлять это. org.springframework.aop.support.JdkRegexpMethodPointcut – это общий срез регулярного выражения, который использует поддержку регулярных выражений в JDK.

С помощью класса JdkRegexpMethodPointcut можно указать список строк шаблонов. Если любая из них совпадет, то срез примет значение true. (Как следствие, результирующий срез фактически будет объединением указанных шаблонов).

В следующем примере показано, как использовать

<bean id="settersAndAbsquatulatePointcut"
        class="org.springframework.aop.support.JdkRegexpMethodPointcut">
    <property name="patterns">
        <list>
            <value>.*set.*</value>
            <value>.*absquatulate</value>
        </list>
    </property>
</bean>

Spring предоставляет удобный класс RegexpMethodPointcutAdvisor, который позволяет также ссылаться на Advice (помните, что Advice может быть советом "перехват", советом "перед", советом "генерация исключения" и другими). За кулисами Spring использует JdkRegexpMethodPointcut. Использование RegexpMethodPointcutAdvisor упрощает связывание, так как один боб инкапсулирует и срез, и совет, как показано в следующем примере:

<bean id="settersAndAbsquatulateAdvisor"
        class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice">
        <ref bean="beanNameOfAopAllianceInterceptor"/>
    </property>
    <property name="patterns">
        <list>
            <value>.*set.*</value>
            <value>.*absquatulate</value>
        </list>
    </property>
</bean>

Вы можете использовать RegexpMethodPointcutAdvisor с любым типом Advice.

Срезы, управляемые атрибутами

Важным типом статического среза является срез, управляемый метаданными. При этом используются значения атрибутов метаданных (как правило, метаданных на уровне источника).

Динамические срезы

Вычисление динамических срезов более ресурсоемкая задача. Эти срезы учитывают аргументы метода, а также статическую информацию. Это означает, что их вычисление необходимо производить при каждом вызове метода и что результат нельзя кэшировать, так как аргументы будут меняться.

Основным примером является срез control flow.

Срезы потока управления

Срезы потока управления (control flow pointcuts) из Spring концептуально похожи на срезы cflow из AspectJ, хотя и не столь эффективные. (В настоящее время не существует способа, позволяющего задать, чтоб срез проходил ниже точки соединения, совпадающей с другим срезом.) Срез потока управления совпадает с текущим стеком вызовов. Например, он может сработать, если точка соединения была вызвана методом из пакета com.mycompany.web или классом SomeCaller. Срезы потока управления задаются с помощью класса org.springframework.aop.support.ControlFlowPointcut.

Срезы потока управления значительно более затратно вычислять во время выполнения программы, чем даже другие динамические срезы. В Java 1.4 затратность примерно в пять раз выше, чем для других динамических срезов.

Суперклассы срезов

Spring предоставляет практичные суперклассы (родительские классы) срезов, которые могут помочь реализовать ваши собственные срезы.

Java
class TestStaticPointcut extends StaticMethodMatcherPointcut {
    public boolean matches(Method m, Class targetClass) {
        // возвращает true, если специально заданные критерии совпадают
    }
}
Kotlin
class TestStaticPointcut : StaticMethodMatcherPointcut() {
    override fun matches(method: Method, targetClass: Class<*>): Boolean {
        // возвращает true, если специально заданные критерии совпадают
    }
}

Существуют также суперклассы для динамических срезов. Вы можете использовать специальные срезы с любым типом советов.

Специальные срезы

Поскольку срезы в Spring AOP являются классами Java, а не функциями языка (как в AspectJ), вы можете объявлять специальные срезы, как статические, так и динамические. Специальные срезы в Spring могут быть произвольно сложными. Однако рекомендуется использовать язык выражений срезов AspectJ, если это возможно.

Более поздние версии Spring могут обеспечивать поддержку "семантических срезов", как предложено в JAC – например, "любые методы, которые изменяют переменные экземпляра в целевом объекте".