Обзор
Конечная цель Spring — упростить разработку приложений.. С точки зрения непрофессионала, сократите повторяющийся код и напишите меньше кода для достижения той же цели. Аспектно-ориентированное программирование (АОП, Аспектно-ориентированное программирование) — это способ уменьшить повторяющийся код. Все мы знаем, что JAVA — это язык объектно-ориентированного программирования (ООП, объектно-ориентированное программирование), который абстрагирует функциональные модули в объекты в java. Эти объекты дополняют приложения и службы, которые мы видели через определенные соединения. Его ядром является объект (Object).
Чтобы понять аспектное программирование, вам нужно сначала понять, что такое аспект. Разделите арбуз на две части с помощью ножа, а срез — это поверхность среза; для приготовления пищи кастрюля и плита работают вместе, чтобы завершить обжаривание, а кастрюля и плита — это поверхность среза. В структуре веб-иерархии, веб-уровень -> уровень шлюза -> уровень сервиса -> уровень данных, каждый уровень также является аспектом.В программировании между объектами и объектами, между методами и методами, между модулями и модулями есть все аспекты..
Классы должны быть чистыми и не должны содержать логику, не связанную с собой. Принцип единой ответственности.
Аспектное программирование может привести к отделению кода; в то же время аспектное программирование также требует выполнения кода, добавляя дополнительное выполнение кода. В соответствии с местными условиями используйте АОП.
Камень других гор
- Легко понять идею АОП (аспектно-ориентированное программирование):woo woo woo.cn, блог on.com/лицо волка, полное вопросов/боится…
- Вещь АОП: Аспектно-ориентированное программирование:OSCHINA.net/Huang Yong/No…
- Идеальное украшение ООП - принцип реализации SpringAOP АОП:woo woo woo.cn blog on.com/Chen Junping…
- АОП весенней серии:блог woo woo woo.cn на.com/news/fear/59…
образное понимание
Когда мы обычно выполняем действия, мы обычно проверяем правильность каждого интерфейса (начинается ли он, заканчивается и т. д.) и требует ли интерфейс входа пользователя.
Согласно нормальной логике, мы можем это сделать.
Есть проблема с этим, сколько раз требуется копия кода для такого количества интерфейсов. Для «ленивого человека» это невыносимо. Ну так придумайте публичный метод, чтобы каждый интерфейс вызывал этот интерфейс. Здесь немного нарезанной лапши.
Так же есть проблема, хотя мне и не нужно каждый раз копировать код, каждый интерфейс должен вызывать этот метод. Итак, есть концепция аспекта, когда я внедряю метод в вызываемый где-то интерфейс (pointcut).
Таким образом, интерфейсу нужно заботиться только о конкретном бизнесе, и ему не нужно обращать внимание на другую логику или обработку, которые интерфейс не заботит.
Красная рамка — аспектно-ориентированное программирование.
теория
Прежде чем использовать АОП, нам нужно понять несколько концепций.
Точка присоединения
Все возможные места, где аспекты должны быть введены. Такие как методы до и после, инициализация класса, инициализация свойства и так далее.
Точечная резка
Точка соединения, которая должна выполнять некоторую обработку (например, печать журналов, обработка кэшей и т. д.). Как указать pointcut? Spring использует язык выражений pointcut AspectJ для определения аспектов Spring.
Между несколькими выражениями можно использовать «и», «или» и «не» для логической связи.
Одним из наиболее сложных является исполнение.
В настоящее время Spring поддерживает только определения pointcut для методов.
Совет
Определите, когда что-то делать. Spring поддерживает типы уведомлений по 5 методам
Аспект
Коллекция советов + pointcuts, которые определяют, где и когда что делать.
Введение
Позволяет нам добавлять новые свойства метода в существующий класс. Разве это не применение аспекта (то есть нового атрибута метода: определение совета) к целевому классу?
Цель
Целевой класс, упомянутый во введении, то есть объект, который необходимо уведомить. То есть реальная бизнес-логика, которая может быть вплетена в аспект нами, сами того не зная. Вместо этого сосредоточьтесь на логике самого бизнеса.
Ткачество
Процесс применения аспекта к целевому объекту для создания нового прокси-объекта.
Принцип реализации АОП весной
Реализация АОП фактически использует режим прокси.
играет роль
Концепция агентства: Простое понимание состоит в том, что, создавая прокси-объект для объекта, мы не ссылаемся напрямую на исходный объект, но созданный прокси-объект управляет ссылкой на исходный объект.
По периоду создания агента класс агентов можно разделить на два типа.
- Статический прокси: создается программистом или автоматически генерируется специальным инструментом, а затем компилируется. Перед запуском программы файл .class прокси-класса уже существует.
- Динамический прокси: он создается динамически с использованием механизма отражения во время работы программы, без необходимости писать код вручную. Динамический прокси не только упрощает работу по программированию, но и повышает расширяемость программной системы, поскольку механизм отражения Java может генерировать класс динамического прокси любого типа.
Принцип агентства: прокси-объект содержит ссылку на реальный объект внутри, так что с реальным объектом можно манипулировать, а прокси-объект предоставляет тот же интерфейс, что и реальный объект, чтобы он мог заменить реальный объект в любое время. В то же время прокси-объект может добавлять другие операции при выполнении операций над реальным объектом, что эквивалентно инкапсуляции реального объекта.
Spring использует динамические прокси.
JDK динамического прокси
Сам java jdk поддерживает динамическое создание прокси-объектов.
Динамический прокси в Java имеет недостаток: он поддерживает только классы, реализующие интерфейсы. Таким образом, может быть введен прокси класса поддержки сторонней библиотеки cglib (библиотека генерации кода). Если вы заинтересованы в динамическом прокси-сервере JDK, вы можете обратиться к:blog.CSDN.net/U012410733/…
cglib динамического прокси
Если вас интересует библиотека cglib, вы можете обратиться к:blog.CSDN.net/Fade Out/Аретти…
Образец
Есть такое требование кэшировать или печатать логи для некоторых интерфейсов. Я не хочу вызывать метод кэширования или метод печати журнала в каждом интерфейсе. Ты можешь это сделать. Код:
- Определить абстрактный интерфейс животных: Animal
- Определение конкретного животного-кошки: Кошка
- Определите класс конфигурации сканирования компонента: AnimalConfig
- Определите аннотацию кеша: Кэш
- Определение аспекта кэша: CacheAspect
- Определение аспекта журнала: LogAspect
- Определите класс тестовой записи: Приложение
1. Интерфейс животных
package bean;
public interface Animal {
public String sayName(String name, Integer num);
}
2. Класс кошек
package bean;
import org.springframework.stereotype.Component;
@Component
public class Cat implements Animal {
@Cache(60)
public String sayName(String name, Integer num) {
return "this is cat " + name + "," + num;
}
}
3. Класс сканирования исходной конфигурации AnimalConfig
package bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AnimalConfig {
}
4. Аннотация Cache (используется вместе с CacheAspect)
package bean;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cache {
int value() default 0;
}
5. Аспект кеша CacheAspect
package bean;
import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
@Component
@Aspect
@Order(1000)
public class CacheAspect {
// 定义切入点:带有Cache注解的方法
@Pointcut("@annotation(Cache)")
private void cache(){}
// 临时存储区
private static Map<String, Object> cacheList = new LinkedHashMap<String, Object>();
// 定义环绕通知,处理接口/方法添加缓存
@Around("cache()")
private Object cacheAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
Object object = proceedingJoinPoint.getTarget();
Object[] args = proceedingJoinPoint.getArgs();
String className = object.getClass().getName();
MethodSignature signature = (MethodSignature)proceedingJoinPoint.getSignature();
Method method = signature.getMethod();
// 组装cache key
String cacheKey = className + "_" + method.getName() + "_" + JSONObject.toJSONString(args);
if (cacheList.containsKey(cacheKey)){
System.out.println("data get cache");
return cacheList.get(cacheKey);
}else {
System.out.println("data get db");
Object result = proceedingJoinPoint.proceed();
cacheList.put(cacheKey, result);
return result;
}
}
}
6. Аспект журнала LogAspect
package bean;
import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Aspect
@Order(100)
public class LogAspect {
//定义切点:包含任意参数的、任意返回值、的公共方法sayName
@Pointcut("execution(public * *sayName(..))")
private void log(){}
//定义环绕通知:处理日志注入
@Around("log()")
private Object logAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object[] args = proceedingJoinPoint.getArgs();
System.out.println("before, params:" + JSONObject.toJSONString(args));
Object result = proceedingJoinPoint.proceed();
System.out.println("after, result:" + JSONObject.toJSONString(result));
return result;
}
}
7. Класс входа в тест APP
import bean.Animal;
import bean.AnimalConfig;
import bean.Cat;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class App {
public static void main(String[] args){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AnimalConfig.class);
Animal animal = applicationContext.getBean("cat", Cat.class);
String result = animal.sayName("rudytan", 12);
String result1 = animal.sayName("rudytan", 12);
String result2 = animal.sayName("rudytan", 12);
String result3 = animal.sayName("rudytan", 13);
String result4 = animal.sayName("rudytan", 13);
System.out.println(result);
}
}
инструкция:
- @Cache — это пользовательская аннотация (отмечающая необходимость кэширования метода)
- @EnableAspectJAutoProxy — включить ли динамический прокси cglib
- @Aspect определяет класс как класс аспекта
- @Order определяет порядок выполнения при наличии нескольких классов фасетов.Чем больше значение, тем выполняется первое выполнение.
- @Pointcut определяет текущую функцию как pointcut.
- @Around определяет объемные уведомления