Java动态代理的两种实现

动态代理与静态代理

静态代理:

程序编写时,以手动编码的方式来对某一个类或者对象的功能进行增强.

代码示例:
public class StaticProxy {

	public static void main(String[] args) {
		Car car = new Car();
		System.out.println("------方法执行前------");
		car.run();
		System.out.println("------方法执行后------");
	}
}

class Car {
	public void run() {
		System.out.println("run......");
	}
}
/**
 * 运行结果
 * ------动态调整------
 * run......
 * ------动态调整------
 */
动态代理:

在程序运行过程中动态来增强某些类的功能,并且不需要我们每一次都进行代码编写,增强了我们程序的灵活性.
Java中动态代理的实现方式有两种: JDK动态代理与CGLIB动态代理

一.JDK动态代理

JDK的动态代理是依赖于接口的,如果类没有实现任何接口是无法使用JDK动态代理的,原理在于动态代理时,会创建出一个实现被代理类实现的接口的被代理类的兄弟类的class文件并进行加载创建实例并进行缓存,对同一个类调用多次代理不会每次都创建代理对象.

调用代理对象的方法时,会被invoke方法拦截,执行增强方法,可以在增强方法中调用代理对象方法的invoke方法执行代理类的对应方法.
经过动态代理创建出来的代理对象,都是被 final修饰 继承自Proxy类 并实现被代理类实现的接口
$Proxy后面的数字代表生成代理类的次数

public final class $Proxy0 extends Proxy implements Car
实现代理的代码:
// 创建接口用于动态代理
public interface Car {
	void run();
}
// 接口的一个实现类
public class Truck implements Car {

	// 品牌
	private String brand;

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	@Override
	public void run() {
		System.out.println("Car run......");
	}
}
public class JDKProxy {

	public static void main(String[] args) {
		// 创建被代理类对象
		Car car = new Truck();

		/**
		 * 参数介绍
		 * newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler)
		 * loader 使用哪一个类加载器来加载代理类,通常我们使用当前类的加载器即可
		 * interfaces 被代理类实现了哪些接口,可以通过 被代理类.class.getInterfaces()来获取
		 * invocationHandler 具体的处理类,具体决定如何执行增强逻辑
		 */
		Car carProxy = (Car) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), Truck.class.getInterfaces(), new InvocationHandler() {
			/**
			 * 参数介绍
			 * proxy 代理类本身 一般情况下不会使用,当我们需要在代理逻辑中返回对象本身的时候就可以拿来使用
			 * method 要增强的方法对象
			 * args 方法的参数
			 */
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				// 执行接口中所有方法都会被此处拦截 可以在此处进行方法功能增强
				System.out.println("------方法执行前------");
				/**
				 * 此处表示执行被代理类(car)的方法
				 * result 是被代理类的返回值 通常我们直接返回 如果需要修改需要注意类型转化异常
				 */
				Object result = method.invoke(car, args);
				System.out.println("------方法执行后------");
				return result;
			}
		});
		carProxy.run();
	}
}
/**
 * 执行结果
 * ------方法执行前------
 * Car run......
 * ------方法执行后------
 */

二.CGLIB动态代理

cglib动态代理不依赖与接口,代理类无论是否实现接口都可以进行代理.cglib不能代理final修饰的方法,因为本质上cglib是创建当前类子类,所以是无法继承到final类型修饰的方法.
cglib使用ASM技术生成代理类的字节码文件,加载到内存创建实例
使用cglib动态代理,需要项目引入cglib的jar包.

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>
实现代理的代码:
// 被代理对象
public class Car {

	// 品牌
	private String brand;

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public void run() {
		System.out.println("Car run......");
	}
}
// 代理逻辑
public class CglibProxy {

	public static void main(String[] args) {

		Enhancer enhancer = new Enhancer();
		// 设置父类类型
		enhancer.setSuperclass(Car.class);
		// 设置具体的代理处理方法
		enhancer.setCallback(new MethodInterceptor() {
			/**
			 * 参数介绍
			 * @param obj 被代理类
			 * @param method 被代理方法
			 * @param args 方法参数
			 * @param methodProxy 代理方法
			 */
			@Override
			public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
				System.out.println("------方法执行前------");
				/**
				 * 不要尝试直接执行被代理类的方法  method.invoke(obj, args) 因为每次调用都会被intercept拦截 会出现递归调用直到栈溢出
				 */
				Object result = methodProxy.invokeSuper(obj, args);
				System.out.println("------方法执行后------");
				return result;
			}
		});
		Car carProxy = (Car) enhancer.create();
		carProxy.run();
	}
}
/**
 * 执行结果
 * ------方法执行前------
 * Car run......
 * ------方法执行后------
 */
JDK动态代理与CGLIB动态代理的区别:

1.代理条件
JDK动态代理依赖于被代理类的接口
CGLIB动态代理不需要代理类实现接口
2.代理类的生成
.JDK动态代理通过反射与InvocationHanlder拦截器实现代理类,在调用被代理类的方法前后通过InvokeHandler进行拦截处理.
CGLIB通过ASM修改被代理类的字节码文件生成代理类的字节码文件(代理类的子类),过反射实例化代理类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值