一、介绍
AOP 面向切面编程,可以在不修改现有代码的情况下,对程序的功能进行拓展,,主要可以用来权限控制,性能检测,事务控制。
AOP实现的原理就是动态代理,在有接口的情况下,使用JDK动态代理,在没有接口的情况下使用cglib动态代理
二、AOP术语
2.1 连接点 (Join Point)
主要是指可以被增强的方法
2.2 切入点 (PointCut)
实际上被增强的方法
2.3 通知(advice)
实际增强的功能
2.4 目标对象(Target)
被增强功能的对象(被代理的对象)
2.5 切面(Aspect)
表现为功能相关的一些advice方法放在一起声明成的一个Java类
2.6 织入(Weaving)
创建代理对象并实现功能增强的声明并运行过程
三、aop注解方式实现
3.1 引入相关依赖
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.25</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> <!--spring 切面包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.3.25</version> </dependency> <!--aop联盟--> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> </dependencies>
3.2 建立UserDao接口和实现类
public interface UserDao {
public int addUser(Integer id,String name);
}
@Repository
public class UserDaoImpl implements UserDao {
public int addUser(Integer id, String name) {
System.out.println(id+","+name);
return id;
}
}
3.3 编写配置文件
<?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
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--spring包扫描-->
<context:component-scan base-package="com.msb.aop"/>
<!--开启自动代理-->
<aop:aspectj-autoproxy/>
</beans>
3.4 建立DaoAspect类
@Aspect
@Component
public class DaoAspect {
}
3.5 前置通知(在DaoAspect这个类中写对应的方法)
/*
* 前置通知: 切点方法执行之前先执行的功能
* 参数列表可以用JoinPoint接收切点对象
* 可以获取方法执行的参数
*/
@Before("execution(* com.msb.aop.dao.UserDao.add*(..))")
public void testBefore(JoinPoint joinPoint){
System.out.println("before执行");
System.out.println(joinPoint.getArgs());
Object target = joinPoint.getTarget();
System.out.println(target.toString());
}
3.6 后置通知
/*
* 后置通知:方法执行之后要增强的功能
* 无论切点方法是否出现异常都会执行的方法
* 参数列表可以用JoinPoint接收切点对象
* */
@After("execution(* com.msb.aop.dao.UserDao.add*(..))")
public void testAfter(JoinPoint joinPoint){
System.out.println("后置通知");
}
3.7 返回通知
/*
* 返回通知:切点方法正常运行结束后增强的功能
* 如果方法运行过程中出现异常,则该功能不运行
* 参数列表可以用 JoinPoint joinPoint接收切点对象
* 可以用Object res接收方法返回值,需要用returning指定返回值名称
* */
@AfterReturning(value = "execution(* com.msb.aop.dao.UserDao.addUser(..))",returning = "res")
public void testAfterReturning(JoinPoint joinPoint,Object res){
System.out.println("返回通知");
System.out.println(res);
}
3.8 异常通知
/*
* 异常通知:切点方法出现异常时运行的增强功能
* 如果方法运行没有出现异常,则该功能不运行
* 参数列表可以用Exception ex接收异常对象 需要通过throwing指定异常名称
*/
@AfterThrowing(value = "execution(* com.msb.aop.dao.UserDao.addUser(..))",throwing = "ex")
public void testAfterThrowing(JoinPoint joinPoint,Exception ex){
System.out.println("异常通知执行");
System.out.println(ex);
}
3.9 环绕通知
/*环绕通知:在切点方法之前和之后都进行功能的增强
* 需要在通知中定义方法执行的位置,并在执行位置之前和之后自定义增强的功能
* 方法列表可以通过ProceedingJoinPoint获取执行的切点
* 我们在环绕通知的最后需要将切点方法的返回值继续向上返回,否则切点方法在执行时接收不到返回值
* */
@Around(value = "execution(* com.msb.aop.dao.UserDao.addUser(..))")
public Object testAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("前");
Object proceed = proceedingJoinPoint.proceed();
System.out.println("后");
return proceed;
}
3.10 测试方法
@Test
public void testBefore(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-spring.xml");
UserDao userDao = applicationContext.getBean(UserDao.class);
userDao.addUser(1,"yanlingfei");
}
四、JoinPoint 和 ProceedingJoinPoint
4.1 ProceedingJoinPoint
public interface ProceedingJoinPoint extends JoinPoint {
void set$AroundClosure(AroundClosure arc);
default void stack$AroundClosure(AroundClosure arc) {
throw new UnsupportedOperationException();
}
Object proceed() throws Throwable;
Object proceed(Object[] args) throws Throwable;
}
4.2 JoinPoint
public interface JoinPoint {
String toString();
String toShortString();
String toLongString();
Object getThis();
// 返回目标对象,即被代理的对象
Object getTarget();
// 返回切入点的参数
Object[] getArgs();
// 返回切入点的Signature
Signature getSignature();
SourceLocation getSourceLocation();
String getKind();
interface StaticPart {
Signature getSignature();
SourceLocation getSourceLocation();
String getKind();
int getId();
String toString();
String toShortString();
String toLongString();
}
interface EnclosingStaticPart extends StaticPart {}
StaticPart getStaticPart();
String METHOD_EXECUTION = "method-execution";
String METHOD_CALL = "method-call";
String CONSTRUCTOR_EXECUTION = "constructor-execution";
String CONSTRUCTOR_CALL = "constructor-call";
String FIELD_GET = "field-get";
String FIELD_SET = "field-set";
String STATICINITIALIZATION = "staticinitialization";
String PREINITIALIZATION = "preinitialization";
String INITIALIZATION = "initialization";
String EXCEPTION_HANDLER = "exception-handler";
String SYNCHRONIZATION_LOCK = "lock";
String SYNCHRONIZATION_UNLOCK = "unlock";
String ADVICE_EXECUTION = "adviceexecution";
}