java动静态代理实现原理

    技术2022-07-11  89

    一.什么是代理?

    代理是不直接通过代理类访问方法,而是通过被代理类的代理对象,间接访问代理类里面的方法。 就好比:(被代理类)相亲女——婚介所(代理类)这种模式,直接通过婚介所(代理类),知道相亲女的择偶要求(被代理类)。

    1.代理有几种?

    一.代理分为静态代理和动态代理 静态代理:是在编译期时,知道哪个是被代理的类,那么使用类的静态代理。 动态代理:在编译期时,不知道哪个是被代理的类,那么使用类的动态代理。

    二.静态代理的实现 创捷一个接口类(女孩)

    public interface Girl { void date(); void watchMovie(); }

    王美丽,重写方法(作为被代理类)

    public class WangMeiLi implements Girl { @Override public void date() { System.out.println("王美丽说:跟你约会好开心啊"); } @Override public void watchMovie() { System.out.println("王美丽说:这个电影我不喜欢看"); } }

    婚介所(代理类),传入被代理类girl,重写date和watch方法,调用被代理类girl里面的方法(此步骤实际为增强此方法内容)

    public class hunjiesuo implements Girl{ private Girl girl; public hunjiesuo(Girl girl) { this.girl=girl; } @Override public void date() { System.out.println("准备约会"); girl.watchMovie(); } @Override public void watchMovie() { System.out.println("准备看电影"); girl.watchMovie(); } }

    测试此方法

    public class Demo { public static void main(String[] args) { Girl girl= new WangMeiLi(); hunjiesuo hjs= new hunjiesuo(girl); hjs.date(); hjs.watchMovie(); } }

    输出结果

    D:\Java\jdk-13.0.1\bin\java.exe -Dvisualvm.id=27764171229000 "-javaagent:D:\idea\IntelliJ IDEA 2020.1\lib\idea_rt.jar=49787:D:\idea\IntelliJ IDEA 2020.1\bin" -Dfile.encoding=UTF-8 -classpath D:\IdeaProjects\basic-code\out\production\day04-code;C:\Users\Administrator\.m2\repository\org\junit\jupiter\junit-jupiter\5.4.2\junit-jupiter-5.4.2.jar;C:\Users\Administrator\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.4.2\junit-jupiter-api-5.4.2.jar;C:\Users\Administrator\.m2\repository\org\apiguardian\apiguardian-api\1.0.0\apiguardian-api-1.0.0.jar;C:\Users\Administrator\.m2\repository\org\opentest4j\opentest4j\1.1.1\opentest4j-1.1.1.jar;C:\Users\Administrator\.m2\repository\org\junit\platform\junit-platform-commons\1.4.2\junit-platform-commons-1.4.2.jar;C:\Users\Administrator\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.4.2\junit-jupiter-params-5.4.2.jar;C:\Users\Administrator\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.4.2\junit-jupiter-engine-5.4.2.jar;C:\Users\Administrator\.m2\repository\org\junit\platform\junit-platform-engine\1.4.2\junit-platform-engine-1.4.2.jar DD1.Demo 准备约会 王美丽说:这个电影我不喜欢看 准备看电影 王美丽说:这个电影我不喜欢看 Process finished with exit code 0

    结论:此方法是不改变被代理类的基础上,通过代理类扩展,进行功能的延伸与增加。要注意的是,代理类要与被代理类对象实现同一个接口。

    三.动态代理的实现 静态代理时,我们手动创建代理类hunjiesuo,而动态代理时在程序运行时,自动生成代理类,并实现Girl接口。

    public interface Girl { void date(); void watchMovie(); } public class WangMeiLi implements Girl { @Override public void date() { System.out.println("王美丽说:跟你约会好开心啊"); } @Override public void watchMovie() { System.out.println("王美丽说:这个电影我不喜欢看"); } }

    前两个步骤相同,不同之处在于代理类的实现,

    public class WangMeiLiProxy implements InvocationHandler { 创建代理对象的类需要继承 InvocationHandler private Girl girl; public WangMeiLiProxy(Girl girl){ this.girl=girl; } 重写接口InvocationHandler的invoke方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("嘻嘻嘻嘻"); Object ret= method.invoke(girl,args); return ret; } 创建代理对象(Proxy.newProxyInstance) 第一个参数是类加载器,第二个参数是被代理类实现的接口,第三个参数是 InvocationHandler public Object getProxyInstance(){ return Proxy.newProxyInstance(girl.getClass().getClassLoader(),girl.getClass().getInterfaces(),this); } }

    测试方法

    public class test { public static void main(String[] args) { Girl girl = new WangMeiLi(); WangMeiLiProxy wa = new WangMeiLiProxy(girl); Girl gir = (Girl) wa.getProxyInstance(); gir.watchMovie();

    当wa.getProxyInstance时,开始创建代理类对象,此时传入girl里面的方法,下面是生产代理对象时,里面的编码(不完整,只取部分)

    public class OProxyO extends Proxy implements Girl { //girl传入的方法,用m1,2.3接收 private static Method m1; private static Method m2; private static Method m3; public final String watchMovie(String varl) throws { super.h是InvocationHandler,m3是传入的方法,即watchMovie try { return (String)super.h.invoke(this,m3,new Object[] {varl}) }catch (RuntimeException| Error var3){ throw var3; } catch (Throwable throwable) { throwable.printStackTrace(); } }

    代理对象创建后,执行watchMoive方法,此时里面会执行invoke方法,而在WangMeiLiProxy中,我们重写了invoke方法,此中的Object ret= method.invoke(girl,args) 是执行WangMeiLi的wachMoive方法 测试结果如下

    嘻嘻嘻嘻 王美丽说:这个电影我不喜欢看 Process finished with exit code 0

    结论:代理对象程序是在运行时,调用getProxyInstance()方法,通过类加载加载,才会产生的。当调用代理对象里面的方法,此方法会在实现自己的方法的同时,又回调被代理对象的方法,从而达到增强和扩展的目的。

    Processed: 0.010, SQL: 9