手写简单的SpringAOP动态代理的方式
SpringAOP代理模式
一、JDK动态代理模式
1、JDK动态代理的原理
- 通过实现InvocationHandler接口创建自己的调用处理器
- 通过为Proxy类指定ClassLoader对象和一组Interface来创建
- 通过反射机制获取动态代理的构造函数
- 通过构造函数创建动态代理的实例
2、JDK动态代理demo
UserDao 接口
package demo;
public interface UserDao {
public void save();
public void update();
public void delete();
public void select();
}
UserDaoImpl接口实现
package demo;
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("保存");
}
public void update() {
System.out.println("更新");
}
public void delete() {
System.out.println("删除");
}
public void select() {
System.out.println("查询");
}
}
JDK动态代理
package demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxy implements InvocationHandler{
//将被增加的对象传递到代理中
private UserDao userDao;
public JdkProxy(UserDao userDao) {
this.userDao=userDao;
}
/**
* 产生UserDao代理的方法
* @return
*/
public UserDao createProxy() {
//第一个参数:增加类的类加载器
//第二个参数:类的接口
//第三个参数:InvocationHandler 动态代理类直接实现handler的接口,第三个参数可以调用自身
UserDao userDaoProxy=(UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(), this);
return userDaoProxy;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断方法名是不是save
if("save".equals(method.getName())) {
//增强
System.out.println("增加权限成功");
return method.invoke(userDao, args);
}
return method.invoke(userDao, args);
}
}
这里就简单的增强了 save() 这个方法
二、Cglib动态代理
1、Cglib动态代理原理
CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
2、代理Demo
CustomerDao
package demo2;
public class CustomerDao {
public void save() {
System.out.println("cglib 保存");
}
public void update() {
System.out.println("cglib 更新");
}
public void delete() {
System.out.println("cglib 删除");
}
public void select() {
System.out.println("cglib 查询");
}
}
CglibProxy
package demo2;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor{
private CustomerDao customerDao;
public CglibProxy(CustomerDao customerDao) {
this.customerDao=customerDao;
}
public CustomerDao createProxy() {
//1.创建cglib的核心对象
Enhancer enhancer=new Enhancer();
//2.设置父类
enhancer.setSuperclass(customerDao.getClass());
//3.设置回调:(类似于InvocationHandler对象)
enhancer.setCallback(this);
//4.创建代理对象
CustomerDao create = (CustomerDao) enhancer.create();
return create;
}
public Object intercept(Object proxy, Method medthod, Object[] arg2, MethodProxy methodProxy) throws Throwable {
// 判断方法是否为save
if("save".equals(medthod.getName())) {
System.out.println("cglib 增强");
return methodProxy.invokeSuper(proxy, arg2);
}
return methodProxy.invokeSuper(proxy, arg2); //如果不是save方法,那就直接执行父类的方法,不增强
}
}
三、两者的区别
1、代理的区别
- JDK动态代理是面向接口的
- Cglib动态代理是通过字节码底层继承要代理类来实现的
而spring是模式采用JDK动态代理的实现机制,如果代理的不是实现类,那么会采用Cglib来实现动态代理
2、性能的区别
- Cglib动态代理所创建的代理在运行时的性能会比JDK动态代理高出不少
- 而在创建对象时Cglib所用的时间会比JDK动态代理要多很多
所以,无需频繁的创建对象时使用Cglib动态代理要好很多,如一些单例的代理,反之则使用JDK动态代理