java反射和动态代理

反射

反射的官方定义是这样的:java

    在运行状态中,对于任意的一个类,都可以知道这个类的全部属性和方法,对任意一个对象都可以经过反射机制调用一个类的任意方法,这种动态获取类信息及动态调用类对象方法的功能称为java的反射机制。api

通常建立类的方式:ide

        Car car = new Car();
        car.setName("宝马");

而反射则是一开始并不知道我要初始化的类对象是什么,天然也没法使用 new 关键字来建立对象了。这时候,咱们使用 JDK 提供的反射 API 进行反射调用:函数

        Class clz = Class.forName("Car");
        Method method = clz.getMethod("setName", String.class);
        Constructor constructor = clz.getConstructor();
        Object object = constructor.newInstance();
        method.invoke(object, "宝马");

 

jdk提供了三种方式获取一个对象的Class,就Car car来讲测试

1.car.getClass(),这个是Object类里面的方法ui

2.Car.Class属性,任何的数据类型,基本数据类型或者抽象数据类型,均可以经过这种方式获取类this

3.Class.forName(""),Class类提供了这样一个方法,让咱们经过类名来获取到对象类spa

这三种方法用的最多的就是第三种,那么获取到类以后,Class类提供了不少获取类属性,方法,构造方法的api。代理

 

经过反射建立类对象主要有两种方式:经过 Class 对象的 newInstance() 方法、经过 Constructor 对象的 newInstance() 方法。code

第一种:经过 Class 对象的 newInstance() 方法。

        Class clz = Car.class;
        Car car = (Car)clz.newInstance();

第二种:经过 Constructor 对象的 newInstance() 方法

        Class clz = Car.class;
        Constructor constructor = clz.getConstructor();
        Car car = (Car)constructor.newInstance();

经过 Constructor 对象建立类对象能够选择特定构造方法,而经过 Class 对象则只能使用默认的无参数构造方法。下面的代码就调用了一个有参数的构造方法进行了类对象的初始化。

        Class clz = Car.class;
        Constructor constructor = clz.getConstructor(String.class);
        Car car = (Car) constructor.newInstance("宝马");

 

经过反射获取类属性、方法、构造器:

getDeclaredMethods() 获取全部的方法

getReturnType() 得到方法的放回类型

getParameterTypes() 得到方法的传入参数类型

getDeclaredMethod("方法名",参数类型.class,……) 得到特定的方法

getDeclaredConstructors() 获取全部的构造方法

getDeclaredConstructor(参数类型.class,……) 获取特定的构造方法

getSuperclass() 获取某类的父类

getInterfaces() 获取某类实现的接口

getFields():得到某个类的全部的公共(public)的字段,包括父类中的字段。 
getDeclaredFields():得到某个类的全部声明的字段,即包括public、private和proteced,可是不包括父类的申明字段。

一样相似的还有getConstructors()和getDeclaredConstructors()、getMethods()和getDeclaredMethods(),这二者分别表示获取某个类的方法、构造函数。

通常状况下,咱们并不能对类的私有字段进行操做,利用反射也不例外,但有的时候,例如要序列化的时候,咱们又必须有能力去处理这些字段,这时候,咱们就须要调用AccessibleObject上的setAccessible()方法来容许这种访问,而因为反射类中的Field,Method和Constructor继承自AccessibleObject,所以,经过在这些类上调用setAccessible()方法,咱们能够实现对这些字段的操做。

例子:

Car.java
public class Car {
    private String name;

    public Car(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
若是在Car.java内部建立mian方法测试的时候,是不会报异常的。
TestReflect.java
import java.lang.reflect.Field;

public class TestReflect {
    public static void main(String[] args) throws Exception {
        Car car = new Car("宝马");
        Class clz = Car.class;
        Field name = clz.getDeclaredField("name");
//        name.setAccessible(true);
        System.out.println(name.get(car));//获取当前对象中当前Field的value
    }
}

测试报异常:

Exception in thread "main" java.lang.IllegalAccessException: Class TestReflect can not access a member of class Car with modifiers "private"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
    at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
    at java.lang.reflect.Field.get(Field.java:390)
    at TestReflect.main(TestReflect.java:9)

取消注释后正常

 动态代理

代理模式的定义:为其余对象提供一种代理以控制对这个对象的访问。在某些状况下,一个对象不适合或者不能直接引用另外一个对象,而代理对象能够在客户端和目标对象之间起到中介的做用。而代理模式又分为静态代理和动态代理。

静态代理通俗点将就是本身手写一个代理类,而动态代理则不用咱们手写,而是依赖于java反射机制。

Subject.java

public interface Subject {
    void doSomething();
}

RealSubject.java

public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("doSomething");
    }
}

ProxyObject.java

public class ProxyObject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("proxy Subject");
        new RealSubject().doSomething();
    }

    public static void main(String[] args) {
        new ProxyObject().doSomething();
    }
}

ProxyObject就是RealSubject的静态代理类,代替了RealSubject完成doSomething的工做。

 

Java中动态代理的实现,关键就是这两个东西:Proxy、InvocationHandler

ProxyHandler.java

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

public class ProxyHandler implements InvocationHandler {
    private Object realObject = null;

    public ProxyHandler(Object proxied) {
        this.realObject = proxied;
    }

    public Subject getProxy() {
        return (Subject) Proxy.newProxyInstance(realObject.getClass().getClassLoader(),
                realObject.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before invoke");
        return method.invoke(realObject, args);
    }

    public static void main(String[] args) {
        ProxyHandler proxyHandler = new ProxyHandler(new RealSubject());
        Subject subject = proxyHandler.getProxy();
        subject.doSomething();
    }
}

动态代理,必须先实现这个InvocationHandler接口,而后经过Proxy生成一个代理对象。

方法里面有一个Proxy类,这个Proxy类提供了不少方法,这里咱们用的是newProxyInstance方法,它有三个参数,第一个是被代理类的类构造器,第二个指的是被代理类的接口,也就是Subject接口,第三个是实现这个代理的类,这里就是本类。具体的来讲,这个方法执行了下面三步:

1.生成一个实现了参数interfaces里全部接口且继承了Proxy的代理类的字节码,而后用参数里的classLoader加载这个代理类。

2.使用代理类父类的构造函数 Proxy(InvocationHandler h)来创造一个代理类的实例,将咱们自定义的InvocationHandler的子类传入。

3.返回这个代理类实例,由于咱们构造的代理类实现了interfaces(也就是咱们程序中传入的realObject.getClass().getInterfaces())里的全部接口,所以返回的代理类能够强转成Subject类型来调用接口中定义的方法。

 

能够添加打印生成的代理对象的相关信息已方便分析:

新的ProxyHandler.java

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

public class ProxyHandler implements InvocationHandler {
    private Object realObject = null;

    public ProxyHandler(Object proxied) {
        this.realObject = proxied;
    }

    public Subject getProxy() {
        return (Subject) Proxy.newProxyInstance(realObject.getClass().getClassLoader(),
                realObject.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before invoke");
        return method.invoke(realObject, args);
    }

    public static void main(String[] args) {
        ProxyHandler proxyHandler = new ProxyHandler(new RealSubject());
        Subject subject = proxyHandler.getProxy();

        //这里能够经过运行结果证实subject是Proxy的一个实例,这个实例实现了Subject接口
        System.out.println(subject instanceof Proxy);

        //这里能够看出subject的Class类是$Proxy0,这个$Proxy0类继承了Proxy,实现了Subject接口
        System.out.println("subject的Class类是:" + subject.getClass().toString());
        System.out.print("subject中的属性有:");
        Field[] field = subject.getClass().getDeclaredFields();
        for (Field f : field) {
            System.out.print(f.getName() + ", ");
        }
        System.out.print("\n" + "subject中的方法有:");
        Method[] method = subject.getClass().getDeclaredMethods();
        for (Method m : method) {
            System.out.print(m.getName() + ", ");
        }

        System.out.print("\n" + "subject的父类是:" + subject.getClass().getSuperclass());
        System.out.print("\n" + "subject实现的接口是:");
        Class<?>[] interfaces = subject.getClass().getInterfaces();
        for (Class<?> i : interfaces) {
            System.out.print(i.getName() + ", ");
        }

        System.out.println("\n\n" + "运行结果为:");
        subject.doSomething();
    }
}

运行获得结果:

true
subject的Class类是:class com.sun.proxy.$Proxy0
subject中的属性有:m1, m3, m2, m0, 
subject中的方法有:equals, toString, hashCode, doSomething, 
subject的父类是:class java.lang.reflect.Proxy
subject实现的接口是:Subject, 

运行结果为:
before invoke
doSomething

分析Proxy类源代码

newProxyInstance方法功能:

(1)根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)建立代理类$Proxy0.$Proxy0类 实现了interfaces的接口,并继承了Proxy类. 
(2)实例化$Proxy0并在构造方法中把DynamicSubject传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值,以下

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

为了分析$Proxy0,能够生成 Proxy0的class文件,而后反编译出代码。

生成class文件的函数:

    public static void getProxy0Code() {
        byte[] classFile = ProxyGenerator.generateProxyClass("Proxy0", Subject.class.getInterfaces());
        try {
            File file = new File("Proxy0.class");
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(classFile);
            fos.flush();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }

经过jd-gui反编译出源代码

来看一下这个继承了Proxy的$Proxy0的源代码: 

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

public final class Proxy0 extends Proxy implements Subject {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public Proxy0(InvocationHandler paramInvocationHandler) {
        super(paramInvocationHandler);
    }

    public final boolean equals(Object paramObject) {
        try {
            return ((Boolean) this.h.invoke(this, m1, new Object[]{paramObject})).booleanValue();
        } catch (Error | RuntimeException localError) {
            throw localError;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final void doSomething() {
        try {
            this.h.invoke(this, m3, null);
            return;
        } catch (Error | RuntimeException localError) {
            throw localError;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final String toString() {
        try {
            return (String) this.h.invoke(this, m2, null);
        } catch (Error | RuntimeException localError) {
            throw localError;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final int hashCode() {
        try {
            return ((Integer) this.h.invoke(this, m0, null)).intValue();
        } catch (Error | RuntimeException localError) {
            throw localError;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m3 = Class.forName("Subject").getMethod("doSomething", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            return;
        } catch (NoSuchMethodException localNoSuchMethodException) {
            throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        } catch (ClassNotFoundException localClassNotFoundException) {
            throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
    }
}

接着把获得的$Proxy0实例强制转换成Subject,并将引用赋给subject。当执行subject.doSomething()方法时,就调用 了$Proxy0类中的doSomething()方法,进而调用父类Proxy中的h的invoke()方法.即 InvocationHandler.invoke()。 

 newProxyInstance生成代理对象的详细分析过程参考

相关文章
相关标签/搜索