Spring框架学习06——AOP底层实现原理
在Java中有多种动态代理技术,如JDK、CGLIB、Javassist、ASM,其中最常用的动态代理技术是JDK和CGLIB。
1、JDK的动态代理
JDK动态代理是java.lang.reflect.*包提供的方法,必须要借助一个接口才能产生代理对象,对于使用业务接口的类,Spring默认使用JDK动态代理实现AOP。
代码示例如下:
创建dao包,并创建StuDao接口和StuDaoImpl实现类,
StuDao
public interface StuDao {
public void add(Student student);
public void find();
public void update(Student student);
public void delete(Student student);
}
实现类:
package com.kude.dao;
import com.kude.entity.Student;
public class StudentDaoimpl implements StuDao {
@Override
public void add(Student student) {
System.out.println("添加学生");
}
@Override
public void find() {
System.out.println("查询学生");
}
@Override
public void update(Student student) {
System.out.println("修改学生");
}
@Override
public void delete(Student student) {
System.out.println("删除学生");
}
}
创建aspect包,并创建切面类MyAspect,该类中可以定义多个通知,即增强处理的方法,示例代码如下:
package com.kude.aspect;
public class MyAspect {
public void check(){
System.out.println("模拟权限控制");
}
public void except(){
System.out.println("模拟异常处理");
}
public void log(){
System.out.println("模拟日志记录");
}
public void monitor(){
System.out.println("模拟性能检测");
}
}
创建proxy包,并创建代理类MyJdkProxy,在JDK动态代理中代理类必须实现java.lang.reflect.InvocationHandler接口,并编写代理方法,在代理方法中需要通过Proxy实现动态代理。示例代码如下:
package com.kude.proxy;
import com.kude.aspect.MyAspect;
import com.kude.dao.StuDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyJdkProxy implements InvocationHandler {
//声明类接口对象
private StuDao stuDao;
public MyJdkProxy(StuDao stuDao) {
this.stuDao = stuDao;
}
//创建代理的方法,建立代理对象和真实对象的代理关系,返回代理对象
public Object createProxy(){
//1.类加载器
ClassLoader cld = MyJdkProxy.class.getClassLoader();
//2.被代理对象实现的所有接口
Class[] clazz = stuDao.getClass().getInterfaces();
return Proxy.newProxyInstance(cld,clazz,this);
}
/**
* 代理的逻辑方法,所有动态代理类的方法调用都交给该方法处理
* @param proxy 被代理对象
* @param method 要执行的方法
* @param args 执行方法时需要的参数
* @return 返回代理结果
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//创建一个切面
MyAspect myAspect = new MyAspect();
//前增强
myAspect.check();
myAspect.except();
//在目标类上调用方法并传入参数,相当于调用stuDao中的方法
Object obj = method.invoke(stuDao,args);
//后增强
myAspect.log();
myAspect.monitor();
return obj;
}
}
创建测试类:
@Test
public void testStu(){
Student student=new Student();
//创建目标对象
StuDao stuDao = new StudentDaoimpl();
//创建代理对象
MyJdkProxy myJdkProxy = new MyJdkProxy(stuDao);
//从代理对象中获取增强后的目标对象
//该对象是一个被代理的对象,它会进入代理的逻辑方法invoke中
StuDao stuDaoProxy = (StuDao) myJdkProxy.createProxy();
//执行方法
stuDaoProxy.add(student);
System.out.println("==================");
stuDaoProxy.update(student);
System.out.println("==================");
stuDaoProxy.delete(student);
}
输出结果:
模拟权限控制
模拟异常处理
添加学生
模拟日志记录
模拟性能检测
==================
模拟权限控制
模拟异常处理
修改学生
模拟日志记录
模拟性能检测
==================
模拟权限控制
模拟异常处理
删除学生
模拟日志记录
模拟性能检测
Process finished with exit code 0