моя контактная информация
Почтамезофия@protonmail.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Прокси относится к режиму, в котором объект A может вести себя так же, как B, удерживая другой объект B. Чтобы открыть протокол внешнему миру, B часто реализует интерфейс, и A также реализует этот интерфейс. Но B — это «настоящий» класс реализации, а A — более «виртуальный». Он заимствует методы B для реализации методов интерфейса. Хотя A — это «псевдоармия», она может усиливать B и делать другие вещи до и после вызова метода B. Spring AOP использует динамические прокси для завершения динамического «плетения» кода.
Преимущества использования прокси выходят за рамки этого. Если проект использует интерфейс, предоставленный другим проектом, но интерфейс другого проекта нестабильен и протокол часто меняется, вы можете использовать прокси. При изменении интерфейса вы можете использовать прокси. нужно только изменить прокси, а не изменять бизнес-код по одному. В этом смысле мы можем сделать это для всех интерфейсов, которые адаптируются к внешнему миру, чтобы предотвратить вторжение внешнего кода в наш код. Это называется защитным программированием. Может быть много других приложений для проксирования.
В приведенном выше примере класс A жестко запрограммирован для хранения B, который является статическим прокси-сервером B. Если объект прокси неясен, это динамический прокси. В настоящее время существует две распространенные реализации динамического прокси: динамический прокси jdk и динамический прокси cglib.
Статический прокси — это шаблон проектирования и тип шаблона прокси. В статическом прокси-классе прокси-класс определяется до запуска программы, а связь между прокси-классом и прокси-классом определяется во время компиляции. Это означает, что и прокси-класс, и прокси-класс реализуют один и тот же интерфейс или наследуют один и тот же родительский класс. Прокси-класс внутри себя содержит экземпляр прокси-класса и одновременно вызывает методы прокси-класса. , он может добавлять некоторые ваши собственные операции до и после вызова, такие как ведение журнала, проверка разрешений, обработка транзакций и т. д.
Статический прокси состоит из трех компонентов: абстрактный интерфейс, прокси-класс и прокси-класс. Примеры его реализации следующие:
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class TargetProxy implements TargetInteface {
-
- private Target target =new Target();
- @Override
- public void method1() {
- System.out.println("执行方法前...");
- target.method1();
- System.out.println("执行方法后...");
- }
-
- @Override
- public void method2() {
- System.out.println("执行方法前...");
- target.method2();
- System.out.println("执行方法后...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("执行方法前...");
- int method3 = target.method3(i);
- System.out.println("执行方法后...");
- return method3;
- }
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println(" Target method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("Target method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("Target method3 running ...");
- return i;
- }
- }
- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = new TargetProxy();
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
Вывод результата:
Прежде чем выполнить метод...
Целевой метод1 работает ...
После выполнения метода...
-----------------------------
Прежде чем выполнить метод...
Целевой метод2 работает ...
После выполнения метода...
-----------------------------
Прежде чем выполнить метод...
Целевой метод3 работает ...
После выполнения метода...
3
Из реализации статических агентов нетрудно увидеть, что преимущества статических агентов заключаются в простоте реализации и легкости понимания. Но очевидны и его недостатки, то есть всякий раз, когда вам нужно добавить функционал прокси в новый класс, вам придется вручную создавать новый прокси-класс, что приведет к резкому увеличению количества классов и увеличению затрат на обслуживание. . В то же время степень связи между прокси-классом и прокси-классом слишком высока. Когда методы добавляются, удаляются или изменяются в прокси-классе, соответствующие методы также должны быть добавлены, удалены или изменены в прокси-классе. , что снижает затраты на обслуживание кода. Другая проблема заключается в том, что когда прокси-объект замещает классы реализации нескольких целевых интерфейсов, в нескольких классах реализации должны быть разные методы. Поскольку прокси-объект должен реализовывать тот же интерфейс, что и целевой объект (фактически это отношение включения), он должен. быть написаны Многочисленные методы могут легко привести к раздутому и сложному в сопровождении коду.
Основная идея динамического прокси заключается в косвенном доступе к исходному объекту через прокси-объект без изменения исходного объектного кода и выполнении дополнительных операций до и после доступа.
Принцип реализации динамического прокси в основном основан на механизме отражения Java. При использовании динамических прокси вам необходимо определить интерфейс или набор интерфейсов, которые определяют поведение проксируемого класса (проксируемого объекта).Затем вам нужно написать реализациюInvocationHandler
Класс интерфейса. Этот класс содержит логику, которая выполняется до и после вызова метода прокси-объекта.при звонкеProxy.newProxyInstance()
метод, передайте загрузчик классов интерфейса, массив интерфейса иInvocationHandler
Object, Java будет динамически генерировать прокси-класс, реализующий указанный интерфейс во время выполнения, и делегировать вызовы методовInvocationHandler
объекты для обработки.Когда вызывается метод прокси-объекта, он фактически вызываетInvocationHandler
Интерфейсinvoke()
Метод, в котором вы можете выполнить некоторую логику предварительной обработки на основе имени метода, параметров и другой информации, а затем вызвать соответствующий метод прокси-объекта посредством отражения.
Далее мы представляем два динамических прокси: JDK Proxy и CGLib.
JDK Proxy использует механизм отражения Java для динамического создания прокси-классов. Конкретно,Proxy
класс будет использоватьProxyGenerator
class (хотя этот класс не является общедоступным API, он является ключом к реализации динамического проксирования внутри JDK) для генерации байт-кода прокси-класса и загрузки его в JVM.Сгенерированный прокси-класс будет наследовать отjava.lang.reflect.Proxy
class и реализовать указанный интерфейс.В методе прокси-класса он будет называтьсяInvocationHandler
изinvoke
Метод, пересылает вызов метода процессору для обработки.
Кроме того, для повышения производительности JDK Proxy также предоставляет механизм кэширования объекта Class созданного прокси-класса. Таким образом, когда вам нужно создать прокси-объект того же типа, вы можете напрямую получить объект класса прокси-класса из кэша, не создавая его повторно.Кэширование осуществляется черезWeakCache
Реализованный классом, он использует слабые ссылки на объекты кэша, чтобы элементы кэша, которые больше не используются, можно было автоматически очищать, когда JVM выполняет сбор мусора.
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
InvocationHandler
интерфейс и переписатьinvoke
метод.существоватьinvoke
В методе вы можете добавить собственную логику, такую как ведение журнала, проверку разрешений и т. д., и вызывать исходный метод класса посредством отражения.Proxy.newProxyInstance
метод, передавая загрузчик классов, массив интерфейса иInvocationHandler
Экземпляр для динамического создания прокси-объектов. Этот метод возвращает экземпляр прокси-класса, реализующий указанный интерфейс.- public class TargetProxy {
- public static <T> Object getTarget(T t) {
- //新构建了一个 新的 代理类的对象
- return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
- //比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
- System.out.println("执行方法前...");
- Object invoke = method.invoke(t, args);
- System.out.println("执行方法后...");
- return invoke;
- }
- });
- }
- }
InvocationHandler
изinvoke
Метод, в котором выполняется пользовательская логика, а затем вызывается метод исходного класса.- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
Вывод результата:
Прежде чем выполнить метод...
метод1 работает ...
После выполнения метода...
-----------------------------
Прежде чем выполнить метод...
метод2 работает ...
После выполнения метода...
-----------------------------
Прежде чем выполнить метод...
метод3 работает ...
После выполнения метода...
3
MethodInterceptor
интерфейс для определения перехватчика метода, который будет выполнять пользовательскую логику до и после вызова метода прокси-объекта, например предварительную обработку, постобработку, обработку исключений и т. д.- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
- import java.lang.reflect.Method;
- public class Target {
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
MethodInterceptor
класс интерфейса и переопределитьintercept
метод. Напишите логику прокси в этом методе.Enhancer
класс для создания прокси-объектов.Вам необходимо установить прокси-класс (черезsetSuperclass
метод) и обратные вызовы (черезsetCallback
Метод устанавливает класс реализации MethodInterceptor).- public class TargetProxy {
- public static <T> Object getProxy(T t) {
- Enhancer en = new Enhancer(); //帮我们生成代理对象
- en.setSuperclass(t.getClass());//设置要代理的目标类
- en.setCallback(new MethodInterceptor() {//代理要做什么
- @Override
- public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
- System.out.println("执行方法前。。。");
- //调用原有方法
- Object invoke = methodProxy.invokeSuper(object, args);
- // Object invoke = method.invoke(t, args);// 作用等同与上面。
- System.out.println("执行方法后。。。");
- return invoke;
- }
- });
- return en.create();
- }
- }
intercept
Прокси-логика в методах.- public class TargetUser {
-
- public static void main(String[] args) {
- Target target = (Target) TargetProxy.getProxy(new Target());
- System.out.println(target.getClass().getName());
- target.method1();
- }
-
- }
Вывод результата:
com.heaboy.aopdemo.cglibproxy.ЦельЭнчасансерБуСгЛяБф9ф41фб8
перед выполнением метода. . .
метод1 работает ...
После выполнения метода. . .
преимущество:
недостаток:
Тип прокси-объекта:JDK Proxy может проксировать только классы, реализующие интерфейсы, тогда как CGLib может напрямую проксировать обычные классы.
производительность: CGLib генерирует подклассы прокси-классов во время выполнения и обычно считается, что он работает немного лучше, чем JDK Proxy. Но в большинстве сценариев эта разница в производительности незначительна.
сцены, которые будут использоваться: Если целевой объект уже реализует интерфейс, использование JDK Proxy — простой и понятный выбор. Если вам нужно проксировать класс, который не реализует интерфейс, вы должны использовать CGLib.
полагаться:JDK Proxy не требует дополнительных зависимостей, поскольку он является частью базовой библиотеки Java, тогда как CGLib требует добавления библиотеки CGLib в качестве зависимости проекта;
JDK Proxy — это функция, которая поставляется с языком Java и не требует реализации путем загрузки сторонних классов;
Java обеспечивает стабильную поддержку JDK Proxy и будет продолжать обновлять и обновлять JDK Proxy. Например, производительность JDK Proxy в версии Java 8 значительно улучшилась по сравнению с предыдущими версиями;
JDK Proxy реализуется посредством перехватчиков и отражения;
JDK Proxy может проксировать только классы, наследующие интерфейсы;
JDK Proxy относительно прост в реализации и вызове;
CGLib — это инструмент, предоставленный третьей стороной, реализованный на основе ASM и обладающий относительно высокой производительностью;
CGLib не нужно реализовывать через интерфейс, он вызывается путем реализации подкласса.
Статический прокси: Статические прокси определяются во время компиляции. Прокси-класс должен быть написан для каждого прокси-класса. Прокси-класс и прокси-класс реализуют один и тот же интерфейс или наследуют один и тот же родительский класс.
Прокси-класс статического прокси существует во время компиляции, поэтому он может проксировать только определенные классы во время работы программы и не может динамически решать, какие классы проксировать.
Статический прокси оборачивает вызов метода исходного объекта и может добавлять дополнительную логику до и после вызова, но класс прокси необходимо написать заранее, что увеличит объем кода.
Статический прокси явно определяет прокси-объект в коде и относительно интуитивно понятен в использовании, но добавление новых прокси-классов требует перекомпиляции.
Динамический прокси: Динамический прокси создает прокси-объекты во время выполнения без предварительного написания прокси-классов. Используйте механизм отражения Java для динамического создания прокси-классов и прокси-объектов.
Динамические прокси основаны на интерфейсах и реализуются через класс java.lang.reflect.Proxy и интерфейс java.lang.reflect.IndictionHandler.
Динамический прокси может проксировать классы нескольких интерфейсов и динамически решать, какие классы проксировать. Во время выполнения по мере необходимости для различных объектов могут создаваться прокси, что обеспечивает большую гибкость.
Динамическому прокси не нужно писать отдельный класс прокси для каждого класса прокси, что является более гибким и позволяет экономить код.
Динамические агенты могут добавлять пользовательскую логику до и после вызовов методов прокси-объекта, например ведение журнала, управление транзакциями и т. д. Недостаток динамического прокси заключается в том, что по сравнению со статическим прокси создание прокси-объекта во время выполнения требует определенных затрат на производительность.
Статические прокси подходят для следующих сценариев:
Когда количество целевых объектов (прокси-объектов) ограничено и определено, статический прокси можно реализовать путем написания прокси-классов вручную. Статические прокси создают прокси-классы во время компиляции, поэтому они имеют более высокую производительность во время выполнения.
Статические прокси инкапсулируют целевой объект и добавляют дополнительные функции без изменения исходного кода. Из-за этого статические прокси часто используются для решения сквозных задач, таких как ведение журналов и управление транзакциями.
Динамический прокси подходит для следующих сценариев:
Если количество целевых объектов неопределенно или не может быть определено заранее, динамические прокси-серверы могут более удобно генерировать прокси-объекты. Он генерирует прокси-классы и прокси-объекты во время выполнения, избегая утомительной работы по написанию нескольких прокси-классов вручную.
Динамические прокси обеспечивают гибкость добавления, удаления или изменения поведения прокси для целевых объектов во время выполнения. Это делает динамические прокси часто используемыми в сценариях приложений, таких как АОП (аспектно-ориентированное программирование) и RPC (удаленный вызов процедур).
Следует отметить, что поскольку динамические прокси создают прокси-классы и прокси-объекты посредством механизма отражения во время выполнения, их производительность может быть немного ниже, чем у статических прокси. Кроме того, динамические прокси могут проксировать только целевые объекты, реализующие интерфейс, тогда как статические прокси не имеют этого ограничения.
Подводя итог, статические прокси подходят для сценариев, где количество целевых объектов ограничено и определено и требуют инкапсуляции и дополнительных функций, тогда как динамические прокси подходят для сценариев, где количество целевых объектов неопределенно или не может быть определено заранее; и поведение прокси необходимо гибко добавлять, удалять или изменять. Выберите подходящий метод агентства, исходя из конкретных потребностей и обстоятельств.
Spring AOP — важный модуль в среде Spring, используемый для реализации аспектно-ориентированного программирования.
Программирование лицом к лицу Это модель программирования, которая позволяет программистам выполнять модульную структуру с помощью пользовательских точек пересечения и инкапсулировать поведение, влияющее на несколько классов, в модули многократного использования. Пример. Например, вывод журнала. Если вы не используете АОП, вам необходимо поместить операторы вывода журнала во все классы и методы. Однако с помощью АОП вы можете инкапсулировать операторы вывода журнала в модуль многократного использования и поместить их в модуль. декларативным образом. В классе вывод журнала автоматически завершается каждый раз, когда используется класс.
В идее аспектно-ориентированного программирования функции делятся на два типа
Основной бизнес: Вход, регистрация, добавление, удаление, изменение и запрос — все это называется основной деятельностью.
Периферийные функции: Журналы и управление транзакциями являются вторичными периферийными службами.
В аспектно-ориентированном программировании основные бизнес-функции и периферийные функции разрабатываются независимо, и они не связаны между собой. Затем аспектные функции и основные бизнес-функции «сплетаются» вместе, что называется АОП.
АОП может конвертировать те, которые не связаны с бизнесом,Но он инкапсулирован для логики или обязанностей (таких как обработка транзакций, управление журналами, контроль разрешений и т. д.), обычно вызываемых бизнес-модулями.,легкоУменьшите дублирование кода в системе,Уменьшить связь между модулями,иСпособствует будущей масштабируемости и ремонтопригодности.。
В АОП существуют следующие концепции:
АспектJ: Аспект — это всего лишь концепция. Не существует конкретного интерфейса или класса, соответствующего ему. Это собирательное название для точки соединения, совета и Pointcut.
Точка соединения : Точка соединения относится к точке во время выполнения программы, например вызову метода, обработке исключений и т. д. В Spring AOP поддерживаются только точки соединения на уровне метода.
Совет : Уведомление, то есть сквозная логика в определенном нами аспекте, имеет три типа: «вокруг», «до» и «после». Во многих средах реализации АОП Advice обычно действует как перехватчик, а также может содержать множество перехватчиков в качестве ссылки, которая должна обрабатываться вокруг точки соединения.
Точечный срез: Pointcut, используется для сопоставления точек соединения. Какие точки соединения, содержащиеся в AspectJ, необходимо фильтровать с помощью Pointcut.
Введение : Введение, позволяющее аспекту объявить, что рекомендуемые объекты реализуют любые дополнительные интерфейсы, которые они на самом деле не реализуют. Например, прокси-объект можно использовать для проксирования двух целевых классов.
Ткачество : Сотка, теперь, когда у нас есть точки подключения, точки обрезки, уведомления и аспекты, как их применить в программе? Правильно, это плетение. Под руководством pointcuts логика уведомлений вставляется в целевой метод, чтобы наша логика уведомлений могла выполняться при вызове метода.
АОП прокси : Прокси-сервер АОП относится к объекту, который реализует протокол аспекта в структуре реализации АОП. В Spring AOP есть два типа прокси: динамический прокси JDK и динамический прокси CGLIB.
Целевой объект: Целевой объект — это проксируемый объект.
Spring AOP реализован на основе динамического прокси-сервера JDK и расширения Cglib. Оба метода прокси являются методами времени выполнения, поэтому у них нет обработки во время компиляции, поэтому Spring реализуется через код Java.
Некоторые общие действия, разбросанные по нескольким классам или объектам (например, ведение журнала, управление транзакциями, контроль разрешений, ограничение тока интерфейса, мощность интерфейса и т. д.), эти действия обычно называются сквозные проблемы . Если мы реализуем такое поведение неоднократно в каждом классе или объекте, это приведет к созданию избыточного, сложного и трудно поддерживаемого кода.
АОП может преобразовать сквозные задачи (такие как ведение журнала, управление транзакциями, контроль разрешений, ограничение тока интерфейса, питание интерфейса и т. д.) из Основная бизнес-логика (основные проблемы, основные проблемы) Отделиться от фокуса, чтобы добиться разделения задач.
Ведение журнала: настройте аннотации журнала и используйте AOP для ведения журнала с помощью одной строки кода.
Статистика производительности: используйте АОП для подсчета времени выполнения метода до и после выполнения целевого метода, чтобы облегчить оптимизацию и анализ.
Управление транзакциями:@Transactional
Аннотации позволяют Spring выполнять за нас управление транзакциями, например откат операций исключений, устраняя повторяющуюся логику управления транзакциями.@Transactional
Аннотации реализованы на основе АОП.
Контроль разрешений: используйте АОП, чтобы определить, имеет ли пользователь необходимые разрешения перед выполнением целевого метода. Если да, выполните целевой метод, иначе он не будет выполнен.Например, SpringSecurity использует@PreAuthorize
Вы можете настроить проверку разрешений, прокомментировав строку кода.
Ограничение тока интерфейса: используйте AOP для ограничения запроса с помощью определенных алгоритмов и реализаций ограничения тока до выполнения целевого метода.
Управление кешем: используйте АОП для чтения и обновления кеша до и после выполнения целевого метода.
Общие методы реализации АОП включают динамический прокси, операции с байт-кодом и т. д.
Spring AOP основан на динамическом прокси. Если проксируемый объект реализует определенный интерфейс, то Spring AOP будет использовать его. JDK-прокси, чтобы создать прокси-объект. Для объектов, которые не реализуют интерфейс, вы не можете использовать прокси-сервер JDK. В настоящее время Spring AOP будет использовать. Cglib Создайте подкласс прокси-объекта, который будет служить прокси.
существоватьspring-aop.xml
Настройте связанные bean-компоненты и аспекты в файле конфигурации.
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
-
- <bean id="target" class="com.xxhh.aopdemo.aop.Target"/>
-
- <bean id="targetAdvice" class="com.xxhh.aopdemo.aop.TargetAdvice"/>
-
- <bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="target" ref="target"/> <!--被代理的类-->
- <property name="interceptorNames" value="targetAdvice"/> <!--如果用多种增强方式,value的值使用逗号(,)分割-->
- <property name="proxyTargetClass" value="false"/> <!--如果设置为true,则创建基于类的代理(使用CGLIB);如果设置为false,则创建基于接口的代理(使用JDK动态代理)。-->
- <property name="interfaces" value="com.xxhh.aopdemo.aop.TargetInteface"/> <!--target实现的接口-->
- </bean>
- </beans>
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface{
-
- /*
- * 需要增强的方法,连接点JoinPoint
- **/
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
- public class TargetAdvice implements MethodInterceptor, MethodBeforeAdvice, AfterReturningAdvice {
-
- /*
- * 通知/增强
- **/
- @Override
- public Object invoke(MethodInvocation methodInvocation) throws Throwable {
- System.out.println("前置环绕通知");
- Object proceed = methodInvocation.proceed();
- System.out.println("后置环绕通知");
- return proceed;
- }
-
- @Override
- public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
- System.out.println("后置返回通知");
- }
-
- @Override
- public void before(Method method, Object[] args, Object target) throws Throwable {
- System.out.println("前置通知");
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-aop.xml");
- TargetInteface targetProxy = (TargetInteface) appCtx.getBean("targetProxy");
- targetProxy.method1();
- }
- }
Результат вывода:
Уведомление на передней панели объемного звучания
Предварительное уведомление
метод1 работает ...
почтовое уведомление о возврате
Уведомление об объемном тылу
существоватьspring-confaop.xml
Настройте связанные bean-компоненты и аспекты в файле конфигурации.
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- /*
- * 目标类
- **/
- public class Target {
-
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- /*
- * 连接点JoinPoint
- **/
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- // int i1 = 1 / i;
- return i;
- }
- }
- import org.aspectj.lang.ProceedingJoinPoint;
- /*
- * 切面类
- **/
- public class TargetAspect {
-
- /*
- * 前置通知
- **/
- public void before() {
- System.out.println("conf前置通知");
- }
-
- public void after() {
- System.out.println("conf后置通知");
- }
-
- public void afterReturning() {
- System.out.println("conf后置返回通知");
- }
-
- public void afterThrowing(Exception ex) throws Exception {
- // System.out.println("conf异常通知");
- // System.out.println(ex.getMessage());
- }
-
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("conf环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("conf环绕后置");
- }
- return proceed;
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-confaop.xml");
- Target targetProxy = (Target) appCtx.getBean("target");
- System.out.println(targetProxy.method3(0));
- }
- }
Результат вывода:
предварительное уведомление conf
префикс объемного звука conf
метод3 работает ...
conf уведомление после возврата
объемный пост conf
уведомление о сообщении conf
0
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface TestAnnotation{
- }
- /*
- * 切面类
- **/
- @Aspect
- @Component
- public class AnnotationAspect {
-
- // 定义一个切点:所有被RequestMapping注解修饰的方法会织入advice
- @Pointcut("@annotation(TestAnnotation)")
- private void advicePointcut() {}
-
- /*
- * 前置通知
- **/
- @Before("advicePointcut()")
- public void before() {
- System.out.println("annotation前置通知");
- }
-
- @After("advicePointcut()")
- public void after() {
- System.out.println("annotation后置通知");
- }
-
- @AfterReturning(pointcut = "advicePointcut()")
- public void afterReturning() {
- System.out.println("annotation后置返回通知");
- }
-
- @AfterThrowing(pointcut = "advicePointcut()", throwing = "ex")
- public void afterThrowing(Exception ex) throws Exception {
- System.out.println("annotation异常通知");
- System.out.println(ex.getMessage());
- }
-
- @Around("advicePointcut()")
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("annotation环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("annotation环绕后置");
- }
- return proceed;
- }
- }
- @Controller
- public class TestController {
-
- @RequestMapping("/test.do")
- @ResponseBody
- public String testController() {
- TestController o = (TestController) AopContext.currentProxy();
- o.test();
- // System.out.println("tewt");
- return "ok";
- }
-
- @TestAnnotation
- public void test() {
- System.out.println("test running");
- }
-
- }