Java动态代理——JDK动态代理和CGLIB动态代理的实现
2021/6/10 22:24:58
本文主要是介绍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.
- 第一个参数是
ClassLoader loader
,也就是目标类的类加载器,我们利用反射,获取目标类之后通过getClassLoader()
方法得到类加载器。 - 第二个参数是
Class<?>[] interfaces
,指定要实现的接口。 - 第三个参数是
InvocationHandler h
,InvocationHandler
对象。
输出结果为:
总结实现JDK动态代理的步骤:
- 准备一个接口和一个实现它的类(即目标类);
- 新建一个类实现
InvocationHandler
接口,在其invoke()
方法中编写调用目标对象的代码; - 通过
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动态代理的步骤:
- 准备一个目标类(无须实现接口);
- 新建一个类实现
MethodIntercepto
接口,并在intercept
方法中编写调用目标对象的代码; - 创建一个类加强器,指定目标类和回调方法(见第二步);
- 利用类加强器创建代理对象。
从setSuperclass()
方法可以看出,实际上目标类是代理类的父类。也就是说,CGLIB动态代理采用的是继承方式,所以不要求目标类实现特定的接口。
这篇关于Java动态代理——JDK动态代理和CGLIB动态代理的实现的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-09-28AI给的和自己写的Python代码,都无法改变输入框的内容,替换也不行
- 2024-09-27Sentinel配置限流资料:新手入门教程
- 2024-09-27Sentinel配置限流资料详解
- 2024-09-27Sentinel限流资料:新手入门教程
- 2024-09-26Sentinel限流资料入门详解
- 2024-09-26Springboot框架资料:初学者入门教程
- 2024-09-26Springboot框架资料详解:新手入门教程
- 2024-09-26Springboot企业级开发资料:新手入门指南
- 2024-09-26SpringBoot企业级开发资料新手指南
- 2024-09-26Springboot微服务资料入门教程