Java—反射机制实战及动态代理总结

技术公众号:后端技术解忧铺
关注微信公众号:CodingTechWork,一起学习进步。

引言

  反射在Java技术应用中是老生常谈的事了,我们每次都是知道个皮毛,这个反射可以动态获取类的信息,比如类的属性和方法,但是在平时疯狂写CURD业务代码时,却很少关注或接触使用到反射机制。当然,这并不代表反射没落,反射无用,其实,在高级开发中,还是大量使用了反射机制的,比如我们常说的动态代理、注解等场景都是需要依靠反射来实现。

反射介绍

概念

  反射是在运行状态中,对于任意一个类,我们都能够通过反射机制获取到这个类的所有属性方法,对于任意一个对象,我们都可以通过反射机制调用它的任意一个属性和方法,包括private类型。这种能够动态获取类的信息和动态调用对象的属性和方法的功能就是JAVA中的反射机制。

作用

  1. 反射机制可以操作字节码文件,可以读取和修改字节码文件。
  2. 反射机制可以操作代码片段,可以操作class文件。

反射的类

说明
java.lang.Class该类表示JVM运行时类或接口信息,每个class都有对应的Class对象,代表整个类
java.lang.reflect.Field表示字节码中的属性字节码,代表类中的成员变量
java.lang.reflect.Method表示字节码中的方法字节码,代表类中的方法
java.lang.reflect.Constructor表示字节码中的构造方法字节码,代表类中的构造方法

获取Class的4种方法

  1. 通过类.class获取
Class<?> pClass = PersonBean.class;
  1. 通过Class.forName()方法传入类的全路径获取:
Class<?> pClass = Class.forName("com.xxx.PersonBean");
  1. 通过对象实例getClass()方法获取
PersonBean p = new PersonBean();
Class<?> pClass = p.getClass();
  1. 通过类加载器loadClass()方法传入类的全路径获取:
Class<?> pClass = ClassLoader.getSystemClassLoader().loadClass("com.xxx.PersonBean");

反射实例化对象

//反射获取Class
Class<?> c = Class.forName("com.xxx.PersonBean");
//实例化对象
Object obj = c.newInstance();

反射访问私有属性和方法

需要通过setAccessible(boolean flag)方法将类的封装打破。

privateMethod.setAccessible(true);
privateMethod.invoke(obj);

Class类的方法列表

方法名说明
public T newInstance()创建对象实例
public String getName()返回全路径类名
public String getSimpleName()返回类名,不带路径
public Field[] getFields()返回类中public修饰的属性
public Field[] getDeclaredFields()返回类中所有属性
public Field getDeclaredField(String name)根据属性名name获取指定的属性
public native int getModifiers()native方法,获取属性的修饰符列表,一般配合Modifier类的toString(int xxx)方法使用
public Method[] getDeclaredMethods()返回类中所有实例方法
public Method getDeclaredMethod(String name, Class<?>… parameterTypes)根据方法名name和方法形参获取指定方法
public Constructor<?>[] getDeclaredConstructors()返回类中所有构造方法
public Constructor getDeclaredConstructor(Class<?>… parameterTypes)根据方法形参获取指定构造方法
public native Class<? super T> getSuperclass()返回调用类的父类
public Class<?>[] getInterfaces()返回调用类实现的接口集合

Field类的方法列表

方法名说明
public String getName()返回属性名
public int getModifiers()获取属性的修饰符列表,一般配合Modifier类的toString(int xxx)方法使用
public Class<?> getType()获取属性类型,一般配合Class类的getSimpleName()方法使用
public void set(Object obj, Object value)设置属性值
public Object get(Object obj)读取属性值

Method类的方法列表

方法名说明
public String getName()获取方法名
public int getModifiers()获取方法的修饰符列表,一般配合Modifier类的toString(int xxx)方法使用
public Class<?> getReturnType()获取方法类型,一般配合Class类的getSimpleName()方法使用
public Class<?>[] getParameterTypes()获取方法的修饰符列表,一般配合Class类的getSimpleName()方法使用
public Object invoke(Object obj, Object… args)调用方法

反射实战

目标类(PersonBean)

package com.test.selfcoding.bean;

/**
 * @ClassNAME PersonBean
 * @Description TODO
 * @Author Andya
 * @Version 1.0
 */
public class PersonBean {

    private String name;

    private int age;

    public PersonBean() {

    }

    public PersonBean(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void printPublicPersonInfo(String name) {
        System.out.println("person name is: " + name);
    }

    private void printPrivatePersonInfo(String name, int age) {
        System.out.println("person name is: " + name + ", age is: " + age);
    }

    private void printPersonName() {
        System.out.println("origin name is: " + name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

调用类(ReflectTest)

package com.test.selfcoding.service;

import com.test.selfcoding.bean.PersonBean;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @ClassNAME ReflectionTest
 * @Description TODO
 * @Author Andya
 * @Version 1.0
 */
public class ReflectionTest {


    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获取类Class对象并创建对应实例
        Class<?> targetClass = Class.forName("com.test.selfcoding.bean.PersonBean");
        Object obj = targetClass.newInstance();

        //获取所有域
        System.out.println("========fields=========");
        Field[] fields = targetClass.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        //获取所有构造函数
        System.out.println("========constructors=========");
        Constructor[] constructors = targetClass.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        //获取所有方法
        System.out.println("========method=========");
        Method[] methods = targetClass.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }

        //获取指定的public方法并调用
        System.out.println("获取指定的public方法并调用");
        Method publicMethod = targetClass.getDeclaredMethod("printPublicPersonInfo", String.class);
        publicMethod.invoke(obj, "xiaoming");

        //获取指定的private方法并调用
        System.out.println("获取指定的private方法并调用");
        Method privateMethod = targetClass.getDeclaredMethod("printPrivatePersonInfo", String.class, int.class);
        privateMethod.setAccessible(true);
        privateMethod.invoke(obj, "xiaohong", 20);

        //获取指定的参数
        System.out.println("获取指定的参数");
        Field nameField = targetClass.getDeclaredField("name");
        nameField.setAccessible(true);
        nameField.set(obj, "wangyuan");
        Method printNameMethod = targetClass.getDeclaredMethod("printPersonName");
        printNameMethod.setAccessible(true);
        printNameMethod.invoke(obj);

    }
}


执行结果

========fields=========
name
age
========constructors=========
public com.test.selfcoding.bean.PersonBean()
public com.test.selfcoding.bean.PersonBean(java.lang.String,int)
========method=========
printPublicPersonInfo
printPrivatePersonInfo
printPersonName
getAge
setAge
getName
setName
获取指定的public方法并调用
person name is: xiaoming
获取指定的private方法并调用
person name is: xiaohong, age is: 20
获取指定的参数
origin name is: wangyuan

代理

  什么是代理?代理proxy,其实就是为目标对象提供一个代理对象来控制访问方式,且能够在目标对象实现基础上提供额外的扩展功能。比如说,华为公司通过手机代理商去售卖手机,衣服原工厂通过各个代理商去售卖衣服,房地产通过中介公司售卖房子,等等。

接口和被代理类

接口

定义一个接口:手机厂商

package com.test.selfcoding.proxy.staticproxy;

public interface Phone {
    void sellPhone();
}

被代理类

被代理类1:华为手机厂商

package com.test.selfcoding.proxy.staticproxy;

/**
 * @ClassNAME HuaweiPhone
 * @Description TODO
 * @Author Andya
 * @Version 1.0
 */
public class HuaweiPhone implements Phone {

    @Override
    public void sellPhone() {
        System.out.println("sell huawei phone!");
    }
}

被代理类2:小米手机厂商

package com.test.selfcoding.proxy.staticproxy;

/**
 * @ClassNAME XiaoMiPhone
 * @Description TODO
 * @Author Andya
 * @Version 1.0
 */
public class XiaoMiPhone implements Phone{

    @Override
    public void sellPhone() {
        System.out.println("sell xiaomi phone");
    }
}

静态代理

  在学习动态代理之前,我们先学习一下,静态代理我们一般是怎样实现的。

静态代理类

代理类1:华为手机代理商

package com.test.selfcoding.proxy.staticproxy;

/**
 * @ClassNAME HuaweiPhoneProxy
 * @Description TODO
 * @Author Andya
 * @Version 1.0
 */
public class HuaweiPhoneProxy implements Phone {

    private Phone phone;

    public HuaweiPhoneProxy() {
        this.phone = new HuaweiPhone();
    }

    @Override
    public void sellPhone() {
        //代理商提供其他服务
        System.out.println("华为手机售前");
        //代理接口的操作
        phone.sellPhone();
        System.out.println("华为手机售后");
    }
}

被代理类2:小米手机代理商

package com.test.selfcoding.proxy.staticproxy;

/**
 * @ClassNAME XiaoMiPhoneProxy
 * @Description TODO
 * @Author Andya
 * @Version 1.0
 */
public class XiaoMiPhoneProxy implements Phone{

    private Phone phone;

    public XiaoMiPhoneProxy () {
        this.phone = new XiaoMiPhone();
    }


    @Override
    public void sellPhone() {
        //代理商提供其他服务
        System.out.println("小米手机售前");
        //代理接口的操作
        phone.sellPhone();
        System.out.println("小米手机售后");
    }
}

静态代理调用

package com.test.selfcoding.proxy.staticproxy;

/**
 * @ClassNAME StaticProxyTest
 * @Description TODO
 * @Author Andya
 * @Version 1.0
 */
public class StaticProxyTest {
    public static void main(String[] args) {
        //代理华为
        Phone huaweiProxy = new HuaweiPhoneProxy();
        huaweiProxy.sellPhone();

        //代理小米
        Phone xiaomiProxy = new XiaoMiPhoneProxy();
        xiaomiProxy.sellPhone();
    }
}

静态代理结果

华为手机售前
sell huawei phone!
华为手机售后
小米手机售前
sell xiaomi phone
小米手机售后

被代理类被传递给代理类后,代理类在执行具体方法时通过所持有的被代理类完成调用。我们可以看到每次代理只能为一个类服务,需要多个代理类来实现被代理类的访问。

动态代理

  看完静态代理,我们发现其缺点是随着手机厂商增多,代理类需要不断地增多,于是我们就用到了动态代理。

动态代理处理器

package com.test.selfcoding.proxy.staticproxy;

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

/**
 * @ClassNAME PhoneProxyHandler
 * @Description TODO
 * @Author Andya
 * @Version 1.0
 */
public class PhoneProxyHandler implements InvocationHandler {
    private Object object;
    private String name;
    public PhoneProxyHandler (Object object, String name) {
        this.object = object;
        this.name = name;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("Before invoke " + method.getName());
        System.out.println(name + "手机售前");
        method.invoke(object, args);
        System.out.println(name + "手机售后");
        System.out.println("After invoke " + method.getName());
        return null;
    }
}

动态代理调用

package com.test.selfcoding.proxy.staticproxy;

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

/**
 * @ClassNAME DynamicProxyTest
 * @Description TODO
 * @Author Andya
 * @Version 1.0
 */
public class DynamicProxyTest {

    public static void main(String[] args) {
        //动态代理华为
        Phone huaweiPhone = new HuaweiPhone();
        InvocationHandler huaweiHandler = new PhoneProxyHandler(huaweiPhone,"华为");
        //创建华为手机的动态代理类
        Phone huaweiProxy = (Phone) Proxy.newProxyInstance(huaweiPhone.getClass().getClassLoader(), huaweiPhone.getClass().getInterfaces(), huaweiHandler);
        huaweiProxy.sellPhone();

        //动态代理小米
        Phone xiaomiPhone = new XiaoMiPhone();
        InvocationHandler xiaomiHandler = new PhoneProxyHandler(xiaomiPhone,"小米");
        //创建小米手机的动态代理类
        Phone xiaomiProxy = (Phone) Proxy.newProxyInstance(huaweiPhone.getClass().getClassLoader(), huaweiPhone.getClass().getInterfaces(), xiaomiHandler);
        xiaomiProxy.sellPhone();
        
    }
}

动态代理调用结果

Before invoke sellPhone
华为手机售前
sell huawei phone!
华为手机售后
After invoke sellPhone
Before invoke sellPhone
小米手机售前
sell xiaomi phone
小米手机售后
After invoke sellPhone

通过Proxy类的静态方法newProxyInstance返回一个接口的代理实例,针对不同的被代理类进行控制。

动态代理newProxyInstance()方法的源码

 @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
    	//判空
        Objects.requireNonNull(h);
		
		//获取入参一组接口
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        //此处即为代理类对象的生成
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

			//通过constructorParams获取代理类的构造函数
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            //若私有,通过设置setAccessible打破封装
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //创建代理实例
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

动态代理getProxyClass0()源码


    /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }
posted @ 2022-06-18 18:10  Andya_net  阅读(40)  评论(0编辑  收藏  举报  来源