深入学习java源码之Method.invoke()与 Method.getDefaultValue()
invoke方法用来在运行时动态地调用某个实例的方法。它的实现如下:
@CallerSensitive
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
我们根据invoke方法的实现,将其分为以下几步:
权限检查
invoke方法会首先检查AccessibleObject的override属性的值。AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。 override的值默认是false,表示需要权限调用规则,调用方法时需要检查权限;我们也可以用setAccessible方法设置为true,若override的值为true,表示忽略权限规则,调用方法时无需检查权限(也就是说可以调用任意的private方法,违反了封装)。 如果override属性为默认值false,则进行进一步的权限检查: (1)首先用Reflection.quickCheckMemberAccess(clazz, modifiers)方法检查方法是否为public,如果是的话跳出本步;如果不是public方法,那么用Reflection.getCallerClass()方法获取调用这个方法的Class对象,这是一个native方法:
@CallerSensitive
public static native Class getCallerClass();
在OpenJDK的源码中找到此方法的JNI入口(Reflection.c):
JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass__
(JNIEnv *env, jclass unused)
{
return JVM_GetCallerClass(env, JVM_CALLER_DEPTH);
}
获取了这个Class对象caller后用checkAccess方法做一次快速的权限校验,其实现为:
volatile Object securityCheckCache;
void checkAccess(Class caller, Class clazz, Object obj, int modifiers)
throws IllegalAccessException
{
if (caller == clazz) { // 快速校验
return; // 权限通过校验
}
Object cache = securityCheckCache; // read volatile
Class targetClass = clazz;
if (obj != null
&& Modifier.isProtected(modifiers)
&& ((targetClass = obj.getClass()) != clazz)) {
// Must match a 2-list of { caller, targetClass }.
if (cache instanceof Class[]) {
Class[] cache2 = (Class[]) cache;
if (cache2[1] == targetClass &&
cache2[0] == caller) {
return; // ACCESS IS OK
}
// (Test cache[1] first since range check for [1]
// subsumes range check for [0].)
}
} else if (cache == caller) {
// Non-protected case (or obj.class == this.clazz).
return; // ACCESS IS OK
}
// If no return, fall through to the slow path.
slowCheckMemberAccess(caller, clazz, obj, modifiers, targetClass);
}
首先先执行一次快速校验,一旦调用方法的Class正确则权限检查通过。 若未通过,则创建一个缓存,中间再进行一堆检查(比如检验是否为protected属性)。 如果上面的所有权限检查都未通过,那么将执行更详细的检查,其实现为:
// Keep all this slow stuff out of line:
void slowCheckMemberAccess(Class caller, Class clazz, Object obj, int modifiers,
Class targetClass)
throws IllegalAccessException
{
Reflection.ensureMemberAccess(caller, clazz, obj, modifiers);
// Success: Update the cache.
Object cache = ((targetClass == clazz)
? caller
: new Class[] { caller, targetClass });
// Note: The two cache elements are not volatile,
// but they are effectively final. The Java memory model
// guarantees that the initializing stores for the cache
// elements will occur before the volatile write.
securityCheckCache = cache; // write volatile
}
大体意思就是,用Reflection.ensureMemberAccess方法继续检查权限,若检查通过就更新缓存,这样下一次同一个类调用同一个方法时就不用执行权限检查了,这是一种简单的缓存机制。由于JMM的happens-before规则能够保证缓存初始化能够在写缓存之前发生,因此两个cache不需要声明为volatile。 到这里,前期的权限检查工作就结束了。如果没有通过检查则会抛出异常,如果通过了检查则会到下一步。
调用MethodAccessor的invoke方法
Method.invoke()实际上并不是自己实现的反射调用逻辑,而是委托给sun.reflect.MethodAccessor来处理。 首先要了解Method对象的基本构成,每个Java方法有且只有一个Method对象作为root,它相当于根对象,对用户不可见。当我们创建Method对象时,我们代码中获得的Method对象都相当于它的副本(或引用)。root对象持有一个MethodAccessor对象,所以所有获取到的Method对象都共享这一个MethodAccessor对象,因此必须保证它在内存中的可见性。root对象其声明及注释为:
private volatile MethodAccessor methodAccessor;
private Method root;
可以看到MethodAccessor是一个接口,定义了invoke方法。分析其Usage可得它的具体实现类有:
- sun.reflect.DelegatingMethodAccessorImpl
- sun.reflect.MethodAccessorImpl
- sun.reflect.NativeMethodAccessorImpl
第一次调用一个Java方法对应的Method对象的invoke()方法之前,实现调用逻辑的MethodAccessor对象还没有创建;等第一次调用时才新创建MethodAccessor并更新给root,然后调用MethodAccessor.invoke()完成反射调用:
private MethodAccessor acquireMethodAccessor() {
// First check to see if one has been created yet, and take it
// if so
MethodAccessor tmp = null;
if (root != null) tmp = root.getMethodAccessor();
if (tmp != null) {
methodAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newMethodAccessor(this);
setMethodAccessor(tmp);
}
return tmp;
}
可以看到methodAccessor实例由reflectionFactory对象操控生成,它在AccessibleObject下的声明如下:
static final ReflectionFactory reflectionFactory =
AccessController.doPrivileged(
new sun.reflect.ReflectionFactory.GetReflectionFactoryAction());
观察前面的声明部分的注释,我们可以发现一些有趣的东西。就像注释里说的,实际的MethodAccessor实现有两个版本,一个是Java版本,一个是native版本,两者各有特点。初次启动时Method.invoke()和Constructor.newInstance()方法采用native方法要比Java方法快3-4倍,而启动后native方法又要消耗额外的性能而慢于Java方法。也就是说,Java实现的版本在初始化时需要较多时间,但长久来说性能较好;native版本正好相反,启动时相对较快,但运行时间长了之后速度就比不过Java版了。这是HotSpot的优化方式带来的性能特性,同时也是许多虚拟机的共同点:跨越native边界会对优化有阻碍作用,它就像个黑箱一样让虚拟机难以分析也将其内联,于是运行时间长了之后反而是托管版本的代码更快些。
为了尽可能地减少性能损耗,HotSpot JDK采用“inflation”的技巧:让Java方法在被反射调用时,开头若干次使用native版,等反射调用次数超过阈值时则生成一个专用的MethodAccessor实现类,生成其中的invoke()方法的字节码,以后对该Java方法的反射调用就会使用Java版本。 这项优化是从JDK 1.4开始的。
研究ReflectionFactory.newMethodAccessor()生产MethodAccessor对象的逻辑,一开始(native版)会生产NativeMethodAccessorImpl和DelegatingMethodAccessorImpl两个对象。
DelegatingMethodAccessorImpl的源码如下:
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
private MethodAccessorImpl delegate;
DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) {
setDelegate(delegate);
}
public Object invoke(Object obj, Object[] args)
throws IllegalArgumentException, InvocationTargetException
{
return delegate.invoke(obj, args);
}
void setDelegate(MethodAccessorImpl delegate) {
this.delegate = delegate;
}
}
它其实是一个中间层,方便在native版与Java版的MethodAccessor之间进行切换。
每次NativeMethodAccessorImpl.invoke()方法被调用时,程序调用计数器都会增加1,看看是否超过阈值;一旦超过,则调用MethodAccessorGenerator.generateMethod()来生成Java版的MethodAccessor的实现类,并且改变DelegatingMethodAccessorImpl所引用的MethodAccessor为Java版。后续经由DelegatingMethodAccessorImpl.invoke()调用到的就是Java版的实现了。 到这里,我们已经追寻到native版的invoke方法在Java一侧声明的最底层 - invoke0了,下面我们将深入到HotSpot JVM中去研究其具体实现。
MagicAccessorImpl
原本Java的安全机制使得不同类之间不是任意信息都可见,但JDK里面专门设了个MagicAccessorImpl标记类开了个后门来允许不同类之间信息可以互相访问(由JVM管理):
@CallerSensitive注解又是什么鬼?
JDK 1.8才引进了这个注解,因此在老版本的反射实现里并没有这个玩意。这是它的定义:
@Retention(RetentionPolicy.RUNTIME)
@Target({METHOD})
public @interface CallerSensitive {
}
简而言之,用@CallerSensitive
注解修饰的方法从一开始就知道具体调用它的对象,这样就不用再经过一系列的检查才能确定具体调用它的对象了。它实际上是调用sun.reflect.Reflection.getCallerClass
方法。
Reflection类位于调用栈中的0帧位置,sun.reflect.Reflection.getCallerClass()
方法返回调用栈中从0帧开始的第x帧中的类实例。该方法提供的机制可用于确定调用者类,从而实现“感知调用者(Caller Sensitive)”的行为,即允许应用程序根据调用类或调用栈中的其它类来改变其自身的行为。
java源码
Modifier and TypeMethod and Descriptionboolean
equals(Object obj)
将此 方法
与指定对象进行比较。
AnnotatedType
getAnnotatedReturnType()
返回一个 AnnotatedType
对象,表示使用类型来指定此可执行文件所表示的方法/构造函数的返回类型。
T
getAnnotation(类 annotationClass)
返回该元素的,如果这样的注释 ,否则返回null指定类型的注释。
Annotation[]
getDeclaredAnnotations()
返回 直接存在于此元素上的注释。
类
getDeclaringClass()
返回 类
表示声明该对象表示的可执行的类或接口对象。
Object
getDefaultValue()
返回由此 方法
实例表示的注释成员的默认值。
类[]
getExceptionTypes()
返回一个 类
对象的数组,表示由该对象表示的底层可执行文件所声明的异常类型。
Type[]
getGenericExceptionTypes()
返回一个 Type
对象的数组, Type
此可执行对象声明抛出的异常。
Type[]
getGenericParameterTypes()
返回一个 Type
对象的数组, Type
以声明顺序表示由该对象表示的可执行文件的形式参数类型。
Type
getGenericReturnType()
返回一个 Type
对象,它表示由该表示的方法的正式返回类型 方法
对象。
int
getModifiers()
返回由该对象表示的可执行文件的Java语言modifiers 。
String
getName()
返回由此 方法
对象表示的方法的名称,作为 String
。
Annotation[][]
getParameterAnnotations()
返回一个 Annotation
s的数组数组,表示由该对象表示的Executable的形式参数的声明顺序的 Executable
。
int
getParameterCount()
返回由此对象表示的可执行文件的形式参数(无论是显式声明还是隐式声明)的数量。
类[]
getParameterTypes()
返回一个 类
对象的数组, 类
以声明顺序表示由该对象表示的可执行文件的形式参数类型。
类
getReturnType()
返回一个 类
对象,它表示由该表示的方法的正式返回类型 方法
对象。
TypeVariable[]
getTypeParameters()
返回一个 TypeVariable
对象的数组,它们以声明顺序表示由此 GenericDeclaration
对象表示的通用声明声明的类型变量。
int
hashCode()
返回这个 方法
的哈希码。
Object
invoke(Object obj, Object... args)
在具有指定参数的 方法
对象上调用此 方法
对象表示的底层方法。
boolean
isBridge()
返回true
如果这个方法是一个桥接方法; 返回false
否则。
boolean
isDefault()
如果此方法是默认方法,则返回true
; 返回false
其他。
boolean
isSynthetic()
返回true
如果这个可执行文件是一个合成的构建体; 返回false
其他。
boolean
isVarArgs()
返回true
如果这个可执行文件被宣布为带有可变数量的参数; 返回false
其他。
String
toGenericString()
返回描述此 方法
的字符串,包括类型参数。
String
toString()
返回一个描述这个 方法
的字符串。
package java.lang.reflect;
import sun.reflect.CallerSensitive;
import sun.reflect.MethodAccessor;
import sun.reflect.Reflection;
import sun.reflect.generics.repository.MethodRepository;
import sun.reflect.generics.factory.CoreReflectionFactory;
import sun.reflect.generics.factory.GenericsFactory;
import sun.reflect.generics.scope.MethodScope;
import sun.reflect.annotation.AnnotationType;
import sun.reflect.annotation.AnnotationParser;
import java.lang.annotation.Annotation;
import java.lang.annotation.AnnotationFormatError;
import java.nio.ByteBuffer;
public final class Method extends Executable {
private Class clazz;
private int slot;
// This is guaranteed to be interned by the VM in the 1.4
// reflection implementation
private String name;
private Class returnType;
private Class[] parameterTypes;
private Class[] exceptionTypes;
private int modifiers;
// Generics and annotations support
private transient String signature;
// generic info repository; lazily initialized
private transient MethodRepository genericInfo;
private byte[] annotations;
private byte[] parameterAnnotations;
private byte[] annotationDefault;
private volatile MethodAccessor methodAccessor;
// For sharing of MethodAccessors. This branching structure is
// currently only two levels deep (i.e., one root Method and
// potentially many Method objects pointing to it.)
//
// If this branching structure would ever contain cycles, deadlocks can
// occur in annotation code.
private Method root;
// Generics infrastructure
private String getGenericSignature() {return signature;}
// Accessor for factory
private GenericsFactory getFactory() {
// create scope and factory
return CoreReflectionFactory.make(this, MethodScope.make(this));
}
// Accessor for generic info repository
@Override
MethodRepository getGenericInfo() {
// lazily initialize repository if necessary
if (genericInfo == null) {
// create and cache generic info repository
genericInfo = MethodRepository.make(getGenericSignature(),
getFactory());
}
return genericInfo; //return cached repository
}
Method(Class declaringClass,
String name,
Class[] parameterTypes,
Class returnType,
Class[] checkedExceptions,
int modifiers,
int slot,
String signature,
byte[] annotations,
byte[] parameterAnnotations,
byte[] annotationDefault) {
this.clazz = declaringClass;
this.name = name;
this.parameterTypes = parameterTypes;
this.returnType = returnType;
this.exceptionTypes = checkedExceptions;
this.modifiers = modifiers;
this.slot = slot;
this.signature = signature;
this.annotations = annotations;
this.parameterAnnotations = parameterAnnotations;
this.annotationDefault = annotationDefault;
}
Method copy() {
if (this.root != null)
throw new IllegalArgumentException("Can not copy a non-root Method");
Method res = new Method(clazz, name, parameterTypes, returnType,
exceptionTypes, modifiers, slot, signature,
annotations, parameterAnnotations, annotationDefault);
res.root = this;
// Might as well eagerly propagate this if already present
res.methodAccessor = methodAccessor;
return res;
}
@Override
Executable getRoot() {
return root;
}
@Override
boolean hasGenericInformation() {
return (getGenericSignature() != null);
}
@Override
byte[] getAnnotationBytes() {
return annotations;
}
@Override
public Class getDeclaringClass() {
return clazz;
}
@Override
public String getName() {
return name;
}
@Override
public int getModifiers() {
return modifiers;
}
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public TypeVariable[] getTypeParameters() {
if (getGenericSignature() != null)
return (TypeVariable[])getGenericInfo().getTypeParameters();
else
return (TypeVariable[])new TypeVariable[0];
}
public Class getReturnType() {
return returnType;
}
public Type getGenericReturnType() {
if (getGenericSignature() != null) {
return getGenericInfo().getReturnType();
} else { return getReturnType();}
}
@Override
public Class[] getParameterTypes() {
return parameterTypes.clone();
}
public int getParameterCount() { return parameterTypes.length; }
@Override
public Type[] getGenericParameterTypes() {
return super.getGenericParameterTypes();
}
@Override
public Class[] getExceptionTypes() {
return exceptionTypes.clone();
}
@Override
public Type[] getGenericExceptionTypes() {
return super.getGenericExceptionTypes();
}
public boolean equals(Object obj) {
if (obj != null && obj instanceof Method) {
Method other = (Method)obj;
if ((getDeclaringClass() == other.getDeclaringClass())
&& (getName() == other.getName())) {
if (!returnType.equals(other.getReturnType()))
return false;
return equalParamTypes(parameterTypes, other.parameterTypes);
}
}
return false;
}
public int hashCode() {
return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
}
public String toString() {
return sharedToString(Modifier.methodModifiers(),
isDefault(),
parameterTypes,
exceptionTypes);
}
@Override
void specificToStringHeader(StringBuilder sb) {
sb.append(getReturnType().getTypeName()).append(' ');
sb.append(getDeclaringClass().getTypeName()).append('.');
sb.append(getName());
}
@Override
public String toGenericString() {
return sharedToGenericString(Modifier.methodModifiers(), isDefault());
}
@Override
void specificToGenericStringHeader(StringBuilder sb) {
Type genRetType = getGenericReturnType();
sb.append(genRetType.getTypeName()).append(' ');
sb.append(getDeclaringClass().getTypeName()).append('.');
sb.append(getName());
}
@CallerSensitive
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
public boolean isBridge() {
return (getModifiers() & Modifier.BRIDGE) != 0;
}
@Override
public boolean isVarArgs() {
return super.isVarArgs();
}
@Override
public boolean isSynthetic() {
return super.isSynthetic();
}
public boolean isDefault() {
// Default methods are public non-abstract instance methods
// declared in an interface.
return ((getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) ==
Modifier.PUBLIC) && getDeclaringClass().isInterface();
}
private MethodAccessor acquireMethodAccessor() {
// First check to see if one has been created yet, and take it
// if so
MethodAccessor tmp = null;
if (root != null) tmp = root.getMethodAccessor();
if (tmp != null) {
methodAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newMethodAccessor(this);
setMethodAccessor(tmp);
}
return tmp;
}
// Returns MethodAccessor for this Method object, not looking up
// the chain to the root
MethodAccessor getMethodAccessor() {
return methodAccessor;
}
// Sets the MethodAccessor for this Method object and
// (recursively) its root
void setMethodAccessor(MethodAccessor accessor) {
methodAccessor = accessor;
// Propagate up
if (root != null) {
root.setMethodAccessor(accessor);
}
}
public Object getDefaultValue() {
if (annotationDefault == null)
return null;
Class memberType = AnnotationType.invocationHandlerReturnType(
getReturnType());
Object result = AnnotationParser.parseMemberValue(
memberType, ByteBuffer.wrap(annotationDefault),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
getDeclaringClass());
if (result instanceof sun.reflect.annotation.ExceptionProxy)
throw new AnnotationFormatError("Invalid default: " + this);
return result;
}
public T getAnnotation(Class annotationClass) {
return super.getAnnotation(annotationClass);
}
public Annotation[] getDeclaredAnnotations() {
return super.getDeclaredAnnotations();
}
@Override
public Annotation[][] getParameterAnnotations() {
return sharedGetParameterAnnotations(parameterTypes, parameterAnnotations);
}
@Override
public AnnotatedType getAnnotatedReturnType() {
return getAnnotatedReturnType0(getGenericReturnType());
}
@Override
void handleParameterNumberMismatch(int resultLength, int numParameters) {
throw new AnnotationFormatError("Parameter annotations don't match number of parameters");
}
}