zoukankan      html  css  js  c++  java
  • JDK动态代理详解-依赖接口

    0. 原理分析

    a). 自定义实现InvocationHandler类,实现代理类执行时的invoke方法
    b). 使用Proxy.newProxyInstance生成接口的代理类(入参还包括InvocationHandler)
    c). 所有的proxyImpl.methodName都会被invoke方法拦截
    d). 备注: 推荐反编译$Proxy0.查看
    	1 -- 设置系统参数以保存中间态生成的class文件,  文件名类似 $Proxy0.class
    		System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true")
    	2 -- $Proxy0.class所在的目录 System.getProperty("user.dir")/com/sun/proxy/, 即执行java命令的目录下
    		IDEA和eclipse中是工程的根目录
    

    1. 示例

    1.1 示例1--直接代理接口(Mybatis的Mapper)

    TestInterface.java
    public interface TestInterface {
        public void saySomething(String thing);
    }
    
    InvokeMethodClass.java
    public  class InvokeMethodClass  implements InvocationHandler{
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("进入invoke方法!");
            //method.invoke("zzzzzz");
            System.out.println("invoke执行结束");
            return null;
        }
    
        public static void main(String[] args) {
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");	//保存中间态的代理类class到文件
            TestInterface tt = (TestInterface) Proxy.newProxyInstance(TestInterface.class.getClassLoader(), new Class[]{TestInterface.class}, new InvokeMethodClass());
            tt.saySomething("sssssss");
        }
    }
    

    执行:

    java -cp G:practiceidea-newideaMaven	argetclasses  test.java.proxytest.InvokeMethodClass
    进入invoke方法!
    invoke执行结束
    

    1.2 示例2--代理接口实现类(Spring中AOP实现之一)

    TestInterface.java
    public interface TestInterface {
        public void saySomething(String thing);
    }
    
    TestInterfaceImpl.java
    public class TestInterfaceImpl implements TestInterface
    {
        public void saySomething(String thing) {
            System.out.println("接口实现类的方法:"+thing);
        }
    }
    
    InvokeMethodClass.java
    public class InvokeMethodClass implements InvocationHandler {
    
        //需要代理的实现类
        private Object impl;
    
        //生成代理类
        public Object bind(Object impl) {
            this.impl = impl;
            return  (TestInterface) Proxy.newProxyInstance(TestInterface.class.getClassLoader(), impl.getClass().getInterfaces(), this);
        }
    
        //方法调用时触发的方法
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("进入invoke方法!");
            method.invoke(impl, "zzzzzz");
            System.out.println("invoke执行结束");
            return null;
        }
    
        public static void main(String[] args) {
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
            InvokeMethodClass invokeMethodClass = new InvokeMethodClass();
    
            TestInterface tt = (TestInterface) invokeMethodClass.bind(new TestInterfaceImpl());
            System.out.println("代理类的class:" + tt.getClass().getName());
    
            tt.saySomething("sssssss");
        }
    }
    

    执行结果:java -cp G:practiceidea-newideaMaven argetclasses test.java.proxytest.InvokeMethodClass

    代理类的class:com.sun.proxy.$Proxy0
    进入invoke方法!
    接口实现类的方法:zzzzzz
    invoke执行结束
    

    2. Proxy.newProxyInstance源码分析

    Proxy.newProxyInstance() -->  Class<?> cl = getProxyClass0(loader, intfs); 
    --> proxyClassCache.get();   	//proxyClassCache来自何处
    		proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
    		WeakCache(BiFunction<K, P, ?> subKeyFactory,
    						 BiFunction<K, P, V> valueFactory) {
    			this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
    			this.valueFactory = Objects.requireNonNull(valueFactory);
    		}
    		Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    --> ProxyClassFactory.apply();	//生产
    --> byte[] proxyClassFile = ProxyGenerator.generateProxyClass(		//生成classFile
                proxyName, interfaces, accessFlags);
    --> if(saveGeneratedFiles) 		//是否保存生成的class文件,前面设置的系统参数及在此处
    	saveGeneratedFiles = ((Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"))).booleanValue();
  • 相关阅读:
    微信H5跳转到小程序
    对比React的hooks与Vue的composition
    H5网页在ios,android,微信中打开手机中的地图导航
    MySQL学习笔记(一)
    Matlab学习笔记(五)
    Matlab学习笔记(四)
    Matlab学习笔记(三)
    Matlab学习笔记(二)
    Matlab学习笔记(一)
    Python学习笔记(四)
  • 原文地址:https://www.cnblogs.com/Desneo/p/7253562.html
Copyright © 2011-2022 走看看