java动静态代理实现原理

一.什么是代理?

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

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()方法,通过类加载加载,才会产生的。当调用代理对象里面的方法,此方法会在实现自己的方法的同时,又回调被代理对象的方法,从而达到增强和扩展的目的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值