Поняття

Модель зрізів зі 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 — наприклад, "будь-які методи, які змінюють змінні екземпляра в цільовому об'єкті".