简单使用JDK的Proxy.newProxyInstance()方法
程序员文章站
2022-06-01 10:23:07
...
JDK的动态代理实现的原理其实是动态生成Proxy的.java文件,再动态编译.java文件成为对应的.class文件,再通过ClassLoader将字节码对象加载到内存中从而实现动态的效果。现在主要是测试一下如何使用JDK的动态代理,不做原理的分析。如果想了解原理可以观看
马士兵的设计模式之动态代理
深入剖析。
package cn.shaines.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
/**
* 定义一个接口
*/
interface MyInterface {
int getInt(int i);
void close();
}
/**
* 接口实现类
*/
class MyInterfaceImpl implements MyInterface {
@Override
public int getInt(int i) {
return i;
}
@Override
public void close() {
System.out.println("==>>close()");
}
public void otherMethod(){
System.out.println("==>>otherMethod()");
}
}
/**
* 测试类JDK代理
*/
public class Test {
/**
* 反射执行方法
* @param o 调用对象
* @param methodName 方法名称
* @param parameterTypes 参数类型.class
* @param parameters 参数实体
*/
public static <R> R methodInvoke(Object o, String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
return (R) ((parameterTypes == null) ? o.getClass().getMethod(methodName).invoke(o) : o.getClass().getMethod(methodName, parameterTypes).invoke(o, parameters));
}
// 入口main
public static void main(String[] args) {
// 使用JDK提供的动态代理方法步骤如下:
// 步骤01: 创建需要代理的实体类对象
MyInterfaceImpl myInterfaceImpl = new MyInterfaceImpl();
// 步骤02: 获取实体类对象的Class对象
Class<? extends MyInterfaceImpl> clazz = myInterfaceImpl.getClass();
// 步骤03: 调用JDK提供的Proxy.newProxyInstance()方法
Object proxyInstance = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 步骤04: 动态修改getInt()方法
if (method.getName().equals("getInt")){
System.out.println("代理类收到的参数是:" + args[0]);
return 100;
}
// 步骤05: 注意这里的实际调用必须是实现类对象
return method.invoke(myInterfaceImpl);
}
});
// cn.shaines.test.MyInterfaceImpl
System.out.println(clazz.getClass().getName());
// java.lang.Class
System.out.println(clazz.getName());
// 步骤06: 使用代理对象(强制转换为接口对象MyInterface,不可以强制转换为MyInterfaceImpl,
// 通过上面的打印可以知道proxyInstance的class和MyInterfaceImpl的class是不同的,强制转换会报错)
// MyInterfaceImpl myInterfaceImpl2 = ((MyInterfaceImpl) proxyInstance);// 报错
MyInterface myInterface1 = ((MyInterface) proxyInstance);
int anInt = myInterface1.getInt(20);
System.out.println("anInt:" + anInt);// anInt:100 被动态修改值
myInterface1.close();
// 放射执行方法,无需强制转为对象都可以使用proxyInstance调用任意方法
try {
int i = methodInvoke(proxyInstance, "getInt", new Class[]{int.class}, new Object[]{10});
methodInvoke(proxyInstance, "close", new Class[]{}, new Object[]{});
// methodInvoke(proxyInstance, "otherMethod", new Class[]{}, new Object[]{});
// 这个方法会报错:java.lang.NoSuchMethodException: cn.shaines.test.$Proxy0.otherMethod()
// 找不到该方法,原因很简单,该动态代理对象是实现接口(MyInterface),不是继承接口实现类(MyInterfaceImpl),所以只有接口的方法,没有具体实现对象(myInterfaceImpl)的方法
} catch (Exception e) {
e.printStackTrace();
}
}
}
上一篇: DZNEmptyDataSet的使用
下一篇: 函数与sting对象
推荐阅读
-
如何通过复制粘贴赚到人生第一桶金(新手可做超级简单的赚钱方法)
-
推荐几种兼职在网上赚钱最快的方法(月入一万很简单)
-
使用.Net Core + Vue + IdentityServer4 + Ocelot 实现一个简单的DEMO +源码
-
手机游戏赚钱到微信的方法,日赚50-100其实非常简单!
-
远程桌面无法使用剪切板的有效解决方法
-
在linux服务器下使用版本控制软件SVN的方法
-
centos7.2.1511安装jdk1.8.0_151及mysql5.6.38的方法
-
啰嗦的 java,简洁的 lombok —— lombok 的使用及简单实现单例模式注解
-
linux下使用perl获取本机ip的几种方法介绍
-
使用CSS3滤镜的filter:blur属性制作毛玻璃模糊效果的方法