AspectJ 中类型的绑定
我们知道,在 AspectJ 中配置切点表达时,需配置全限定性类名,但对于 java.lang.String 可以简化为 String,直接配置,这是怎么实现的呢?这就涉及到了 AspectJ 中的类型绑定机制。
示例一
"execution(* *..UserServiceImpl.doSome(String...,int))"
我们知道,在 Java 的语法中,可变参数只能放在形参的最后,并且每个方法只能有一个可变参数,但是在 AspectJ 的切入点表达式解析规则中,上面的配置是可以解析的。
参数解析
在 org.aspectj.weaver.patterns.PatternParser#parseMethodOrConstructorSignaturePattern 方法中,会执行 parseArgumentsPattern,解析得到参数的匹配模式。
// 解析参数类型时,以 "," 作为类型分割,每个类型单独解析
public TypePatternList parseArgumentsPattern(boolean parameterAnnotationsPossible) {
List<TypePattern> patterns = new ArrayList<>();
eat("(");
// ()
if (maybeEat(")")) {
return new TypePatternList();
}
do {
if (maybeEat(".")) { // ..
eat(".");
patterns.add(TypePattern.ELLIPSIS);
} else {
patterns.add(parseTypePattern(false, parameterAnnotationsPossible));
}
} while (maybeEat(","));
eat(")");
return new TypePatternList(patterns);
}
解析参数类型时,以 "," 作为类型分割,每个类型单独解析。(String...,int) 被解析成了两个 TypePattern,"String..." 和 "int",最后封装成 TypePatternList。
public TypePattern parseTypePattern(boolean insideTypeParameters, boolean parameterAnnotationsPossible) {
TypePattern p = parseAtomicTypePattern(insideTypeParameters, parameterAnnotationsPossible);
if (maybeEat("&&")) {
p = new AndTypePattern(p, parseNotOrTypePattern(insideTypeParameters, parameterAnnotationsPossible));
}
if (maybeEat("||")) {
p = new OrTypePattern(p, parseTypePattern(insideTypeParameters, parameterAnnotationsPossible));
}
return p;
}
可以看到,转换成了类型解析,执行 parseAtomicTypePattern --> parseSingleTypePattern。
// insideTypeParameters false
public TypePattern parseSingleTypePattern(boolean insideTypeParameters) {
if (insideTypeParameters && maybeEat("?")) {
return parseGenericsWildcardTypePattern();
}
if (allowHasTypePatterns) {
if (maybeEatIdentifier("hasmethod")) {
return parseHasMethodTypePattern();
}
if (maybeEatIdentifier("hasfield")) {
return parseHasFieldTypePattern();
}
}
if (maybeEatIdentifier("is")) {
int pos = tokenSource.getIndex() - 1;
TypePattern typeIsPattern = parseIsTypePattern();
if (typeIsPattern != null) {
return typeIsPattern;
}
// rewind as if we never tried to parse it as a typeIs
tokenSource.setIndex(pos);
}
// 按 "." 解析成 NamePattern 集合
List<NamePattern> names = parseDottedNamePattern();
int dim = 0;
while (maybeEat("[")) {
eat("]");
dim++;
}
TypePatternList typeParameters = maybeParseTypeParameterList();
int endPos = tokenSource.peek(-1).getEnd();
boolean includeSubtypes = maybeEat("+");
// TODO do we need to associate the + with either the type or the array?
while (maybeEat("[")) {
eat("]");
dim++;
}
boolean isVarArgs = maybeEat("...");
// ??? what about the source location of any's????
if (names.size() == 1 && names.get(0).isAny() && dim == 0 && !isVarArgs && typeParameters == null) {
return TypePattern.ANY;
}
// Notice we increase the dimensions if varargs is set. this is to allow type matching to
// succeed later: The actual signature at runtime of a method declared varargs is an array type of
// the original declared type (so Integer... becomes Integer[] in the bytecode). So, here for the
// pattern 'Integer...' we create a WildTypePattern 'Integer[]' with varargs set. If this matches
// during shadow matching, we confirm that the varargs flags match up before calling it a successful
// match.
return new WildTypePattern(names, includeSubtypes, dim + (isVarArgs ? 1 : 0), endPos, isVarArgs, typeParameters);
}
public List<NamePattern> parseDottedNamePattern() {
List<NamePattern> names = new ArrayList<>();
StringBuffer buf = new StringBuffer();
IToken previous = null;
boolean justProcessedEllipsis = false; // Remember if we just dealt with an ellipsis (PR61536)
boolean justProcessedDot = false;
boolean onADot = false;
while (true) {
IToken tok = null;
int startPos = tokenSource.peek().getStart();
String afterDot = null;
while (true) {
if (previous != null && previous.getString().equals(".")) {
justProcessedDot = true;
}
tok = tokenSource.peek();
onADot = (tok.getString().equals("."));
if (previous != null) {
if (!isAdjacent(previous, tok)) {
break;
}
}
// "..." 也是标识符,但 "<" 不是
if (tok.getString() == "*" || (tok.isIdentifier() && tok.getString() != "...")) {
buf.append(tok.getString());
} else if (tok.getString() == "...") {
break;
// literalKind 为 null,直接 break 退出内循环
} else if (tok.getLiteralKind() != null) {
// System.err.println("literal kind: " + tok.getString());
String s = tok.getString();
int dot = s.indexOf('.');
if (dot != -1) {
buf.append(s.substring(0, dot));
afterDot = s.substring(dot + 1);
previous = tokenSource.next();
break;
}
buf.append(s); // ??? so-so
} else {
break;
}
previous = tokenSource.next();
// XXX need to handle floats and other fun stuff
}
int endPos = tokenSource.peek(-1).getEnd();
if (buf.length() == 0 && names.isEmpty()) {
throw new ParserException("name pattern", tok);
}
if (buf.length() == 0 && justProcessedEllipsis) {
throw new ParserException("name pattern cannot finish with ..", tok);
}
if (buf.length() == 0 && justProcessedDot && !onADot) {
throw new ParserException("name pattern cannot finish with .", tok);
}
if (buf.length() == 0) {
names.add(NamePattern.ELLIPSIS);
justProcessedEllipsis = true;
} else {
checkLegalName(buf.toString(), previous);
NamePattern ret = new NamePattern(buf.toString());
ret.setLocation(sourceContext, startPos, endPos);
names.add(ret);
justProcessedEllipsis = false;
}
if (afterDot == null) {
buf.setLength(0);
// no elipsis or dotted name part
if (!maybeEat(".")) {
break;
// go on
} else {
previous = tokenSource.peek(-1);
}
} else {
buf.setLength(0);
buf.append(afterDot);
afterDot = null;
}
}
// System.err.println("parsed: " + names);
return names;
}
执行 parseDottedNamePattern,按 "." 解析成 NamePattern 集合,也就是将包名和类名按 "." 拆分成单独的部分。对于示例参数类型 "String...",由于未指定包名,解析后 NamePattern 集合 names 中只有一个元素,即 "String"。
接着,由于存在 "...",isVarArgs 为 true。
注意,在配置的切入点表达式中,".." 和 "..." 的含义是不同的。
".." | 按省略号对待,解析后 ellipsisCount 数量会增加,用在方法参数中,表示任意个参数且参数类型不限 |
"..." | 标识符,可变参数,实际解析时按指定类型的数组类型对待 |
处理完以上的解析点之后,将类型封装为 WildTypePattern。
WildTypePattern(NamePattern[] namePatterns, boolean includeSubtypes, int dim, boolean isVarArgs, TypePatternList typeParams) {
super(includeSubtypes, isVarArgs, typeParams);
this.namePatterns = namePatterns;
this.dim = dim;
ellipsisCount = 0;
for (NamePattern namePattern : namePatterns) {
if (namePattern == NamePattern.ELLIPSIS) {
ellipsisCount++;
}
}
setLocation(namePatterns[0].getSourceContext(), namePatterns[0].getStart(), namePatterns[namePatterns.length - 1].getEnd());
}
protected TypePattern(boolean includeSubtypes, boolean isVarArgs, TypePatternList typeParams) {
this.includeSubtypes = includeSubtypes;
this.isVarArgs = isVarArgs;
this.typeParameters = (typeParams == null ? TypePatternList.EMPTY : typeParams);
}
可以看到封装的 WildTypePattern 将 namePatterns 和 typeParameters 分开了,namePatterns 只包含类型定义。
类型绑定
解析完之后,得到 Pointcut,接着构建一个解析范围,也就是 @Aspect 切面类,切点表达式定义在切面类中。
// Pointcut
public final Pointcut resolve(IScope scope) {
assertState(SYMBOLIC);
// scope.getFormalCount() 获取的就是用户在切面方法上显式指定的参数数量
Bindings bindingTable = new Bindings(scope.getFormalCount());
IScope bindingResolutionScope = scope;
if (typeVariablesInScope.length > 0) {
bindingResolutionScope = new ScopeWithTypeVariables(typeVariablesInScope, scope);
}
this.resolveBindings(bindingResolutionScope, bindingTable);
bindingTable.checkAllBound(bindingResolutionScope);
this.state = RESOLVED;
return this;
}
执行 resolveBindings 就是进行类型的解析绑定。
在 KindedPointcut#resolveBindings 中,执行 signature.resolveBindings(scope, bindings)。
// SignaturePattern
@Override
public SignaturePattern resolveBindings(IScope scope, Bindings bindings) {
if (returnType != null) {
returnType = returnType.resolveBindings(scope, bindings, false, false);
checkForIncorrectTargetKind(returnType, scope, false);
}
if (declaringType != null) {
declaringType = declaringType.resolveBindings(scope, bindings, false, false);
checkForIncorrectTargetKind(declaringType, scope, false);
isExactDeclaringTypePattern = (declaringType instanceof ExactTypePattern);
}
if (parameterTypes != null) {
parameterTypes = parameterTypes.resolveBindings(scope, bindings, false, false);
checkForIncorrectTargetKind(parameterTypes, scope, false, true);
}
if (throwsPattern != null) {
throwsPattern = throwsPattern.resolveBindings(scope, bindings);
if (throwsPattern.getForbidden().getTypePatterns().length > 0
|| throwsPattern.getRequired().getTypePatterns().length > 0) {
checkForIncorrectTargetKind(throwsPattern, scope, false);
}
}
if (annotationPattern != null) {
annotationPattern = annotationPattern.resolveBindings(scope, bindings, false);
checkForIncorrectTargetKind(annotationPattern, scope, true);
}
hashcode = -1;
return this;
}
可以看到,分别针对返回值类型,方法定义类型、参数类型、异常类型、注解类型进行了绑定。我们主要来看下参数绑定。
上面的 parameterTypes,其实就是方法参数解析之后封装的 TypePatternList。
// TypePatternList
public TypePatternList resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
for (int i = 0; i < typePatterns.length; i++) {
TypePattern p = typePatterns[i];
if (p != null) {
typePatterns[i] = typePatterns[i].resolveBindings(scope, bindings, allowBinding, requireExactType);
}
}
return this;
}
遍历每一个类型对应的 TypePattern,逐个进行绑定。除 "*" 外,其余的类型在切入点表达式解析时都会被解析为 WildTypePattern,所以此处会执行 WildTypePattern#resolveBindings 进行类型的绑定。
// WildTypePattern
@Override
public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
// NamePattern 是 "*"
if (isNamePatternStar()) {
TypePattern anyPattern = maybeResolveToAnyPattern(scope, bindings, allowBinding, requireExactType);
if (anyPattern != null) {
if (requireExactType) {
scope.getWorld().getMessageHandler().handleMessage(
MessageUtil.error(WeaverMessages.format(WeaverMessages.WILDCARD_NOT_ALLOWED), getSourceLocation()));
return NO;
} else {
return anyPattern;
}
}
}
// 返回 null
TypePattern bindingTypePattern = maybeResolveToBindingTypePattern(scope, bindings, allowBinding, requireExactType);
if (bindingTypePattern != null) {
return bindingTypePattern;
}
annotationPattern = annotationPattern.resolveBindings(scope, bindings, allowBinding);
// resolve any type parameters
// 类型泛型参数
// 先对泛型参数类型进行绑定
if (typeParameters != null && typeParameters.size() > 0) {
typeParameters.resolveBindings(scope, bindings, allowBinding, requireExactType);
isGeneric = false;
}
// resolve any bounds
if (upperBound != null) {
upperBound = upperBound.resolveBindings(scope, bindings, allowBinding, requireExactType);
}
if (lowerBound != null) {
lowerBound = lowerBound.resolveBindings(scope, bindings, allowBinding, requireExactType);
// amc - additional interface bounds only needed if we support type vars again.
}
// 获取全限定性类名
String fullyQualifiedName = maybeGetCleanName(); // String
// 全限定性类名不为 null,才执行绑定
if (fullyQualifiedName != null) {
return resolveBindingsFromFullyQualifiedTypeName(fullyQualifiedName, scope, bindings, allowBinding, requireExactType);
} else {
if (requireExactType) {
scope.getWorld().getMessageHandler().handleMessage(
MessageUtil.error(WeaverMessages.format(WeaverMessages.WILDCARD_NOT_ALLOWED), getSourceLocation()));
return NO;
}
importedPrefixes = scope.getImportedPrefixes();
knownMatches = preMatch(scope.getImportedNames());
return this; // pattern contains wildcards so can't be resolved to an ExactTypePattern...
// XXX need to implement behavior for Lint.invalidWildcardTypeName
}
}
private TypePattern maybeResolveToBindingTypePattern(IScope scope, Bindings bindings, boolean allowBinding,
boolean requireExactType) {
// namePatterns 长度为 1,获取 simpleName
// 例如 int 类型
String simpleName = maybeGetSimpleName();
if (simpleName != null) {
// scope 为 BindingScope,继承 SimpleScope
// 返回 null
FormalBinding formalBinding = scope.lookupFormal(simpleName); // null
if (formalBinding != null) {
if (bindings == null) {
scope.message(IMessage.ERROR, this, "negation doesn't allow binding");
return this;
}
if (!allowBinding) {
scope.message(IMessage.ERROR, this, "name binding only allowed in target, this, and args pcds");
return this;
}
BindingTypePattern binding = new BindingTypePattern(formalBinding, isVarArgs);
binding.copyLocationFrom(this);
bindings.register(binding, scope);
return binding;
}
}
return null; // not possible to resolve to a binding type pattern
}
由外部传入的 parameterNames 和 parameterTypes 封装的 org.aspectj.weaver.tools.PointcutParameter 数组,在构建 IScope 时,解析为 FormalBinding 数组,封装在 IScope 的实现类 BindingScope 中。执行 scope.lookupFormal(simpleName) 时,遍历 FormalBinding 数组,判断 FormalBinding 数组元素持有的 name 是否和 simpleName 相等,相等则将当前 FormalBinding 返回。外部未传入 parameterNames 和 parameterTypes 时,执行 maybeResolveToBindingTypePattern 返回 null。我们在前面的文章 《AspectJ 中通知方法参数绑定》中介绍过,显式指定的参数在之后的 checkAllBound 方法执行时都会抛出异常,所以使用时不会自定义显式参数,即此处恒返回 null。
有一点注意,当获取全限定性类名 fullyQualifiedName 时,如果配置的表达式中表示类型的部分含有 "*",则表示不确定,获取的 fullyQualifiedName 为 null。只有 fullyQualifiedName 不为 null,才会执行真正的绑定。否则,会将原 WildTypePattern 返回。
// WildTypePattern
private TypePattern resolveBindingsFromFullyQualifiedTypeName(String fullyQualifiedName, IScope scope, Bindings bindings,
boolean allowBinding, boolean requireExactType) {
String originalName = fullyQualifiedName;
ResolvedType resolvedTypeInTheWorld = null;
UnresolvedType type;
// System.out.println("resolve: " + cleanName);
// ??? this loop has too many inefficiencies to count
resolvedTypeInTheWorld = lookupTypeInWorldIncludingPrefixes(scope.getWorld(), fullyQualifiedName, scope
.getImportedPrefixes());
if (resolvedTypeInTheWorld.isGenericWildcard()) {
type = resolvedTypeInTheWorld;
} else {
type = lookupTypeInScope(scope, fullyQualifiedName, this);
}
// 在 scope 中未找到
if ((type instanceof ResolvedType) && ((ResolvedType) type).isMissing()) {
return resolveBindingsForMissingType(resolvedTypeInTheWorld, originalName, scope, bindings, allowBinding,
requireExactType);
} else {
// scope 中找到,解析绑定的确切类型
return resolveBindingsForExactType(scope, type, fullyQualifiedName, requireExactType);
}
}
private ResolvedType lookupTypeInWorldIncludingPrefixes(World world, String typeName, String[] prefixes) {
ResolvedType ret = lookupTypeInWorld(world, typeName); // String
if (!ret.isMissing()) {
return ret;
}
ResolvedType retWithPrefix = ret;
int counter = 0;
// 丢失了,加上前缀接着找,默认的前缀一个 "java.lang.",找到了,退出循环,此时 retWithPrefix 为 ReferenceType
while (retWithPrefix.isMissing() && (counter < prefixes.length)) {
retWithPrefix = lookupTypeInWorld(world, prefixes[counter] + typeName);
counter++;
}
// 找到了,将 retWithPrefix 返回
if (!retWithPrefix.isMissing()) {
return retWithPrefix;
}
return ret;
}
private ResolvedType lookupTypeInWorld(World world, String typeName) {
UnresolvedType ut = UnresolvedType.forName(typeName); // signature = "LString;" --> new UnresolvedType(signature);
ResolvedType ret = world.resolve(ut, true); // 调用 World#resolve --> World#resolveToReferenceType
// ret 为 MissingResolvedTypeWithKnownSignature 时,isMissing() 返回 true
while (ret.isMissing()) {
int lastDot = typeName.lastIndexOf('.');
// "String" 跳出循环
if (lastDot == -1) {
break;
}
// 内部类
typeName = typeName.substring(0, lastDot) + '$' + typeName.substring(lastDot + 1);
ret = world.resolve(UnresolvedType.forName(typeName), true);
}
return ret;
}
在 lookTypeInWorldIncludingPrefixes 中,先对确定的全限定性类名,即 typeName,执行 lookupTypeInWorld,其实就是利用传入的 World,对 typeName 进行解决。
scope.getImportedPrefixes(),在 SimpleScope 中,默认 importedPrefixes 为 "java.lang."。
当 typeName 为 "String" 时,执行 WildTypePattern#lookupTypeInWorld,在方法中,利用 World 将 ut 处理为 ResolvedType。
public ResolvedType resolve(UnresolvedType ty, boolean allowMissing) {
// special resolution processing for already resolved types.
if (ty instanceof ResolvedType) {
ResolvedType rty = (ResolvedType) ty;
rty = resolve(rty);
// A TypeVariableReferenceType may look like it is resolved (it extends ResolvedType) but the internal
// type variable may not yet have been resolved
if (!rty.isTypeVariableReference() || ((TypeVariableReferenceType) rty).isTypeVariableResolved()) {
return rty;
}
}
// dispatch back to the type variable reference to resolve its
// constituent parts don't do this for other unresolved types otherwise
// you'll end up in a
// loop
if (ty.isTypeVariableReference()) {
return ty.resolve(this);
}
// if we've already got a resolved type for the signature, just return
// it
// after updating the world
String signature = ty.getSignature();
ResolvedType ret = typeMap.get(signature);
if (ret != null) {
ret.world = this; // Set the world for the RTX
return ret;
} else if (signature.equals("?") || signature.equals("*")) {
// might be a problem here, not sure '?' should make it to here as a
// signature, the
// proper signature for wildcard '?' is '*'
// fault in generic wildcard, can't be done earlier because of init
// issues
// TODO ought to be shared single instance representing this
ResolvedType something = getWildcard();
typeMap.put("?", something);
return something;
}
// no existing resolved type, create one
synchronized (buildingTypeLock) {
if (ty.isArray()) {
ResolvedType componentType = resolve(ty.getComponentType(), allowMissing);
ret = new ArrayReferenceType(signature, "[" + componentType.getErasureSignature(), this, componentType);
} else {
ret = resolveToReferenceType(ty, allowMissing);
if (!allowMissing && ret.isMissing()) {
ret = handleRequiredMissingTypeDuringResolution(ty);
}
if (completeBinaryTypes) {
completeBinaryType(ret);
}
}
}
// Pulling in the type may have already put the right entry in the map
ResolvedType result = typeMap.get(signature);
if (result == null && !ret.isMissing()) {
ret = ensureRawTypeIfNecessary(ret);
typeMap.put(signature, ret);
return ret;
}
if (result == null) {
return ret;
} else {
return result;
}
}
// World
// 解析为 ReferenceType
private final ResolvedType resolveToReferenceType(UnresolvedType ty, boolean allowMissing) {
if (ty.isParameterizedType()) {
// ======= parameterized types ================
ResolvedType rt = resolveGenericTypeFor(ty, allowMissing);
if (rt.isMissing()) {
return rt;
}
ReferenceType genericType = (ReferenceType) rt;
ReferenceType parameterizedType = TypeFactory.createParameterizedType(genericType, ty.typeParameters, this);
return parameterizedType;
} else if (ty.isGenericType()) {
// ======= generic types ======================
ResolvedType rt = resolveGenericTypeFor(ty, false);
if (rt.isMissing()) {
return rt;
}
ReferenceType genericType = (ReferenceType) rt;
if (rt.isMissing()) {
return rt;
}
return genericType;
} else if (ty.isGenericWildcard()) {
// ======= generic wildcard types =============
return resolveGenericWildcardFor((WildcardedUnresolvedType) ty);
} else {
// ======= simple and raw types ===============
// 获取泛型擦除后的签名字符串
String erasedSignature = ty.getErasureSignature();
ReferenceType simpleOrRawType = new ReferenceType(erasedSignature, this);
if (ty.needsModifiableDelegate()) {
simpleOrRawType.setNeedsModifiableDelegate(true);
}
// 针对 "String" 创建 delegate 时,利用 ClassLoader 加载 "String",无法加载,返回 null
ReferenceTypeDelegate delegate = resolveDelegate(simpleOrRawType);
if (delegate == null) {
// MissingResolvedTypeWithKnownSignature 继承 ResolvedType,ResolvedType 继承 UnresolvedType
return new MissingResolvedTypeWithKnownSignature(ty.getSignature(), erasedSignature, this);
}
if (delegate.isGeneric() && behaveInJava5Way) {
// ======== raw type ===========
simpleOrRawType.typeKind = TypeKind.RAW;
if (simpleOrRawType.hasNewInterfaces()) { // debug 375777
throw new IllegalStateException(
"Simple type promoted forced to raw, but it had new interfaces/superclass. Type is "
+ simpleOrRawType.getName());
}
ReferenceType genericType = makeGenericTypeFrom(delegate, simpleOrRawType);
simpleOrRawType.setDelegate(delegate);
genericType.setDelegate(delegate);
simpleOrRawType.setGenericType(genericType);
return simpleOrRawType;
} else {
// ======== simple type =========
simpleOrRawType.setDelegate(delegate);
return simpleOrRawType;
}
}
}
将 UnresolvedType 解析为 ReferenceType 之后,会为其创建一个 delegate。
public static ReflectionBasedReferenceTypeDelegate createDelegate(ReferenceType forReferenceType, World inWorld,
ClassLoader usingClassLoader) {
try {
Class c = Class.forName(forReferenceType.getName(), false, usingClassLoader);
ReflectionBasedReferenceTypeDelegate rbrtd = create15Delegate(forReferenceType, c, usingClassLoader, inWorld);
if (rbrtd != null) {
return rbrtd; // can be null if we didn't find the class the delegate logic loads
}
return new ReflectionBasedReferenceTypeDelegate(c, usingClassLoader, inWorld, forReferenceType);
} catch (ClassNotFoundException cnfEx) {
return null;
}
}
private static ReflectionBasedReferenceTypeDelegate create15Delegate(ReferenceType forReferenceType, Class forClass,
ClassLoader usingClassLoader, World inWorld) {
try {
Class delegateClass = Class.forName("org.aspectj.weaver.reflect.Java15ReflectionBasedReferenceTypeDelegate");
ReflectionBasedReferenceTypeDelegate ret = (ReflectionBasedReferenceTypeDelegate) delegateClass.getDeclaredConstructor().newInstance();
ret.initialize(forReferenceType, forClass, usingClassLoader, inWorld);
return ret;
} catch (ClassNotFoundException cnfEx) {
throw new IllegalStateException(
"Attempted to create Java 1.5 reflection based delegate but org.aspectj.weaver.reflect.Java15ReflectionBasedReferenceTypeDelegate was not found on classpath");
} catch (InstantiationException insEx) {
throw new IllegalStateException("Attempted to create Java 1.5 reflection based delegate but InstantiationException: "
+ insEx + " occured");
} catch (IllegalAccessException illAccEx) {
throw new IllegalStateException("Attempted to create Java 1.5 reflection based delegate but IllegalAccessException: "
+ illAccEx + " occured");
} catch (NoSuchMethodException nsMethEx) {
throw new IllegalStateException("Attempted to create Java 1.5 reflection based delegate but NoSuchMethodException: "
+ nsMethEx + " occured");
} catch (InvocationTargetException invTargEx) {
throw new IllegalStateException("Attempted to create Java 1.5 reflection based delegate but InvocationTargetException: "
+ invTargEx + " occured");
}
}
利用 classLoader 去加载 "String",此时捕获异常,返回 null,由于 delegate 为 null,会创建一个 MissingResolvedTypeWithKnownSignature 返回。MissingResolvedTypeWithKnownSignature 继承 ResolvedType。
MissingResolvedTypeWithKnownSignature#isMissing 返回 true,此时在 lookupTypeInWorldIncludingPrefixes 方法中,遍历 prefixes 数组,给无法加载的类型,加上前缀接着执行 lookupTypeInWorld 去查找,"String" 变成 "java.lang.String",这一次可以加载。利用反射创建一个 Java15ReflectionBasedReferenceTypeDelegate,并完成初始化。之后为 simpleOrRawType 设置 delegate 之后返回,接着退出循环,此时 retWithPrefix 为 ReferenceType。
接着,由于 resolvedTypeInTheWorld.isGenericWildcard() 返回 false,执行 lookupTypeInScope,在 scope 中再查找一遍。
// WildTypePattern
// 此处参数 loacation,即 WildTypePattern
private UnresolvedType lookupTypeInScope(IScope scope, String typeName, IHasPosition location) {
UnresolvedType type = null;
while (ResolvedType.isMissing(type = scope.lookupType(typeName, location))) { // typeName "String"
int lastDot = typeName.lastIndexOf('.');
if (lastDot == -1) {
break;
}
typeName = typeName.substring(0, lastDot) + '$' + typeName.substring(lastDot + 1);
}
return type;
}
// BindingsScope
public UnresolvedType lookupType(String name, IHasPosition location) {
// 扩展 importedPrefixes
// bug 126560
if (enclosingType != null && !importsUpdated) {
// add the package we're in to the list of imported
// prefixes so that we can find types in the same package
String pkgName = enclosingType.getPackageName(); // 切面类包名
if (pkgName != null && !pkgName.equals("")) {
String[] existingImports = getImportedPrefixes(); // {"java.lang."}
String pkgNameWithDot = pkgName.concat("."); // pkgName + "."
boolean found = false;
for (String existingImport : existingImports) {
if (existingImport.equals(pkgNameWithDot)) {
found = true;
break;
}
}
// 变更 SimpleScope 中 importedPrefixes
if (!found) {
String[] newImports = new String[existingImports.length + 1];
System.arraycopy(existingImports, 0, newImports, 0, existingImports.length);
newImports[existingImports.length] = pkgNameWithDot;
setImportedPrefixes(newImports);
}
}
importsUpdated = true;
}
return super.lookupType(name, location);
}
// BindingScope 父类 SimpleScope
public UnresolvedType lookupType(String name, IHasPosition location) {
for (String importedName : importedNames) { // {}
// make sure we're matching against the type name rather than part of it
// if (importedName.endsWith("." + name)) {
if (importedName.endsWith(name)) {
return world.resolve(importedName);
}
}
// Check for a primitive
if (name.length() < 8 && Character.isLowerCase(name.charAt(0))) {
// could be a primitive
int len = name.length();
if (len == 3) {
if (name.equals("int")) {
return UnresolvedType.INT;
}
} else if (len == 4) {
if (name.equals("void")) {
return UnresolvedType.VOID;
} else if (name.equals("byte")) {
return UnresolvedType.BYTE;
} else if (name.equals("char")) {
return UnresolvedType.CHAR;
} else if (name.equals("long")) {
return UnresolvedType.LONG;
}
} else if (len == 5) {
if (name.equals("float")) {
return UnresolvedType.FLOAT;
} else if (name.equals("short")) {
return UnresolvedType.SHORT;
}
} else if (len == 6) {
if (name.equals("double")) {
return UnresolvedType.DOUBLE;
}
} else if (len == 7) {
if (name.equals("boolean")) {
return UnresolvedType.BOOLEAN;
}
}
}
// Is it fully qualified?
// 全类型指定,直接解析
if (name.indexOf('.') != -1) {
return world.resolve(UnresolvedType.forName(name), true);
}
// 遍历前缀,加前缀解析
for (String importedPrefix : importedPrefixes) {
ResolvedType tryType = world.resolve(UnresolvedType.forName(importedPrefix + name), true);
if (!tryType.isMissing()) {
return tryType;
}
}
return world.resolve(UnresolvedType.forName(name), true);
}
可以看到,先对默认的 importedPrefixes 进行了扩充,将切面类所在包名也扩充了进去。接着执行 SimpleScope#lookupType,对基本类型和全限定类型,单独处理,针对 "String",会加上前缀进行解析,解析为 ReferenceType,直接返回。此处执行 world.resolve 时,如果之前已经对相应类型进行过解析,则会直接从 World 中的缓存字段 typeMap 中获取到对应的 ResolvedType。
由于已经判断为确定的类型,接下来执行绑定的最后一步,调用 WildTypePattern#resolveBindingsForExactType,封装 ExactTypePattern。
// WildTypePattern
private TypePattern resolveBindingsForExactType(IScope scope, UnresolvedType aType, String fullyQualifiedName,
boolean requireExactType) {
TypePattern ret = null;
if (aType.isTypeVariableReference()) {
// we have to set the bounds on it based on the bounds of this pattern
ret = resolveBindingsForTypeVariable(scope, (UnresolvedTypeVariableReferenceType) aType);
} else if (typeParameters.size() > 0) {
// 存在泛型参数时处理方式
ret = resolveParameterizedType(scope, aType, requireExactType);
} else if (upperBound != null || lowerBound != null) {
// this must be a generic wildcard with bounds
// 泛型类型存在边界
ret = resolveGenericWildcard(scope, aType);
} else {
// String... 可变参数,dim 不为 0
if (dim != 0) {
aType = UnresolvedType.makeArray(aType, dim); // 数组类型 java.lang.String[]
}
ret = new ExactTypePattern(aType, includeSubtypes, isVarArgs);
}
ret.setAnnotationTypePattern(annotationPattern);
ret.copyLocationFrom(this);
return ret;
}
此处根据不同的条件,执行不同的封装策略。如果存在泛型参数,执行 WildTypePattern#resolveParameterizedType,将 WildTypePattern 封装为 ExactTypePattern。
默认情况下,如果 dim 不为 0,即存在数组类型或可变参数,将其统一处理为数组类型对应的字节码签名。
public static UnresolvedType makeArray(UnresolvedType base, int dims) {
StringBuffer sig = new StringBuffer();
for (int i = 0; i < dims; i++) {
sig.append("[");
}
sig.append(base.getSignature()); // "[Ljava/lang/String;"
return UnresolvedType.forSignature(sig.toString());
}
例如,base 为 "java.lang.String",处理后,signature 变为 "[Ljava/lang/String",接着利用 TypeFactory#createTypeFromSignature 为 signature 创建 UnresolvedType。
// TypeFactory#createTypeFromSignature
...
} else if (firstChar == '[') {
int dims = 0;
while (signature.charAt(dims) == '[') {
dims++;
}
// 数组元素类型
UnresolvedType componentType = createTypeFromSignature(signature.substring(dims));
return new UnresolvedType(signature, signature.substring(0, dims) + componentType.getErasureSignature());
}
...
针对签名字符串 "Ljava/lang/String;" 和 "[Ljava/lang/String;" 分别创建 UnresolvedType,之后将数组签名字符串创建的 UnresolvedType 返回,视为 aType。
之后,封装一个 ExactTypePattern。就这样,将一个 "String..." 解析为 java.lang.String[]。
顺便说下,由于在 scope.lookupType 中对 importedPrefixes 进行了扩充,也就是和切面类在同一个包下的类,配置为切入点表达式类型时,也可以简写为类名的形式,不用指定包名。
示例二
execution(* *..UserServiceImpl.doSome(java.util.List<String>,int))
参数解析
经过前面的介绍,我们知道,(java.util.List<String>,int) 会被解析成两个 TypePattern,之后封装成一个 TypePatternList。解析第一个参数类型时,由于存在泛型参数,会调用 PatternParser#maybeParseTypeParameterList。
// 泛型参数解析 "<,>"
public TypePatternList maybeParseTypeParameterList() {
if (!maybeEat("<")) {
return null;
}
List<TypePattern> typePats = new ArrayList<>();
do {
TypePattern tp = parseTypePattern(true, false);
typePats.add(tp);
} while (maybeEat(","));
eat(">");
TypePattern[] tps = new TypePattern[typePats.size()];
typePats.toArray(tps);
return new TypePatternList(tps);
}
可以看到,又转化为对单个类型的解析。之后将所有的泛型参数类型封装成一个 TypePatternList。
此处将 "java.util.List<String>" 封装为 WildTypePattern,持有字段 typeParameters 为 "String" 封装的 WildTypePattern 所组成的 TypePatternList。
类型绑定
直接来看参数绑定,在 WildTypePattern#resolveBindings 中,针对 "java.util.List<String>" 封装的 WildTypePattern,由于 typeParameters 不为 null。执行 typeParameters.resolveBindings(...),即执行 TypeParameterList#resolveBindings。遍历每一个泛型类型,执行 WildTypePattern#resolveBindings。也就是说,只要是类型,最终都会转换到 WildTypePattern#resolveBindings 来执行。
将 "String" 封装的 WildTypePattern,在 WildTypePattern#resolveBindingsFromFullyQualifiedTypeName 中添加默认前缀,处理为 "java.lang.String",之后封装为 ExactTypePattern。
接着来看 "java.util.List" 的绑定,在 WildTypePattern#resolveBindings 中,得到fullyQualifiedName 为 "java.util.List",接着执行 WildTypePattern#resolveBindingsFromFullyQualifiedTypeName --> lookupTypeInWorldIncludingPrefixes --> lookupTypeInWorld,先将 "java.util.List" 封装成 typeKind 为 TypeKind.SIMPLE 的 UnresolvedType,之后执行 World#resolve。在 typeMap 中未查找到,执行 World#resolveToReferenceType。封装 simpleOrRawType,之后为其创建 delegate。利用 classLoader 加载 "java.util.List" 得到 aClass,在 Java15ReflectionBasedReferenceTypeDelegate#initialize 方法中将 aClass 传递给 Java15ReflectionBasedReferenceTypeDelegate 父类 ReflectionBasedReferenceTypeDelegate 中 myClass 字段。
创建完 delegate,在 World#resolveToReference 中,调用 delegate.isGeneric()。
@Override
public boolean isGeneric() {
// return false; // for now
return getBaseClass().getTypeParameters().length > 0;
}
protected Class getBaseClass() {
return this.myClass;
}
java.util.List 定义时就存在泛型参数,所以此时返回 true。将 simpleOrRawType 中 typeKind 修改为 TypeKind.RAW,接着执行 World#makeGenericTypeFrom。
// World
private ReferenceType makeGenericTypeFrom(ReferenceTypeDelegate delegate, ReferenceType rawType) {
String genericSig = delegate.getDeclaredGenericSignature();
if (genericSig != null) {
return new ReferenceType(UnresolvedType.forGenericTypeSignature(rawType.getSignature(),
delegate.getDeclaredGenericSignature()), this);
} else {
// 执行 else
return new ReferenceType(UnresolvedType.forGenericTypeVariables(rawType.getSignature(), delegate.getTypeVariables()),
this);
}
}
// Java15ReflectionBasedReferenceTypeDelegate
@Override
public TypeVariable[] getTypeVariables() {
// null
TypeVariable[] workInProgressSetOfVariables = getResolvedTypeX().getWorld().getTypeVariablesCurrentlyBeingProcessed(
getBaseClass());
if (workInProgressSetOfVariables != null) {
return workInProgressSetOfVariables;
}
if (this.typeVariables == null) {
java.lang.reflect.TypeVariable[] tVars = this.getBaseClass().getTypeParameters();
// org.aspectj.weaver.TypeVariable
TypeVariable[] rTypeVariables = new TypeVariable[tVars.length];
// basic initialization
for (int i = 0; i < tVars.length; i++) {
rTypeVariables[i] = new TypeVariable(tVars[i].getName());
}
// stash it
this.getResolvedTypeX().getWorld().recordTypeVariablesCurrentlyBeingProcessed(getBaseClass(), rTypeVariables);
// now fill in the details...
for (int i = 0; i < tVars.length; i++) {
// 处理 java.lang.reflect.TypeVariable,将其处理成 TypeVariableReferenceType
TypeVariableReferenceType tvrt = ((TypeVariableReferenceType) typeConverter.fromType(tVars[i]));
TypeVariable tv = tvrt.getTypeVariable();
rTypeVariables[i].setSuperclass(tv.getSuperclass());
rTypeVariables[i].setAdditionalInterfaceBounds(tv.getSuperInterfaces());
rTypeVariables[i].setDeclaringElement(tv.getDeclaringElement());
rTypeVariables[i].setDeclaringElementKind(tv.getDeclaringElementKind());
rTypeVariables[i].setRank(tv.getRank());
}
this.typeVariables = rTypeVariables;
this.getResolvedTypeX().getWorld().forgetTypeVariablesCurrentlyBeingProcessed(getBaseClass());
}
return this.typeVariables;
}
// JavaLangTypeToResolvedTypeConverter
public ResolvedType fromType(Type type) {
if (type instanceof Class) {
Class clazz = (Class) type;
String name = clazz.getName();
/**
* getName() can return:
*
* 1. If this class object represents a reference type that is not an
* array type then the binary name of the class is returned
* 2. If this class object represents a primitive type or void, then
* the name returned is a String equal to the Java language keyword
* corresponding to the primitive type or void.
* 3. If this class object represents a class of arrays, then the internal
* form of the name consists of the name of the element type preceded by
* one or more '[' characters representing the depth of the array nesting.
*/
if (clazz.isArray()) {
UnresolvedType ut = UnresolvedType.forSignature(name.replace('.', '/'));
return getWorld().resolve(ut);
} else {
return getWorld().resolve(name);
}
} else if (type instanceof ParameterizedType) {
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=509327
// TODO should deal with the ownerType if it set, indicating this is possibly an inner type of a parameterized type
Type ownerType = ((ParameterizedType) type).getOwnerType();
ParameterizedType parameterizedType = (ParameterizedType) type;
ResolvedType baseType = fromType(parameterizedType.getRawType());
Type[] typeArguments = parameterizedType.getActualTypeArguments();
if (baseType.isSimpleType() && typeArguments.length == 0 && ownerType != null) {
// 'type' is an inner type of some outer parameterized type
// For now just return the base type - in future create the parameterized form of the outer
// and use it with the inner. We return the base type to be compatible with what the
// code does that accesses the info from the bytecode (unlike this code which accesses it
// reflectively).
return baseType;
}
ResolvedType[] resolvedTypeArguments = fromTypes(typeArguments);
return TypeFactory.createParameterizedType(baseType, resolvedTypeArguments, getWorld());
} else if (type instanceof java.lang.reflect.TypeVariable) {
TypeVariableReferenceType inprogressVar = typeVariablesInProgress.get(type);
if (inprogressVar != null) {
return inprogressVar;
}
java.lang.reflect.TypeVariable tv = (java.lang.reflect.TypeVariable) type;
// org.aspectj.weaver.TypeVariable
TypeVariable rt_tv = new TypeVariable(tv.getName());
// 将 rt_tv 封装为 TypeVariableReferenceType
TypeVariableReferenceType tvrt = new TypeVariableReferenceType(rt_tv, getWorld());
typeVariablesInProgress.put(type, tvrt); // record what we are working on, for recursion case
// 处理边界
Type[] bounds = tv.getBounds();
ResolvedType[] resBounds = fromTypes(bounds);
ResolvedType upperBound = resBounds[0];
ResolvedType[] additionalBounds = new ResolvedType[0];
if (resBounds.length > 1) {
additionalBounds = new ResolvedType[resBounds.length - 1];
System.arraycopy(resBounds, 1, additionalBounds, 0, additionalBounds.length);
}
rt_tv.setUpperBound(upperBound);
rt_tv.setAdditionalInterfaceBounds(additionalBounds);
typeVariablesInProgress.remove(type); // we have finished working on it
return tvrt;
} else if (type instanceof WildcardType) {
WildcardType wildType = (WildcardType) type;
Type[] lowerBounds = wildType.getLowerBounds();
Type[] upperBounds = wildType.getUpperBounds();
ResolvedType bound = null;
boolean isExtends = lowerBounds.length == 0;
if (isExtends) {
bound = fromType(upperBounds[0]);
} else {
bound = fromType(lowerBounds[0]);
}
return new BoundedReferenceType((ReferenceType) bound, isExtends, getWorld());
} else if (type instanceof GenericArrayType) {
GenericArrayType genericArrayType = (GenericArrayType) type;
Type componentType = genericArrayType.getGenericComponentType();
return UnresolvedType.makeArray(fromType(componentType), 1).resolve(getWorld());
}
return ResolvedType.MISSING;
}
public TypeVariableReferenceType(TypeVariable typeVariable, World world) {
super(typeVariable.getGenericSignature(), typeVariable.getErasureSignature(), world);
this.typeVariable = typeVariable;
}
public String getGenericSignature() {
return "T" + name + ";";
}
public String getErasureSignature() {
return getFirstBound().getErasureSignature();
}
// org.aspectj.weaver.TypeVariable
// 未指定返回 UnresolvedType.OBJECT
public UnresolvedType getFirstBound() {
if (firstbound != null) {
return firstbound;
}
if (superclass == null || superclass.getSignature().equals("Ljava/lang/Object;")) {
if (superInterfaces.length > 0) {
firstbound = superInterfaces[0];
} else {
firstbound = UnresolvedType.OBJECT;
}
} else {
firstbound = superclass;
}
return firstbound;
}
public static UnresolvedType forGenericTypeVariables(String sig, TypeVariable[] tVars) {
UnresolvedType ret = UnresolvedType.forSignature(sig);
ret.typeKind = TypeKind.GENERIC;
ret.typeVariables = tVars;
ret.signatureErasure = sig;
ret.signature = ret.signatureErasure;
return ret;
}
public ReferenceType(UnresolvedType genericType, World world) {
super(genericType.getSignature(), world);
typeKind = TypeKind.GENERIC;
this.typeVariables = genericType.typeVariables;
}
由于解析切入点表达式时,将一个类型中的类型和泛型分开解析,所以此处 this.getBaseClass().getTypeParameters() 相当于泛型擦除之后获取定义时的泛型变量,即 java.lang.reflect.TypeVariable。之后将 java.lang.reflect.TypeVariable 转换为 org.aspectj.weaver.TypeVariable。可以看到,对泛型类型变量的处理都是委托给 delegate 来处理的。
接着调用 UnresolvedType#forGenericTypeVariables,封装一个 typeKind 为 TypeKind.GENERIC 的 UnresolvedType,之后又依赖这个 UnresolvedType 封装一个 ReferenceType,作为 genericType,simpleOrRawType 和 genericType 共用一个 delegate,调用 ReferenceType#setGenericType,为 simpleOrRawType 中 genericType 属性赋值。最后将这个 simpleOrRawType 返回并缓存在 typeMap 中。
接着在 WildTypePattern#resolveBindingsFromFullyQualifiedTypeName 中调用 lookupTypeInScope,由于 "Ljava/util/List;" 已经缓存在了 typeMap 中,所以这一次直接从缓存获取。
完成这些准备工作之后,调用 WildTypePattern#resolveBindingsForExactType,此时由于存在 typeParameters,调用 WildTypePattern#resolveParameterizedType。
// WildTypePattern
private TypePattern resolveParameterizedType(IScope scope, UnresolvedType aType, boolean requireExactType) {
// 保证 aType 已经解析
ResolvedType rt = aType.resolve(scope.getWorld());
if (!verifyTypeParameters(rt, scope, requireExactType)) {
return TypePattern.NO; // messages already isued
}
// Only if the type is exact *and* the type parameters are exact should we create an
// ExactTypePattern for this WildTypePattern
// 实际泛型参数类型都已确定,且是否不允许子类型
if (typeParameters.areAllExactWithNoSubtypesAllowed()) {
TypePattern[] typePats = typeParameters.getTypePatterns();
UnresolvedType[] typeParameterTypes = new UnresolvedType[typePats.length];
for (int i = 0; i < typeParameterTypes.length; i++) {
typeParameterTypes[i] = ((ExactTypePattern) typePats[i]).getExactType();
}
// rt could be a parameterized type 156058
if (rt.isParameterizedType()) {
rt = rt.getGenericType();
}
// 拼接 ParameterizedType,并完成 resolve
ResolvedType type = TypeFactory.createParameterizedType(rt, typeParameterTypes, scope.getWorld());
if (isGeneric) {
type = type.getGenericType();
}
// UnresolvedType tx = UnresolvedType.forParameterizedTypes(aType,typeParameterTypes);
// UnresolvedType type = scope.getWorld().resolve(tx,true);
if (dim != 0) {
type = ResolvedType.makeArray(type, dim);
}
return new ExactTypePattern(type, includeSubtypes, isVarArgs);
} else {
// AMC... just leave it as a wild type pattern then?
importedPrefixes = scope.getImportedPrefixes();
knownMatches = preMatch(scope.getImportedNames());
return this;
}
}
// TypeFactory
public static ReferenceType createParameterizedType(ResolvedType aBaseType, UnresolvedType[] someTypeParameters, World inAWorld) {
ResolvedType baseType = aBaseType;
if (!aBaseType.isGenericType()) {
if (someTypeParameters != null && someTypeParameters.length > 0) {
if (!aBaseType.isRawType()) {
throw new IllegalStateException("Expecting raw type, but " + aBaseType+" is of type "+aBaseType.getTypekind());
}
// 获取 genericType 作为 baseType
baseType = baseType.getGenericType();
if (baseType == null) {
throw new IllegalStateException("Raw type does not have generic type set");
}
} // else if someTypeParameters is null, then the base type is allowed to be non-generic, it's an inner
}
ResolvedType[] resolvedParameters = inAWorld.resolve(someTypeParameters);
// 是否已经存在衍生品
ReferenceType existingType = ((ReferenceType)baseType).findDerivativeType(resolvedParameters);
ReferenceType pType = null;
if (existingType!=null) {
pType = existingType;
} else {
// 创建衍生品
pType =new ReferenceType(baseType, resolvedParameters, inAWorld);
}
// 放入 typeMap
return (ReferenceType) pType.resolve(inAWorld);
}
public ReferenceType(ResolvedType theGenericType,
ResolvedType[] theParameters, World aWorld) {
// 拼接的参数化签名为:"Pjava/util/List<Ljava/lang/String;>;"
// 泛型擦除后的签名:"Ljava/util/List;"
super(makeParameterizedSignature(theGenericType, theParameters),
theGenericType.signatureErasure, aWorld);
ReferenceType genericReferenceType = (ReferenceType) theGenericType;
this.typeParameters = theParameters;
this.genericType = genericReferenceType;
this.typeKind = TypeKind.PARAMETERIZED;
this.delegate = genericReferenceType.getDelegate();
// 将拼接的衍生品作为泛型类型的依赖
genericReferenceType.addDependentType(this);
}
// 拼接参数化签名
private static String makeParameterizedSignature(ResolvedType aGenericType,
ResolvedType[] someParameters) {
// Ljava/util/List;
String rawSignature = aGenericType.getErasureSignature();
StringBuffer ret = new StringBuffer();
ret.append(PARAMETERIZED_TYPE_IDENTIFIER);
ret.append(rawSignature.substring(1, rawSignature.length() - 1));
ret.append("<");
for (ResolvedType someParameter : someParameters) {
ret.append(someParameter.getSignature());
}
ret.append(">;");
return ret.toString();
}
synchronized void addDependentType(ReferenceType dependent) {
// 添加依赖
synchronized (derivativeTypes) {
this.derivativeTypes
.add(new WeakReference<>(dependent));
}
}
从 aBaseType,也就是前面返回的 simpleOrRawType 中获取 genericType 作为 baseType,将类型和泛型实参类型拼接起来,作为 signature,之后封装 ReferenceType,此时 typeKind 为 TypeKind.PARAMETERIZED。
java.util.List<String> 被处理为 "Pjava/util/List<Ljava/lang/String;>;",称之为衍生品。
最后将这个衍生品 ReferenceType 传递给 ExactTypePattern。
这样就完成了泛型类型的类型绑定,解析的时候,将定义类型和泛型参数类型分开,统一封装到 WildTypePattern,之后在类型绑定时,将其具体类型和实际泛型参数类型拼接为一个字符串,封装 ReferenceType,传递给 ExactTypePattern。