JDK 动态代理
java.lang.reflect.Proxy 创建代理对象,调用下面的方法实现动态代理。newProxyInstance()
- 参数1:ClassLoader
- 参数2:interfaces[]
- 参数3:InvocationHandler 接口实现增强部分功能; ```java package io.zsy.annotation.aop;
import io.zsy.annotation.dao.UserDao; import io.zsy.annotation.dao.UserMapper;
import java.lang.reflect.Proxy;
/**
- @author zhangshuaiyin
@date 2022/4/25 20:28 */ public class JdkProxy { public static void main(String[] args) {
Class<?>[] interfaces = {UserDao.class};
UserDao userMapper = new UserMapper();
UserDao userDao = (UserDao) Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), interfaces, (proxy, method, params) -> {
// 执行代理方法之前
System.out.println("JdkProxy - 动态代理方法执行前执行逻辑");
// 被代理的方法执行, proxy是被代理的对象,method是被代理对象的方法
method.invoke(userMapper, params);
// 执行代理方法之后
System.out.println("JdkProxy - 动态代理方法执行后执行逻辑");
return proxy;
});
userDao.add();
AOP 术语
- 连接点:可以增强的方法
- 切入点:实际被增强的方法
- 通知:实际增强的逻辑部分(增强)
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知
- 切面:把通知应用到切入点的过程
引入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<!-- 实现 AOP -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
Spring AOP
Spring 框架一般是基于 AspectJ 实现 AOP 操作。AspectJ 不是 Spring 组成部分,独立于 AOP 框架。一般把 AspectJ 和 Spring 一起使用完成 AOP 操作。
- 基于 xml 配置方式
-
切入点表达式
切入点表达式指定了对哪个类的哪个方法进行增强。
语法结构:execution([权限修饰符][返回类型][全限定类名][方法名称]([参数列表]))
示例: 对 io.zsy.dao.BookDao 类进行增强:
execution(* io.zsy.dao.BookDao.add(..))
- 对所有方法进行增强:
execution(* io.zsy.dao.BookDao.*(..))
对 io.zsy.dao 包下的所有类的所有方法增强:
execution(* io.zsy.dao.*.*(..))
注解方式实现
创建被代理类和代理对象 ```java package io.zsy.annotation.aop.anno;
import org.springframework.stereotype.Component;
/**
- @author zhangshuaiyin
- @date 2022/4/25 21:01
*/
@Component
public class User {
public void add() {
} }System.out.println("User add..");
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component;
/**
- @author zhangshuaiyin
@date 2022/4/25 21:01 */ @Aspect @Component public class UserProxy {
@Pointcut(value = “execution(* io.zsy.annotation.aop.anno.User.add(..))”) public void pointCut() { }
@Before(“pointCut()”) public void before() {
System.out.println("UserProxy before - 前置通知");
}
@After(“execution(* io.zsy.annotation.aop.anno.User.add(..))”) public void after() {
System.out.println("UserProxy after - 后置通知");
}
@Around(“execution(* io.zsy.annotation.aop.anno.User.add(..))”) public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("UserProxy around - 环绕通知 方法执行前"); Object result = joinPoint.proceed(); System.out.println("UserProxy around - 环绕通知 方法执行后"); return result;
}
@AfterThrowing(“execution(* io.zsy.annotation.aop.anno.User.add(..))”) public void afterThrowing() {
System.out.println("UserProxy afterThrowing - 异常通知");
}
@AfterReturning(“execution(* io.zsy.annotation.aop.anno.User.add(..))”) public void afterReturning() {
System.out.println("UserProxy afterReturning - 最终通知");
} }
2. 配置文件开启组件扫描和AspectJ
```xml
<?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">
<!-- 开启组件扫描,创建有注解的 bean 对象 -->
<context:component-scan base-package="io.zsy.annotation.aop.anno"/>
<!-- 开启 Aspect 生成代理对象 -->
<aop:aspectj-autoproxy/>
</beans>
- 测试 ```java package io.zsy.annotation;
import io.zsy.annotation.aop.anno.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
- @author zhangshuaiyin
@date 2022/4/25 21:08 */ public class AopTests {
@Test public void testAopAnno() {
ApplicationContext context = new ClassPathXmlApplicationContext("aop-anno.xml"); User user = context.getBean("user", User.class); user.add();
} } ``` 其他注解:
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
- @author zhangshuaiyin
@date 2022/4/25 21:28 */ @Configuration @ComponentScan(basePackages = {“io.zsy.annotation.aop.anno”}) @EnableAspectJAutoProxy(proxyTargetClass = true) public class AopConfig { }
测试 ```java @Test public void testAopAllAnno() { ApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class); User user = context.getBean("user", User.class); user.add(); }
配置文件实现
```xml <?xml version=”1.0” encoding=”UTF-8”?>
<aop:before method="before" pointcut-ref="p"/>
```