一.Aop底层原理
1.AOP 底层使用动态代理
(1)有两种情况动态代理
第一种 有接口情况,使用 JDK 动态代理
- 创建接口实现类代理对象,增强类的方法
第二种 没有接口情况,使用 CGLIB 动态代理
- 创建子类的代理对象,增强类的方法
二.Aop术语
-
连接点 类里面哪些方法可以被增强,这些方法称为连接点
-
切入点 实际被真正增强的方法,称为切入点
3.通知(增强) (1)实际增强的逻辑部分称为通知(增强)
(2)通知有多种类型
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知
4.切面
切面是指把通知应用到切入点过程
三.实现Aop操作
1. 切入点表达式
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构: execution(权限修饰符+返回类型+类全路径+方法名称(参数列表) )
例1:对 com.spring5.dao.BookDao 类里面的 add 进行增强
execution(* com.spring5.dao.BookDao.add(..))
例2:对 com.spring5.dao.BookDao 类里面的所有的方法进行增强
execution(* com.spring5.dao.BookDao.* (..))
例3:对 com.spring5.dao 包里面所有类,类里面所有方法进行增强
execution(* com.spring5.dao.*.* (..))
2.基于AspectJ注解实现Aop操作
(1)创建类,并在类里面定义方法
public class User {
public void add() {
System.out.println("add.......");
}
}
(2)创建增强类,编写增强逻辑
//增强的类
public class UserProxy {
public void before() {//前置通知
System.out.println("before......");
}
}
(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: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">
<!--开启注解扫描-->
<context:component-scan base-package="com.spring5.aopanno"></context:component-scan>
(4)使用注解创建User和UserProxy
(5)在增强类上添加注解 @Aspect
@Component
@Aspect
public class UserProxy {
//类中代码已省略
}
(6)在 spring 配置文件中开启生成代理对象
<!-- 开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
(7)配置不同类型的通知.在增强类的里面的通知方法上面添加通知类型注解,使用切入点表达式配置
@Component
@Aspect
public class UserProxy {
// 前置通知
@Before(value = "execution(* com.spring5.aopanno.User.add(..))")
public void before(){
System.out.println("before.....");
}
@AfterReturning(value = "execution(* com.spring5.aopanno.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning...");
}
@After(value = "execution(* com.spring5.aopanno.User.add(..))")
public void after(){
System.out.println("after...");
}
@AfterThrowing (value= "execution(* com.spring5.aopanno.User.add(..))")
public void afterThrowing(){
System.out.println("after...");
}
@Around (value= "execution(* com.spring5.aopanno.User.add(..))")
public void around (ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前......");
// 被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println("环绕之后......");
}
}
其中@After为最终通知,是在被增强的方法执行结束后执行的。而@AfterReturning为后置通知,在被增强的方法正常结束后执行的。@AfterThrowing魏异常通知,在被增强方法有异常时才执行
补充:可以使用@Pointcut对相同的切入点抽取
//相同切入点抽取
@Pointcut(value = "execution(* com.spring5.aopanno.User.add(..))")public void pointdemo() {
}
//前置通知
//@Before 注解表示作为前置通知
@Before(value = "pointdemo()")
public void before() {
System.out.println("before.........");
}
有多个增强类多同一个方法进行增强,还可以在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高
@Component
@Aspect
@Order(1)
public class PersonProxy{}
3.基于AspectJ 配置文件AOP 操作
(1)创建两个类,增强类和被增强类,创建方法(同上) (2)在 spring 配置文件中创建两个类对象
<!--创建对象-->
<bean id="book" class="com.spring5.aopxml.Book"></bean>
<bean id="bookProxy" class="com.spring5.aopxml.BookProxy"></bean>
(3)在 spring 配置文件中配置切入点
<!--配置 aop 增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(*com.spring5.aopxml.Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy">
<!--增强作用在具体的方法上-->
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>
总之,Aop是在程序运行期间,在不修改源码的基础上对方法进行功能增强。使用Aop可以减少重复代码,提高开发效率,并且便于维护。