java魔法类之ReflectionFactory介绍

前言

在看objenesis(一个提供多种实例化对象的方式的库)的源码时,发现其中使用到了ReflectionFactory类,它会绕过构造器来实例化对象,且会跳过类成员变量的初始化。

简单使用

使用反射实例化对象

import java.lang.reflect.Constructor;

public class TestReflection {
    public static void main(String[] args) throws Exception {
        Constructor<User> declaredConstructor = User.class.getDeclaredConstructor();
        System.out.println(declaredConstructor.newInstance());
    }
    public static class User {
        private String name = "lisi";
        public User() {
            System.out.println("User created");
        }
        @Override
        public String toString() {
            return "user=" + name;
        }
    }
}

输出结果为

User created
user=lisi

使用ReflectionFactory实例化对象(java8)

import sun.reflect.ReflectionFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class TestReflectionFactory {
    public static void main(String[] args)
            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取ReflectionFactory对象,它本身是单例的
        ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
        //获取Object类的构造器
        Constructor<Object> constructor = Object.class.getDeclaredConstructor();
        //根据Object构造器创建一个User类的构造器
        Constructor<?> constructorForSerialization = reflectionFactory
                .newConstructorForSerialization(User.class, constructor);
        constructorForSerialization.setAccessible(true);
        //实例化对象
        System.out.println(constructorForSerialization.newInstance());
    }

    public static class User {
        private String name = "lisi";
        public User() {
            System.out.println("User created");
        }
        @Override
        public String toString() {
            return "user=" + name;
        }
    }
}

输出结果为

user=null

可以看到正常实例化了对象,但没有执行构造器且name成员变量没有被初始化。

使用ReflectionFactory实例化对象(java11)

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

public class TestReflectionFactory {
    public static void main(String[] args) throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, ClassNotFoundException {
        Constructor<?> constructor = newConstructorForSerialization(User.class, getJavaLangObjectConstructor());
        System.out.println(constructor.newInstance());
    }

    public static class User {
        private String name = "lisi";
        public User() {
            System.out.println("User created");
        }
        @Override
        public String toString() {
            return "user=" + name;
        }
    }

    public static <T> Constructor<T> newConstructorForSerialization(Class<T> type, Constructor<?> constructor) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        Class<?> reflectionFactoryClass = getReflectionFactoryClass();
        Object reflectionFactory = createReflectionFactory(reflectionFactoryClass);
        Method newConstructorForSerializationMethod = getNewConstructorForSerializationMethod(reflectionFactoryClass);
        return (Constructor) newConstructorForSerializationMethod.invoke(reflectionFactory, type, constructor);
    }
    private static Class<?> getReflectionFactoryClass() throws ClassNotFoundException {
        return Class.forName("sun.reflect.ReflectionFactory");
    }
    private static Object createReflectionFactory(Class<?> reflectionFactoryClass) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method method = reflectionFactoryClass.getDeclaredMethod("getReflectionFactory");
        return method.invoke((Object) null);
    }
    private static Method getNewConstructorForSerializationMethod(Class<?> reflectionFactoryClass) throws NoSuchMethodException {
        return reflectionFactoryClass.getDeclaredMethod("newConstructorForSerialization", Class.class, Constructor.class);
    }
    private static Constructor<Object> getJavaLangObjectConstructor() throws NoSuchMethodException {
        return Object.class.getConstructor((Class[]) null);
    }
}

输出结果为

user=null

通过反射来获取ReflectionFactory类(参考Spring源码SunReflectionFactoryInstantiator类)。

实现原理

内部使用字节码创建ConstructorAccessor接口的实现类

public final Constructor<?> newConstructorForSerialization(Class<?> cl,
                                                               Constructor<?> constructorToCall)
    {
        if (constructorToCall.getDeclaringClass() == cl) {
            constructorToCall.setAccessible(true);
            return constructorToCall;
        }
        return generateConstructor(cl, constructorToCall);
    }

// 创建构造器
private final Constructor<?> generateConstructor(Class<?> cl,
                                                     Constructor<?> constructorToCall) {

	//核心逻辑,通过字节码生成ConstructorAccessor,实现类类型为SerializationConstructorAccessorImpl 
        ConstructorAccessor acc = new MethodAccessorGenerator().
            generateSerializationConstructor(cl,
                                             constructorToCall.getParameterTypes(),
                                             constructorToCall.getExceptionTypes(),
                                             constructorToCall.getModifiers(),
                                             constructorToCall.getDeclaringClass());
        Constructor<?> c = newConstructor(constructorToCall.getDeclaringClass(),
                                          constructorToCall.getParameterTypes(),
                                          constructorToCall.getExceptionTypes(),
                                          constructorToCall.getModifiers(),
                                          langReflectAccess().
                                          getConstructorSlot(constructorToCall),
                                          langReflectAccess().
                                          getConstructorSignature(constructorToCall),
                                          langReflectAccess().
                                          getConstructorAnnotations(constructorToCall),
                                          langReflectAccess().
                                          getConstructorParameterAnnotations(constructorToCall));
        setConstructorAccessor(c, acc);
        c.setAccessible(true);
        return c;
    }

生成字节码的核心为MethodAccessorGenerator的generateSerializationConstructor()方法。

参考

objenesis官网
reflectionFactory.newConstructorForSerialization原理

posted @ 2021-10-29 18:52  strongmore  阅读(1023)  评论(0编辑  收藏  举报