>Java >Java베이스 >JVM 반영 원리 기술 포인트에 대한 매우 상세한 요약~

JVM 반영 원리 기술 포인트에 대한 매우 상세한 요약~

coldplay.xixi
coldplay.xixi앞으로
2020-10-10 17:20:142347검색

오늘

Java Basics 칼럼에서는 JVM 반영 원리 기술 사항에 대한 매우 자세한 요약을 소개합니다.

JVM 반영 원리 기술 포인트에 대한 매우 상세한 요약~

반사 정의

1. JAVA 반사 메커니즘은 실행 상태

모든 클래스에 대해 이 클래스의 모든 속성과 메서드를 알 수 있습니다.

모든 개체에 대해 호출할 수 있습니다.

이러한 정보의 동적 획득과 객체 메서드를 동적으로 호출하는 기능을 Java 언어의 반사 메커니즘이라고 합니다.

리플렉션에서 제공하는 함수:

  • 런타임에 객체가 속한 클래스를 결정합니다.
  • 런타임에 모든 클래스의 객체를 구성합니다.
  • 런타임에 클래스의 멤버 변수와 메서드를 결정합니다.

(속성이 비공개인 경우 외부 세계는 일반적인 상황에서 속성 값을 조작하는 것이 허용되지 않습니다. 여기서 Field 클래스의 setAccessible(true) 메서드를 사용하여 일시적으로 속성을 열 수 있습니다. 연산 권한)

리플렉션의 사용 시나리오

  • Java로 코딩할 때 클래스와 객체의 구체적인 정보를 알고 있으면 이때 리플렉션 없이 클래스와 객체에 직접 연산을 할 수 있습니다
  • 모르는 경우. 코딩 시 클래스 또는 객체의 특정 정보를 보려면 Reflection을 사용하여

Reflection 소스 코드 분석

예제 API:

Class.forName("com.my.reflectTest").newInstance()复制代码

1 Reflection을 사용하여 클래스 인스턴스 Class.forName("xxx");

을 얻으세요. 먼저, 클래스 정보를 얻기 위해 java.lang.Class의 정적 메소드를 호출합니다!

참고: 클래스 정보를 얻기 위한 forName() 반사는 구현을 Java에 맡기지 않고 로드를 위해 jvm에 맡깁니다! L 주로 ClassLoader를 먼저 가져온 다음 Native 메서드를 호출하여 정보를 얻습니다. 로딩 클래스는 ClassLoader를 클래스로 복구하여 로드하는 것입니다.

 @CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        // 先通过反射,获取调用进来的类信息,从而获取当前的 classLoader
        Class<?> caller = Reflection.getCallerClass();
        // 调用native方法进行获取class信息
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }复制代码

2.java.lang.ClassLoader----loadClass()

// java.lang.ClassLoader
    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        // 先获取锁
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            // 如果已经加载了的话,就不用再加载了
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // 双亲委托加载
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
 
                // 父类没有加载到时,再自己加载
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);
 
                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
    
    protected Object getClassLoadingLock(String className) {
        Object lock = this;
        if (parallelLockMap != null) {
            // 使用 ConcurrentHashMap来保存锁
            Object newLock = new Object();
            lock = parallelLockMap.putIfAbsent(className, newLock);
            if (lock == null) {
                lock = newLock;
            }
        }
        return lock;
    }
    
    protected final Class<?> findLoadedClass(String name) {
        if (!checkName(name))
            return null;
        return findLoadedClass0(name);
    }复制代码

3.newInstance()

newInstance() 其实相当于调用类的无参构造函数,主要做了三件事复制代码

    권한 감지, 통과하지 못하면 직접 예외가 발생합니다.
  • 인수 없는 생성자를 찾아 캐시합니다.

  • 특정 메서드의 인수 없는 생성자를 호출하고 인스턴스를 생성한 후 반환합니다.

  • // 首先肯定是 Class.newInstance
        @CallerSensitive
        public T newInstance()
            throws InstantiationException, IllegalAccessException
        {
            if (System.getSecurityManager() != null) {
                checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
            }
     
            // NOTE: the following code may not be strictly correct under
            // the current Java memory model.
     
            // Constructor lookup
            // newInstance() 其实相当于调用类的无参构造函数,所以,首先要找到其无参构造器
            if (cachedConstructor == null) {
                if (this == Class.class) {
                    // 不允许调用 Class 的 newInstance() 方法
                    throw new IllegalAccessException(
                        "Can not call newInstance() on the Class for java.lang.Class"
                    );
                }
                try {
                    // 获取无参构造器
                    Class<?>[] empty = {};
                    final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
                    // Disable accessibility checks on the constructor
                    // since we have to do the security check here anyway
                    // (the stack depth is wrong for the Constructor&#39;s
                    // security check to work)
                    java.security.AccessController.doPrivileged(
                        new java.security.PrivilegedAction<Void>() {
                            public Void run() {
                                    c.setAccessible(true);
                                    return null;
                                }
                            });
                    cachedConstructor = c;
                } catch (NoSuchMethodException e) {
                    throw (InstantiationException)
                        new InstantiationException(getName()).initCause(e);
                }
            }
            Constructor<T> tmpConstructor = cachedConstructor;
            // Security check (same as in java.lang.reflect.Constructor)
            int modifiers = tmpConstructor.getModifiers();
            if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                if (newInstanceCallerCache != caller) {
                    Reflection.ensureMemberAccess(caller, this, null, modifiers);
                    newInstanceCallerCache = caller;
                }
            }
            // Run constructor
            try {
                // 调用无参构造器
                return tmpConstructor.newInstance((Object[])null);
            } catch (InvocationTargetException e) {
                Unsafe.getUnsafe().throwException(e.getTargetException());
                // Not reached
                return null;
            }
        }复制代码
  • 4는 일치하는 생성자를 가져옵니다. ; 세 단계로 나뉩니다:

    1. 먼저 모든 생성자를 얻은 다음 매개변수 유형을 비교합니다. 2. 일치하는 항목을 찾은 후 ReflectionFactory를 통해 생성자의 복사본을 복사하고 반환합니다. 3. 그렇지 않으면 NoSuchMethodException;
  • private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
                                            int which) throws NoSuchMethodException
        {
            // 获取所有构造器
            Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
            for (Constructor<T> constructor : constructors) {
                if (arrayContentsEq(parameterTypes,
                                    constructor.getParameterTypes())) {
                    return getReflectionFactory().copyConstructor(constructor);
                }
            }
            throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
        }复制代码
5.privateGetDeclaredConstructors()를 발생시키고 생성자의 모든 주요 단계를 가져옵니다.

 1. 먼저 캐시에서 가져옵니다. 2. 캐시가 없으면 jvm에서 검색하여 캐시에 저장합니다. 캐시는 메모리를 사용할 수 있는지 확인하기 위해 소프트 참조를 사용합니다. 또한 캐시 저장을 위해 relactionData()를 사용합니다. ; ReflectionData의 데이터 구조는 다음과 같습니다!

// 获取当前类所有的构造方法,通过jvm或者缓存
    // Returns an array of "root" constructors. These Constructor
    // objects must NOT be propagated to the outside world, but must
    // instead be copied via ReflectionFactory.copyConstructor.
    private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) {
        checkInitted();
        Constructor<T>[] res;
        // 调用 reflectionData(), 获取保存的信息,使用软引用保存,从而使内存不够可以回收
        ReflectionData<T> rd = reflectionData();
        if (rd != null) {
            res = publicOnly ? rd.publicConstructors : rd.declaredConstructors;
            // 存在缓存,则直接返回
            if (res != null) return res;
        }
        // No cached value available; request value from VM
        if (isInterface()) {
            @SuppressWarnings("unchecked")
            Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0];
            res = temporaryRes;
        } else {
            // 使用native方法从jvm获取构造器
            res = getDeclaredConstructors0(publicOnly);
        }
        if (rd != null) {
            // 最后,将从jvm中读取的内容,存入缓存
            if (publicOnly) {
                rd.publicConstructors = res;
            } else {
                rd.declaredConstructors = res;
            }
        }
        return res;
    }
    
    // Lazily create and cache ReflectionData
    private ReflectionData<T> reflectionData() {
        SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;
        int classRedefinedCount = this.classRedefinedCount;
        ReflectionData<T> rd;
        if (useCaches &&
            reflectionData != null &&
            (rd = reflectionData.get()) != null &&
            rd.redefinedCount == classRedefinedCount) {
            return rd;
        }
        // else no SoftReference or cleared SoftReference or stale ReflectionData
        // -> create and replace new instance
        return newReflectionData(reflectionData, classRedefinedCount);
    }
    
    // 新创建缓存,保存反射信息
    private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData,
                                                int classRedefinedCount) {
        if (!useCaches) return null;
 
        // 使用cas保证更新的线程安全性,所以反射是保证线程安全的
        while (true) {
            ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount);
            // try to CAS it...
            if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) {
                return rd;
            }
            // 先使用CAS更新,如果更新成功,则立即返回,否则测查当前已被其他线程更新的情况,如果和自己想要更新的状态一致,则也算是成功了
            oldReflectionData = this.reflectionData;
            classRedefinedCount = this.classRedefinedCount;
            if (oldReflectionData != null &&
                (rd = oldReflectionData.get()) != null &&
                rd.redefinedCount == classRedefinedCount) {
                return rd;
            }
        }
    }复制代码

6. 위와 같은 과정을 통해 생성자를 획득하게 되었습니다! 다음으로, 인스턴스를 반환하려면 해당 생성자의 newInstance()를 호출하기만 하면 됩니다!

// reflection data that might get invalidated when JVM TI RedefineClasses() is called
    private static class ReflectionData<T> {
        volatile Field[] declaredFields;
        volatile Field[] publicFields;
        volatile Method[] declaredMethods;
        volatile Method[] publicMethods;
        volatile Constructor<T>[] declaredConstructors;
        volatile Constructor<T>[] publicConstructors;
        // Intermediate results for getFields and getMethods
        volatile Field[] declaredPublicFields;
        volatile Method[] declaredPublicMethods;
        volatile Class<?>[] interfaces;
 
        // Value of classRedefinedCount when we created this ReflectionData instance
        final int redefinedCount;
 
        ReflectionData(int redefinedCount) {
            this.redefinedCount = redefinedCount;
        }
    }复制代码

생성자의 인스턴스를 반환한 후 외부 환경에 따라 유형 변환을 수행한 다음 인터페이스나 메서드를 사용하여 인스턴스 함수를 호출할 수 있습니다.

관련 무료 학습 권장사항:

java basics

위 내용은 JVM 반영 원리 기술 포인트에 대한 매우 상세한 요약~의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.im에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제