手写简单的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() 这个方法

字节码重组过程:

1、就是拿到被代理对象的引用,并且获取到它的所有接口(通过反射获取)。
2、JDK Proxy类重新生成一个新的类,同时新的类要实现被代理类所有的接口。
3、动态生成Java代码,把新加的业务逻辑方法由一定逻辑代码去调用。
4、编译新生成的Java代码.class
5、再重新加载到JVM中

二、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动态代理
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值