三、Java高级特性(注解、反射、动态代理)

一、静态代理

实现代码:
(1)自定义接口HttpRequest

package com.it.test.proxy;

/**
 * http 请求的接口
 */
public interface HttpRequest {
    void get();
    void post();

}

(2)创建实现类Retrofit、Vally。并实现HttpRequest接口

package com.it.test.proxy;

public class Retrofit implements HttpRequest {
    @Override
    public void get() {
        System.out.println("Retrofit get");
    }

    @Override
    public void post() {
        System.out.println("Retrofit post");
    }
}

package com.it.test.proxy;

public class Vally implements HttpRequest {
    @Override
    public void get() {
        System.out.println("Vally get");
    }

    @Override
    public void post() {
        System.out.println("Vally post");
    }
}

(3)创建代理类Agent,并实现HttpRequest接口,在代理类的构造方法中接受实际类,并在实现方法中通过实现类去调用。


/**
 * 代理类
 */
public class Agent implements HttpRequest {

    private HttpRequest request;

    public Agent(HttpRequest request) {
        this.request = request;
    }

    @Override
    public void get() {
        request.get();
    }

    @Override
    public void post() {
        request.post();
    }
}

(4)测试

package com.it.test.proxy;

public class Http {
    public static void main(String[] args) {
        HttpRequest httpRequest = new Agent(new Retrofit());
        httpRequest.get();
        httpRequest.post();

        HttpRequest httpRequest2 = new Agent(new Vally());
        httpRequest2.get();
        httpRequest2.post();
    }
}

在实现中,我们只需要创建代理类,并传入具体的实际类。通过调用代理类的方法,其实内部完成实际类的调用。代理类,相当做了一层隔离。假如哪一天我们的实际类修改了,换成了别的。我们只需要修改传入相应的实际类即可。
缺点:当哪一天我们的实际类实现了多个接口,增加了方法,这样一来,代理类就没法代理。因为代理类的构造方法中只接受了一种类型。

二、动态代理

我们知道代理设计模式包含了三个对象

  • 代理接口
  • 代理类
  • 被代理的类
    被代理的类和代理类都实现了代理接口。在静态代理中,代理类只能代理实现一个接口的类,所以当被代理类实现多个接口的时候,无法被代理,因此出现了动态代理。动态代理可以代理多个接口。

1、动态代理使用方法

(1)创建代理接口IWash、IMessage

package com.example.lib;

public interface IWash {
    void wash(String msg);
}

package com.example.lib;

public interface IMessage {

    void outMessage();
}

(2)创建被代理类,实现IWash和IMessage接口

package com.example.lib;

public class Luxi implements IMessage,IWash {
    @Override
    public void outMessage() {
        System.out.println("Luxi outMessage");
    }


    @Override
    public void wash(String msg) {
        System.out.println("Luxi wash"+msg);
    }
}

(3)通过Proxy.newProxyInstance创建代理对象

        /**
         *动态代理
         * Object o 代理对象
         *
         * luxi 被代理对象
         *
         */
        final Luxi luxi = new Luxi();
        InvocationHandler handler =   new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                return method.invoke(luxi,objects);
            }
        };
        /**
         * 创建代理对象
         * Object o
         * newProxyInstance 方法会在底层生成一个代理类.class到内存中,
         * 而在代理类的构造方法中接受了一个InvocationHandler handler。
         * 我们传入匿名内部类,实现其invoke方法,
         * 当我们通过代理对象调用代理接口方法的时候
         * 在代理类里会通过传入的handler调用invoke方法,并传入 三个参数
         * (1)Object o 代理对象
         * (2)Method method 通过反射 获取到的接口的方法,也就是代理类调用接口的方法。
         * (3)Object[] objects 方法的参数
         * 接着就会回调我们实现的invoke方法
         * 在invoke方法中通过反射 使用method 对象执行方法,传入我们被代理的类对象执行方法,其中还包含了方法的参数
         *
         *
         *
         */
        Object o = Proxy.newProxyInstance(MyClass.class.getClassLoader(), new Class[]{IMessage.class,IWash.class},handler );
        /**
         * 这个地方代理对象o之所以可以强转成IMessage,
         * 又可以强转成IWash
         * 是因为代理类可以实现多个接口,
         * 所以可以强转成任意接口类型
         *
         *
         */
        IMessage msg = (IMessage) o;
        msg.outMessage();
        IWash wash = (IWash) o;
        wash.wash("  hello world");

       // proxy();


    }

通过代理对象调用outMessage和wash方法, 最终执行了被代理对象 Luxi的outMessage和wash方法

Luxi outMessage
Luxi wash  hello world

2、动态代理原理分析

(1)创建动态代理对象,传入InvocationHandler handler

   InvocationHandler handler =   new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                return method.invoke(luxi,objects);
            }
        };
   
        Object o = Proxy.newProxyInstance(MyClass.class.getClassLoader(), new Class[]{IMessage.class,IWash.class},handler );

我们通过Proxy.newProxyInstance方法传入classLoader,代理接口的class数组、和InvocationHandler handler创建了一个代理对象。
我们知道创建对象肯定需要类,那么此时我们需要创建一个代理类,才能实例化代理对象。因此在底层实现中首先会创建一个代理的类的class,也就是编译之后的class文件。写入到了内存。底层通过调用ProxyGenerator的generateProxyClass方法实现。为了分析动态代理的原理,我们手动创建一个代理类。


    /**
     * 生成代理类
     */
    private static void proxy(){
        String name = IMessage.class.getName()+"$Proxy";
        //生成代理类 的Class数据
        byte [] bytes = ProxyGenerator.generateProxyClass(name,new Class[]{IMessage.class,IWash.class});
        try {
            FileOutputStream outputStream =new FileOutputStream("lib/"+name+".class");
            outputStream.write(bytes);
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

下面是我们生成的代理类IMessage$Proxy

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.example.lib;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class IMessage$Proxy extends Proxy implements IMessage, IWash {
    private static Method m1;
    private static Method m4;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public IMessage$Proxy(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void wash(String var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void outMessage() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m4 = Class.forName("com.example.lib.IWash").getMethod("wash", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.example.lib.IMessage").getMethod("outMessage");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}


也就是当我们调用 Object o = Proxy.newProxyInstance创建代理对象的时候,会先在内存中创建一个IMessageProxy的代理类,然后再通过实例化这个代理类创建代理对象。 我们看到IMessageProxy的构造方法中接受了一个InvocationHandler 类型的参数,也就是我们传入的InvocationHandler handler ,你们内部类对象。实现了invoke方法。

  InvocationHandler handler =   new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                return method.invoke(luxi,objects);
            }
        };

当通过代理对象调用里面的wash方法的时候,就会调用super.h.invoke方法。

  public final void wash(String var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

而h又是父类的成员,接受的正式我们传入的InvocationHandler 。

    protected Proxy(InvocationHandler var1) {
        Objects.requireNonNull(var1);
        this.h = var1;
    }

因此最终调用了我们内部类实现的invoke方法

  InvocationHandler handler =   new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                return method.invoke(luxi,objects);
            }
        };

也就是创建代理对象,通过代理对象调用代理接口的方法最终会调用到了我们内部类的invoke方法,

invoke方法有三个参数,我们可以在源码中看到。

   static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m4 = Class.forName("com.example.lib.IWash").getMethod("wash", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.example.lib.IMessage").getMethod("outMessage");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
   public final void wash(String var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
  • Object o对象指的是当前的代理对象
  • Method method就是源码中的
m4 = Class.forName("com.example.lib.IWash").getMethod("wash", Class.forName("java.lang.String"));

就是通过反射获取代理接口中的方法,封装成Method。

  • Object[] objects就是new Object[]{var1},通过代理对象调用方法的时候,我们方法传入的参数,封装成了一个数组。
    最后在invoke方法中,我们拿到以上的Method对象和参数数组Object[] objects,我们可以通过调用 method.invoke(luxi,objects);方法,从而达到调用了被代理对象Luxi luxi中的方法。因为代理类和被代理都实现了同一个接口,因此代理类调用的方法,最终反射获取到该方法,再让被代理类调用完成最终的实现。
     final Luxi luxi = new Luxi();
        InvocationHandler handler =   new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                return method.invoke(luxi,objects);
            }
        };

小结

  • 动态代理可以代理多个接口,静态代理只能代理一个接口
  • 动态代理类不是通过我们手动生成,而是通过ProxyGenerator.generateProxyClass动态生成的一个class。
  • 动态代理类创建代理对象的时候需要传入InvocationHandler 对象,而InvocationHandler 对象是一个接口,因此我们需要手动实现其中invoke方法,invoke方法包含了三个参数,当前代理类对象,Method对象(封装了要代理的方法),Object[]参数数组(封装了代理方法的参数值)
  • 当我们创建代理对象之后,调用了代理方法,接着在代理类的内部调用了invoke方法,接着回调到了我们实现的invoke方法
  • 在invoke方法中我们可以拿到代理的方法和参数,通过反射中method.invoke方法,传入被代理的对象。最终调用了代理对象的方法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章