标签:一个 调用 分享图片 image oca 9.png override 查看 nts
代理的作用就是在访问真实对象之前或者之后可以额外加入一些操作。
public interface HelloWorld { void sayHellowWorld(); }
public class HelloWorldImpl implements HelloWorld { @Override public void sayHellowWorld() { System.out.println("Hello World !"); } }
public class JdkProxySImpleDemo implements InvocationHandler { //代理类必须实现 InvocationHandler 接口 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ } }
public class JdkProxySImpleDemo implements InvocationHandler { //真实对象 public Object target = null;
//建立代理对象和真实对象的代理关系,并返回代理对象 public Object bind(Object target){ this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException { } }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException { System.out.println("sayHelloWorld 执行前"); //实现代理方法 Object Obj = method.invoke(target,args);
System.out.println("sayHelloWorld 执行后"); return Obj; }
public static void main(String[] args) { JdkProxySImpleDemo porxy = new JdkProxySImpleDemo(); HelloWorld helloWorld = (HelloWorld)porxy.bind(new HelloWorldImpl()); helloWorld.sayHellowWorld(); } //执行结果 sayHelloWorld 执行前 Hello World ! sayHelloWorld 执行后
只有同一个类加载器加载的字节码生成的对象才是同一个对象,这里的传入真实对象的类加载器,一来确定此代理类是否被此加载器加载,二来如果没有加载则指定使用真实对象的类加载器加载代理类。
真实对象实现的接口不能超过65535个。
这里出现了ConcurrentMap ,所有代理类的Class对象会存储在这。它是一个二级map,最外层map的key就是 类加载器,值也是一个ConcurrentMap ,这个map 的key存放代理类Class 对象,value 是一个Boolean 值 。
这里根据 类加载器 找值 如果为空则进行初始化创建 ConcurrentMap。
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); 生成代理类的字节码并创建代理类Class对象
apply 方法是Proxy类的内部类ProxyClassFactory的方法,它可以生成字节码,并且创建Class对象
首先会检查确保真实对象实现的接口是由同一个类加载器加载的,还会检查是否是接口
检查通过后就会生成代理类对象的字节码 .class
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); 生成二进制字节码。
生成的字节码保存在缓存中,创建字节码比较耗费性能,所以一次创建好后保存在缓存中下次可以直接使用减少性能开销。
defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length); 这里使用 一个本地方法生成 代理类的Class对象。
c1 就是 代理类的Class对象 ,return cons.newInstance(new Object[]{h}); 创建代理对象的实例;
使用反编译工具打开$Ptoxy0.class(IDEA自带反编译工具)
可以看到 代理类 继承自 Proxy 类,实现了被代理类的接口。
这也是为什么被代理对象要实现接口,要想代理必须要有相同的方法替代真实方法执行,一种就是继承被代理类,另一种就是拥有共同接口,由于Java只能单继承所以只能实现共同的接口
super.h就是 代理对象自己 ,这相当于执行 代理对象重载的invoke方法
Method 对象 m3 = Class.forName("day0826_proxy.HelloWorld").getMethod("sayHellowWorld"); 存储了真实对象方法的信息
最后利用反射 调用真实对象的 方法。动态代理完成
标签:一个 调用 分享图片 image oca 9.png override 查看 nts
原文地址:https://www.cnblogs.com/mibloom/p/9538883.html