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();
posted @ 2017-07-29 09:40  Desneo  阅读(252)  评论(0编辑  收藏  举报