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:\practice\idea-new\ideaMaven\target\classes  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:\practice\idea-new\ideaMaven\target\classes 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();

转载于:https://www.cnblogs.com/Desneo/p/7253562.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值