Java教程

Java动态代理——JDK动态代理和CGLIB动态代理的实现

本文主要是介绍Java动态代理——JDK动态代理和CGLIB动态代理的实现,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

什么叫代理模式

代理模式(Proxy Patrern)就是将对象的直接访问变为访问这个对象的代理对象。即通过代理对象间接地访问原本的对象。

代理是为了扩展类而存在的,可以控制对目标类的服务的访问。

为了进行接下来的实验,首先创建一个接口InterfaceTest和一个实现了这个接口的类InterfaceTestImpl

//接口
public interface InterfaceTest {
	public void test(int x);
}
//实现类
public class InterfaceTestImpl implements InterfaceTest{

	@Override
	public void test(int x) {	System.out.println("test:".concat(this.getClass().getSimpleName()));
	}
}

1. JDK动态代理

JDK动态代理是通过JDK自带的Proxy类中的newProxyInstance()方法来动态生成代理对象的。我们需要实现InvocationHandler接口,在其invoke()方法中编写调用目标对象的代码。

下面编写代码来实现JDK动态代理:

public class Solution implements InvocationHandler{
//目标对象jdkTest
private final InterfaceTest jdkTest = new InterfaceTestImpl();
//代理对象的test()方法被调用时,此invoke方法将被调用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	System.out.println("before invoke ".concat(method.getName()));
	//去调目标对象jdkTest的test()方法
	method.invoke(jdkTest, args);
	System.out.println("after invoke ".concat(method.getName()));
	return null;
}

	public static void main(String[] args) {
	//利用反射,获取类加载器
Class<?> clazz = InterfaceTestImpl.class;
//创建代理对象proxy
InterfaceTest proxy = (InterfaceTest) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] {InterfaceTest.class},new Solution());
//调代理对象的test()方法
	proxy.test(1);
	}
}

这里用到的重要的方法,newProxyInstance,靠它动态生成代理对象。来看它的三个参数:

newProxyInstance
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
                               throws IllegalArgumentException

Returns an instance of a proxy class for the specified interfacesthat dispatches method invocations to the specified invocationhandler. 
Proxy.newProxyInstance throws IllegalArgumentException for the same reasons that Proxy.getProxyClass does.
  1. 第一个参数是ClassLoader loader,也就是目标类的类加载器,我们利用反射,获取目标类之后通过getClassLoader()方法得到类加载器。
  2. 第二个参数是Class<?>[] interfaces,指定要实现的接口。
  3. 第三个参数是InvocationHandler hInvocationHandler对象。

输出结果为:
在这里插入图片描述

总结实现JDK动态代理的步骤:

  1. 准备一个接口和一个实现它的类(即目标类);
  2. 新建一个类实现InvocationHandler接口,在其invoke()方法中编写调用目标对象的代码;
  3. 通过Proxy.newProxyInstance()方法创建代理对象。

这一切做完之后,调用代理对象的test()方法实际上最后会去执行目标对象的test()方法。通过debug可以观察到这个流程。

2. CGLIB动态代理

由于JDK动态代理是面向接口的,也就是说如果目标类没有相应的接口,JDK动态代理就无法为其创建代理。这时可以选择用CGLIB动态代理来实现。

下面编写代码来实现CGLIB动态代理:

public class Solution implements MethodInterceptor{
@Override
public Object intercept(Object caller, Method method, Object[] args, MethodProxy proxy) throws Throwable {
	// TODO 自动生成的方法存根
	System.out.println("before invokeSuper ".concat(method.getName()));
	proxy.invokeSuper(caller, args);
	//method.invoke(caller, args);
	System.out.println("after invokSuper ".concat(method.getName()));
	return null;
}
	public static void main(String[] args) {
	//创建类加强器,用来创建动态代理类
Enhancer eh = new Enhancer();
//指定父类,也就是目标类
eh.setSuperclass(InterfaceTestImpl.class);
//指定回调方法,当调用代理对象的某个方法时,此回调方法将被调用
eh.setCallback(new Solution());
//利用类加强器en创建代理对象
InterfaceTestImpl ns = (InterfaceTestImpl) eh.create();
ns.test(1);
ns.toString();
	}
}

输出结果为:
在这里插入图片描述
总结实现CGLIB动态代理的步骤:

  1. 准备一个目标类(无须实现接口);
  2. 新建一个类实现MethodIntercepto接口,并在intercept方法中编写调用目标对象的代码;
  3. 创建一个类加强器,指定目标类和回调方法(见第二步);
  4. 利用类加强器创建代理对象。

setSuperclass()方法可以看出,实际上目标类是代理类的父类。也就是说,CGLIB动态代理采用的是继承方式,所以不要求目标类实现特定的接口。

这篇关于Java动态代理——JDK动态代理和CGLIB动态代理的实现的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!