基本概念可看我之前的文章 AOP——基本概念、底层原理,这次直接来实现AOP的操作,在介绍操作之前,我们得先介绍AOP的各种术语
aop操作术语
1、连接点(JoinPoint):
类里面哪些方法可以被增强,这些方法称为连接点
比如说:一个类中有add updat delect select方法,这些方法都可以被增强,所以被称为连接点
2、切入点(Pointcut ):
实际被真正增强的方法,称为切入点
3、通知/增强(Advice):
(1)实际增强的逻辑部分称为通知/增强
(2)通知有多种类型:
-
前置通知:在目标方法执行之前执行执行的通知。无论何时都第一个执行
-
后置通知:在目标方法执行之后执行的通知。正常执行时第三个执行
-
环绕通知:在环绕通知中必须显式的调用目标方法,目标方法才会执行,简单理解,环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的.
-
异常通知:在目标方法抛出异常时执行的通知。出现异常时第三个执行
-
最终通知:是在目标方法执行之后执行的通知。无论何时都第二个执行,和后置通知不同之处在于,后置通知是在方法正常返回后执行的通知,如果方法没有正常返回例如抛出异常,则后置通知不会执行。而最终通知无论如何都会在目标方法调用过后执行,即使目标方法没有正常的执行完成。另外,后置通知可以通过配置得到返回值,而最终通知无法得到。
4、切面(Aspect):
是动作,把通知应用到切入点过程
5、引入:(Introduction) 表示向现有的类中添加新方法、新属性。
6、目标对象(Target) 表示被增强的对象。
7、代理(Proxy) 表示实现AOP的机制。
8、织入(Weaving) 表示把增强应用到目标对象的过程。
在了解了AOP各种操作术语后,我们就需要对实现AOP操作做准备工作了
aop准备工作
1、Spring的框架中,一般都是基于AspectJ来实现AOP操作
(1)什么是AspectJ
AspectJ并不是Spring组成部分,它是独立AOP框架,一般把AspectJ和Spring框架一起使用, 进行AOP操作
(2)基于AspectJ实现AOP操作
-
基于xml配置文件实现
-
基于注解方式实现(使用)
3、在项目工程里面引入AOP相关依赖。
我们需要准备以下的AspectJ jar包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E9LqxOpX-1670225871236)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/59aba9267e344d33b8a22db3fb9788a9~tplv-k3u1fbpfcp-watermark.image?)]
把这些jar导入到相关的spring项目下
4、切入点表达式、
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构:
execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
标准表达式写法:execution(public void com.dao.UserDao.add())
表达式中,可以用通配符来表示如:
举例1:
对com.dao.UserDao类里面的add进行增强。
execution(* com.dao.UserDao.add(..))
举例2:对com.atguigu.dao.BookDao类里面的所有的方法进行增强
execution(* com.dao.UserDao.* (..))
举例3:对com.atguigu.dao包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.*.* (.))
AspectJ注解
1.创建类,在类中定义方法
import org.springframework.stereotype.Component;
//User类,作为目标对象
@Component
public class AspectJUser {
public void add(){
System.out.println("add");
}
}
2.创建增加类,编写增强逻辑
我们在增强类中创建不同的方法,让不同的方法代表不同的增强逻辑
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AspectJUserProxy {
// 前置通知
@Before("execution(* com.springAOP.AspectJUser.add(..))")
public void before(){
System.out.println("before... ");
}
//最终通知
@After("execution(* com.springAOP.AspectJUser.add(..))")
public void after(){
System.out.println("after...");
}
//后置通知
@AfterReturning("execution(* com.springAOP.AspectJUser.add(..))")
public void AfterReturning(){
System.out.println("AfterReturning...");
}
//异常通知
@AfterThrowing("execution(* com.springAOP.AspectJUser.add(..))")
public void AfterThrowing(){
System.out.println("AfterThrowing...");
}
//环绕通知——在方法之前之后都执行
@Around("execution(* com.springAOP.AspectJUser.add(..))")
public void Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
//简单理解,环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的.
System.out.println("Around前");
proceedingJoinPoint.proceed();
System.out.println("Around后");
}
}
3、进行通知的配置
(1)在spring配置文件中,开启注解扫描。
(2)在spring配置文件中开启生成代理对象。
<!-- 开启注解扫描-->
<context:component-scan base-package="com.springAOP"></context:component-scan>
<!-- 开启aspectj生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
所有类写好,我们写一个test来验证一下
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AspectJTest {
@Test
public void testAop(){
ApplicationContext context =
new ClassPathXmlApplicationContext("com/bean1.xml");
AspectJUser user = context.getBean("aspectJUser", AspectJUser.class);
user.add();
}
}
控制台: