Пружинный сердечник серии АОП (1)
Всем привет, сегодня я расскажу вам об АОП в Spring, аспектно-ориентированном программировании, которое занимает важное место во всей системе Spring. Эта статья все еще основана на практике, аннотации введены, хорошо, структура статьи:
- @AspectJ в деталях
- Spring AOP — аннотации AspectJ
1. Происхождение @AspectJ
Когда дело доходит до AspectJ, на самом деле у многих людей возникают недопонимания. Многие люди знают только набор аннотаций Aspect, используемых в Spring, думая, что это набор аннотаций, разработанных Spring. Здесь я чувствую себя ответственным за уточнение с вами.AspectJ — это АОП-фреймворк, который может выполнять АОП-компиляцию java-кода (обычно во время компиляции), так что java-код имеет АОП-функцию AspectJ (конечно, требуется специальный компилятор).Можно сказать, что AspectJ — это наиболее В настоящее время реализована структура АОП.Зрелый, наиболее многофункциональный язык, и, к счастью, AspectJ полностью совместим с программами Java, почти бесшовно, поэтому для инженеров с базой программирования Java очень легко начать работу и использовать.По сути, AspectJ — это отдельный язык, для него нужен специальный компилятор (компилятор ajc). Цель Spring AOP и ApectJ одна и та же, оба должны одинаково заниматься сквозным бизнесом, но, в отличие от AspectJ, Spring AOP не пытается предоставить полную функцию AOP (даже если это полностью достижимо), Spring AOP платит больше. внимание на родство со Spring Сочетание IOC-контейнера и этого преимущества используется для решения задачи сквозного бизнеса.Поэтому AspectJ имеет большее преимущество с точки зрения улучшения АОП-функций.В то же время у Spring есть заметил, что AspectJ опирается на специальные методы реализации АОП-компилятора (ajc-компилятора), поэтому Spring умничает, чтобы избежать этого,Обратимся к принципу реализации технологии динамических прокси для построения внутреннего механизма Spring AOP (динамическое переплетение), что является наиболее принципиальным отличием от AspectJ (статическое переплетение). После AspectJ 1.5 была введена разработка стиля аннотации в форме @Aspect, и Spring очень быстро последовал этому пути, поэтому те же аннотации, что и AspectJ, использовались после Spring 2.0. Пожалуйста, обрати внимание,Spring просто использует те же аннотации, что и AspectJ 5, но по-прежнему не использует компилятор AspectJ.Нижний уровень — это реализация технологии динамических прокси, поэтому он не зависит от компилятора AspectJ.. Поэтому каждый должен понимать, что, хотя Spring AOP использует этот набор аннотаций, на самом деле нижний уровень AOP заключается в использовании динамического прокси (JDK или CGLib) для динамической имплантации. Что касается статической имплантации AspectJ, то она не является предметом этой статьи, поэтому я упомяну только ее.
2. Spring AOP — аннотации AspectJ
Когда дело доходит до Spring AOP, старые программисты должны быть более осведомлены о том, что предыдущий Spring AOP не использовал аннотацию @Aspect иaop:configДля этого набора XML-решений разработчики определяют некоторые классы для реализации некоторых интерфейсов, и конфигурация отвратительна. В этой статье мы больше не будем это демонстрировать, позже Spring решился, «интегрировал» AspectJ в Spring и открыл пространство имен aop. Нынешний Sping AOP можно рассматривать как светлое будущее. Перед приведенным выше примером давайте упомянем концепцию АОП:
- Pointcut: выражение, которое находит определенный метод
- Аспекты: точки разреза + совет
- Предложение (улучшение): что делать после обнаружения метода
В Интернете есть много концепций, что соединять точки, вплетать, нацеливать объекты, что импортировать. Я лично считаю, что в области Spring AOP на Java это совершенно неуместно. Не путайте себя. Просто следуйте трем концепциям, которые я сказал, и все готово. Что ж, давайте начнем с примера: maven-зависимости:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
//下面这两个aspectj的依赖是为了引入AspectJ的注解
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
//Spring AOP底层会使用CGLib来做动态代理
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
Щенок, может говорить:
public class Dog {
private String name;
public void say(){
System.out.println(name + "在汪汪叫!...");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Класс лапши:
@Aspect //声明自己是一个切面类
public class MyAspect {
/**
* 前置通知
*/
//@Before是增强中的方位
// @Before括号中的就是切入点了
//before()就是传说的增强(建言):说白了,就是要干啥事.
@Before("execution(* com.zdy..*(..))")
public void before(){
System.out.println("前置通知....");
}
}
Этот класс является ключевым моментом.Сначала используйте @Aspect, чтобы объявить, что это фасетный класс, а затем будет расширен метод before().@Before(азимут) + точка входаВы можете конкретно определить местоположение метода определенного класса. Файл конфигурации Spring:
//开启AspectJ功能.
<aop:aspectj-autoproxy />
<bean id="dog" class="com.zdy.Dog" />
<!-- 定义aspect类 -->
<bean name="myAspect" class="com.zdy.MyAspect"/>
Затем основной метод:
ApplicationContext ac =new ClassPathXmlApplicationContext("applicationContext.xml");
Dog dog =(Dog) ac.getBean("dog");
System.out.println(dog.getClass());
dog.say();
Выходной результат:
class com.zdy.Dog$$EnhancerBySpringCGLIB$$80a9ee5f
前置通知....
null在汪汪叫!...
Грубо говоря, это закинуть класс аспекта в контейнер и открыть функцию AdpectJ.Spring AOP найдет метод определенного класса в соответствии с точкой входа (@Before+) в классе аспекта (я определяю все методы всех классов в пакете com.zdy), а затем включит расширенный метод before(). .
Затем давайте поговорим о нескольких аннотациях AspectJ, подобных @Before, поддерживаемых Spring AOP:
- Предварительное уведомление @Before: предварительный совет снабжен аннотацией @Before, и значение выражения pointcut может быть передано напрямую. Совет выполняется до выполнения целевой функции. Обратите внимание, что JoinPoint — это статическая переменная, предоставляемая Spring. joinPoint, о целевом объекте может быть получена информация, такая как имя класса, параметры метода, имя метода и т. д. Этот параметр является необязательным.
@Before("execution(...)")
public void before(JoinPoint joinPoint){
System.out.println("...");
}
- После уведомления @AfterReturning: Аннотированная аннотацией @AfterReturning, функция выполняется после выполнения целевой функции, и можно получить окончательное возвращаемое значение returnVal целевой функции.Когда целевая функция не имеет возвращаемого значения, returnVal вернет значение null, которое необходимо аннотировать with return = «returnVal» Укажите имя параметра и должно совпадать с именем параметра функции уведомления. Обратите внимание, что эти параметры являются необязательными в любом уведомлении. Вы можете заполнить их напрямую, когда они вам нужны. Когда они вам не нужны, вы можете заполнить их, не объявляя.
@AfterReturning(value="execution(...)",returning = "returnVal")
public void AfterReturning(JoinPoint joinPoint,Object returnVal){
System.out.println("我是后置通知...returnVal+"+returnVal);
}
- Уведомление об исключении @AfterThrowing: Уведомление будет запущено только при возникновении исключения, а переменная, которая получает информацию об исключении, объявляется с помощью броска. То же уведомление об исключении также используется для параметра Joinpoint, который можно добавить при необходимости.
@AfterThrowing(value="execution(....)",throwing = "e")
public void afterThrowable(Throwable e){
System.out.println("出现异常:msg="+e.getMessage());
}
- Последнее уведомление @After: это уведомление чем-то похоже на блок finally и будет выполняться независимо от обстоятельств, пока оно применяется.
@After("execution(...)")
public void after(JoinPoint joinPoint) {
System.out.println("最终通知....");
}
- Уведомление вокруг @Around: Совет по окружению может выполняться как до, так и после целевого метода.Что еще более важно, совет по окружению может контролировать, направлен ли целевой метод на выполнение, но даже в этом случае мы должны попытаться выполнить требования самым простым способом.При выполнении до целевой метод, вы должны использовать предварительный совет вместо объемного совета. Код case выглядит следующим образом. Первый параметр должен быть ProceedingJoinPoint. Целевая функция выполняется через метод continue() объекта. Возвращаемое значение continue() — это возвращаемое значение окружающего уведомления. Точно так же объект ProceedingJoinPoint также может получать информацию о целевом объекте, такую как имя класса, параметры метода, имя метода и т. д.
@Around("execution(...)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("我是环绕通知前....");
//执行目标函数
Object obj= (Object) joinPoint.proceed();
System.out.println("我是环绕通知后....");
return obj;
}
Тогда давайте поговорим о выражении pointcut, которое было проигнорировано с помощью "...". Это выражение может быть не исполнением(..), а есть и другие. Я не буду говорить о нем, но наиболее часто используемое выполнение:
//scope :方法作用域,如public,private,protect
//returnt-type:方法返回值类型
//fully-qualified-class-name:方法所在类的完全限定名称
//parameters 方法参数
execution(<scope> <return-type> <fully-qualified-class-name>.*(parameters))
<fully-qualified-class-name>.*(parameters)
Обратите внимание на этот кусок, если он не точен для имени класса, но для имени пакета, он остановится, используйте два ".." для представления любого класса в пакете:
- выполнение(* com.zdy..*(..)): все методы всех классов в пакете com.zdy.
- выполнение(* com.zdy.Dog.*(..)): все методы класса Dog.
Конкретная и подробная грамматика, если вам нужно погуглить ее самостоятельно, эти две наиболее часто используемые. Либо по пакету, либо по конкретному классу.
При использовании pointcut вы также можете извлечь @Pointcut для использования:
/**
* 使用Pointcut定义切点
*/
@Pointcut("execution(...)")
private void myPointcut(){}
/**
* 应用切入点函数
*/
@After(value="myPointcut()")
public void afterDemo(){
System.out.println("最终通知....");
}
Можно избежать повторных исполнений, написанных много раз в разных аннотациях...
Эпилог
Ну вот как Spring AOP реализует АОП на основе аннотаций AspectJ с вами поделились.На самом деле это не сложно,потому что блогер ленивый,и основное содержание сказано.Как и выражение точки входа,на самом деле очень много вещи, чтобы сказать, иПроблема сортировки расширенного уровняНапример, если в классе Aspect определено несколько @Before, кто вызывает его первым, потому что блогер считает, что эти точки знаний не очень важны и используются очень мало, поэтому они не упоминаются. Этот выпуск закончил обмен на основе аннотаций.В следующий раз я расскажу о конфигурации Spring AOP на основе XML, а затем расскажу о некоторых практических сценариях применения. Включение нескольких срезов при попадании в точку касания,Порядок вызова на уровне аспектаУпомяну позже. Затем я расскажу о динамическом прокси-сервере JDK и динамическом прокси-сервере CGLib, используемых в нижней части Spring AOP. Хорошо, это все для этого эпизода ...Over,Have a good day .