AOP 操作
- AOP 操作(准备)
- 1. Spring 框架一般是基于 AspectJ 实现 AOP 操作
- (1)什么是 AspectJ
- 2. 基于 AspectJ 实现 AOP 操作
- 3. 在项目工程里面引入 AOP 先关的依赖
- 4. 切入点表达式
- 举例1:对 com.fairykunkun.dao.UserDao 类里面的 add 进行增强
- 举例2:对 com.fairykunkun.dao.UserDao 类里面的所有方法进行增强
- 举例3:对 com.fairykunkun.dao 包里面的所有类的所有方法进行增强
- AOP 操作( Aspect 注解)
- 1. 创建一个类,在类里面定义方法
- 2. 创建增强类(编写增强逻辑)
- (1)在增强类里面,创建方法,让不同的方法代表不同的通知类型
- 3. 进行通知的一个配置
- (1)在 Spring 的配置文件中开启注解的扫描
- (2)使用注解创建 User 和 UserProxy 对象
- (3)在增强类上面添加注解 @Aspect
- (4)在 Spring 配置文件中开启生成代理对象
- 4. 配置不同类型的通知
- (1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
- 5. 测试
- 6. 总结
- 7. 公共(相同)切入点抽取
- 8. 多个增强类对我们的同一个方法进行增强,设置增强类的优先级
- 9. 完全使用注解开发
- AOP 操作( AspectJ 配置文件)
- 1. 创建两个类,增强类和被增强类,创建方法
- 2. 在 Spring 配置文件中创建两个类对象
- 3. 在 Spring 配置文件中配置切入点
AOP 操作(准备)
1. Spring 框架一般是基于 AspectJ 实现 AOP 操作
(1)什么是 AspectJ
AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spring 框架一起使用,进行 AOP 操作
2. 基于 AspectJ 实现 AOP 操作
(1)基于 xml 配置文件实现
(2)基于注解的方式实现
3. 在项目工程里面引入 AOP 先关的依赖
<!--aop相关依赖-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.20</version>
</dependency>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.9.9.1</version>
</dependency>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.9.1</version>
</dependency>
<dependency><groupId>org.assertj</groupId><artifactId>assertj-core</artifactId><version>3.23.1</version>
</dependency>
4. 切入点表达式
(1)切入点表达式的作用:知道对哪个类里面的那个方法进行增强
(2)语法结构
execution([权限修饰符][返回类型][全类名][方法名称]([参数列表]))
举例1:对 com.fairykunkun.dao.UserDao 类里面的 add 进行增强
execution(*com.fairykunkun.dao.UserDao.add(..))
举例2:对 com.fairykunkun.dao.UserDao 类里面的所有方法进行增强
execution(*com.fairykunkun.dao.UserDao.*(..))
举例3:对 com.fairykunkun.dao 包里面的所有类的所有方法进行增强
execution(*com.fairykunkun.dao.*.*(..))
AOP 操作( Aspect 注解)
1. 创建一个类,在类里面定义方法
package com.fairykunkun.aopanno;
// 被增强的类
public class User {public void add ( ) {System.out.println ( "add ..." );}
}
2. 创建增强类(编写增强逻辑)
(1)在增强类里面,创建方法,让不同的方法代表不同的通知类型
package com.fairykunkun.aopanno;
// 增强的类
public class UserProxy {public void before ( ) {// 前置通知System.out.println ( "before ..." );}
}
3. 进行通知的一个配置
(1)在 Spring 的配置文件中开启注解的扫描
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 开启注解的扫描 --><context:component-scan base-package = "com.fairykunkun.aopanno"></context:component-scan>
</beans>
(2)使用注解创建 User 和 UserProxy 对象
package com.fairykunkun.aopanno;
import org.springframework.stereotype.Component;
// 被增强的类
@Component
public class User {public void add ( ) {System.out.println ( "add ..." );}
}
package com.fairykunkun.aopanno;
import org.springframework.stereotype.Component;
// 增强的类
@Component
public class UserProxy {// 前置通知public void before ( ) {System.out.println ( "before ..." );}
}
(3)在增强类上面添加注解 @Aspect
package com.fairykunkun.aopanno;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
// 增强的类
@Component
@Aspect // 生成代理对象
public class UserProxy {// 前置通知public void before ( ) {System.out.println ( "before ..." );}
}
(4)在 Spring 配置文件中开启生成代理对象
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 开启注解的扫描 --><context:component-scan base-package = "com.fairykunkun.aopanno"></context:component-scan><!-- 开启 Aspect生成代理对象 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
4. 配置不同类型的通知
(1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
package com.fairykunkun.aopanno;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
// 增强的类
@Component
@Aspect // 生成代理对象
public class UserProxy {// 前置通知// @Before 注解表示作为前置通知// * 表示可以返回任意值@Before ( value = "execution(* com.fairykunkun.aopanno.User.add(..))" )public void before ( ) {System.out.println ( "before ..." );}
}
5. 测试
package com.fairykunkun;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.fairykunkun.aopanno.User;
public class TestAop {@Testpublic void testAopAno ( ) {ApplicationContext context =new ClassPathXmlApplicationContext ( "bean11.xml" );User user = context.getBean ( "user" , User.class );user.add ( );}
}
- 继续完善增强类的方法
package com.fairykunkun.aopanno;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
// 增强的类
@Component
@Aspect // 生成代理对象
public class UserProxy {// 前置通知// @Before 注解表示作为前置通知// * 表示可以返回任意值@Before ( value = "execution(* com.fairykunkun.aopanno.User.add(..))" )public void before ( ) {System.out.println ( "before ..." );}@AfterThrowing ( value = "execution(* com.fairykunkun.aopanno.User.add(..))" )public void afterThrowing ( ) {System.out.println ( "afterThrowing......" );}@After ( value = "execution(* com.fairykunkun.aopanno.User.add(..))" )public void after ( ) {System.out.println ( "after......" );} // 环绕通知@Around ( value = "execution(* com.fairykunkun.aopanno.User.add(..))" )public void around ( ProceedingJoinPoint proceedingJoinPoint ) throws Throwable {System.out.println ( "环绕之前......" );// 被增强的方法执行proceedingJoinPoint.proceed ( );System.out.println ( "环绕之后......" );}
}
- 再看一下测试结果
package com.fairykunkun.aopanno;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
// 增强的类
@Component
@Aspect // 生成代理对象
public class UserProxy {// 前置通知// @Before 注解表示作为前置通知// * 表示可以返回任意值@Before ( value = "execution(* com.fairykunkun.aopanno.User.add(..))" )public void before ( ) {System.out.println ( "before ..." );}@AfterThrowing ( value = "execution(* com.fairykunkun.aopanno.User.add(..))" )public void afterThrowing ( ) {System.out.println ( "afterThrowing......" );}@AfterReturning ( value = "execution(* com.fairykunkun.aopanno.User.add(..))" )public void afterReturning ( ) {System.out.println ( "afterReturning......" );}@After ( value = "execution(* com.fairykunkun.aopanno.User.add(..))" )public void after ( ) {System.out.println ( "after......" );}// 环绕通知@Around ( value = "execution(* com.fairykunkun.aopanno.User.add(..))" )public void around ( ProceedingJoinPoint proceedingJoinPoint ) throws Throwable {System.out.println ( "环绕之前......" );// 被增强的方法执行proceedingJoinPoint.proceed ( );System.out.println ( "环绕之后......" );}
}
- 看一下实验结果
- 在 User 的 add 方法中模拟一个异常
package com.fairykunkun.aopanno;
import org.springframework.stereotype.Component;
// 被增强的类
@Component
public class User {public void add ( ) {int i=10/0;System.out.println ( "add ..." );}
}
- 测试
6. 总结
- @Before(前置通知)
- @AfterReturning(后置通知,返回通知)
- @After(最终通知)
- @Around(环绕通知)
- @AfterThrowing(异常通知)
7. 公共(相同)切入点抽取
package com.fairykunkun.aopanno;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
// 增强的类
@Component
@Aspect // 生成代理对象
public class UserProxy {// 相同切入点抽取@Pointcut ( value = "execution(* com.fairykunkun.aopanno.User.add(..))" )public void pointdemo ( ) {}// 前置通知// @Before 注解表示作为前置通知// * 表示可以返回任意值@Before ( value = "pointdemo()" )public void before ( ) {System.out.println ( "before ..." );}@AfterThrowing ( value = "pointdemo()" )public void afterThrowing ( ) {System.out.println ( "afterThrowing......" );}@AfterReturning ( value = "pointdemo()" )public void afterReturning ( ) {System.out.println ( "afterReturning......" );}@After ( value = "pointdemo()" )public void after ( ) {System.out.println ( "after......" );}// 环绕通知@Around ( value = "pointdemo()" )public void around ( ProceedingJoinPoint proceedingJoinPoint ) throws Throwable {System.out.println ( "环绕之前......" );// 被增强的方法执行proceedingJoinPoint.proceed ( );System.out.println ( "环绕之后......" );}
}
- 把之前做的那个异常去掉,然后再做测试
8. 多个增强类对我们的同一个方法进行增强,设置增强类的优先级
package com.fairykunkun.aopanno;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class PersonProxy {// 前置通知@Before (value = "execution(* com.fairykunkun.aopanno.User.add(..))")public void before() {System.out.println ("Person Before......" );}
}
(1)在增强类上面添加注解@Order(数字类型值),数字类型值越小优先级越高
package com.fairykunkun.aopanno;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Aspect
@Order(1)
public class PersonProxy {// 前置通知@Before (value = "execution(* com.fairykunkun.aopanno.User.add(..))")public void before() {System.out.println ("Person Before......" );}
}
- 测试
9. 完全使用注解开发
(1)创建配置类,不需要创建 xml 配置文件
package com.fairykunkun.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan ( basePackages = { "com.fairykunkun" } )
@EnableAspectJAutoProxy ( proxyTargetClass = true )
public class AopConfig {
}
AOP 操作( AspectJ 配置文件)
1. 创建两个类,增强类和被增强类,创建方法
package com.fairykunkun.aopxml;
public class Book {public void buy ( ) {System.out.println ( "buy" );}
}
package com.fairykunkun.aopxml;
public class BookProxy {public void before ( ) {System.out.println ( "before......" );}
}
2. 在 Spring 配置文件中创建两个类对象
<?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:aop = "http://www.springframework.org/schema/aop"xsi:schemaLocation = "http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 创建对象 --><bean id = "book" class = "com.fairykunkun.aopxml.Book"></bean><bean id = "bookProxy" class = "com.fairykunkun.aopxml.BookProxy"></bean>
</beans>
3. 在 Spring 配置文件中配置切入点
<?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:aop = "http://www.springframework.org/schema/aop"xsi:schemaLocation = "http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 创建对象 --><bean id = "book" class = "com.fairykunkun.aopxml.Book"></bean><bean id = "bookProxy" class = "com.fairykunkun.aopxml.BookProxy"></bean><!-- 配置 aop 增强 --><aop:config><!-- 切入点 --><aop:pointcut id = "p" expression = "execution(* com.fairykunkun.aopxml.Book.buy(..))"/><!-- 配置切面 --><aop:aspect ref = "bookProxy"><!-- 增强作用在具体的方法上 --><aop:before method = "before" pointcut-ref = "p"/></aop:aspect></aop:config>
</beans>
- 测试
package com.fairykunkun;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.fairykunkun.aopxml.Book;
public class TestAop {@Testpublic void testAopXml ( ) {ApplicationContext context =new ClassPathXmlApplicationContext ( "bean12.xml" );Book book = context.getBean ( "book" , Book.class );book.buy ( );}
}