此篇博客主要讲解Spring如何验证将要实例化的Bean是否应该被代理,生成代理对象的时机问题。
在第二篇博客中,Spring对容器内所有的标识了@Aspect注解的的类的切面方法(标识了@Around, @Before, @After, @AfterReturning, @AfterThrowing的方法)生成切面Advisor,切面由切入点Pointcut和通知组成,切入点一般是ExpressionPointcut,及带表达式的切入点,由注解上的value或pointcut属性来指定;通知一般就是被织入的方法,就是注解标识的方法。
Spring代理Bean默认是singleton形式,即多个织入方法织入同一个代理对象,而不是每个方法生成一个对象。传统的AOP是每个方法生成一个代理对象。详情可查看@Aspect的value属性。如果被代理对象的scope不是singleton,则需要在value属性上指定代理的类型,比如是perTarget等。
基于注解形式的AOP的代理对象生成的时机一般是在每个Bean初始化之后,及执行BeanPostProcessor的postProcessAfterInitialization方法,可看AbstractAutoProxyCreator的方法结构。如果对象的scope非singleton,那么生成代理对象的时机肯定在postProcessAfterInitialization;如果对象的scope是singleton,那么可能在postProcessAfterInitialization,也可能在getEarlyBeanReference方法。如果被代理的Bean触发了循环引用circular references,即Bean A注入了Bean B,而B内也注入了A,那么在解析B的时候会触发A的getEarlyBeanReference方法,如果A符合被代理的条件,则会直接生产代理对象,将代理对象注入B的属性中。在这种情况下有危险,B本来想注入A,但是结果注入的是A的代理对象,此时A还是一个原始的对象,还未注入属性及执行初始化方法,所以有很大程度上会报异常。结论 : 动态代理scope = singleton时请注意避免循环引用。
接下来将生成代理对象的代码:
代码块1
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
//如果scope = singleton的Bean触发circular references,会在此步生成代理实例,生成时机比正常的早得多
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
this.earlyProxyReferences.add(cacheKey);
}
return wrapIfNecessary(bean, beanName, cacheKey);
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//大部分的动态代理对象均在此步骤生成,此步骤是Bean实例化的最后一步
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
//校验此类是否应该被代理,也就是将此类和所有的ExpressionPointcut匹配,匹配代码解析看下一块(代码块2)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
验证在实例化的Bean是否应该被代理,如果应该则发挥那些符合条件的待织入切面Advisor:
代码块2
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//获取容器中的所有切面
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//验证beanClass是否该被代理,如果应该,则返回所有符合条件的待织入切面
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try { //匹配过程,看下一块代码(代码块3)
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
}
AopUtils工具类循环的将每个Advisor与BeanClass匹配,如果匹配上就方法返回的集合中,
验证步骤:
- 在类上做精确匹配,如果匹配规则定义在方法上,则返回maybetrue,如果规则定义在类上,不匹配则直接返回false
- 当类上返回的结果为true或者maybetrue,再进行方法的匹配。方法的匹配也是先做模糊匹配,如果返回的为nevermatch或者alwaysmatche,则得到了结果。
- 如果返回的结果不能确定为true或false,则需要根据实际的去验证,比如args(…)则验证方法的参数是否有指定的类型,@args则验证方法的参数是否标识了指定的注解
- 在方法上做模糊匹配的原因是一个类从父类继承,实现接口及自身的方法很多,如果能提前做一个大致的预估,如果预估的结果是肯定不匹配或不匹配,则可以省去对其所有方法的匹配解析。
代码块3
public abstract class AopUtils {
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
for (Advisor candidate : candidateAdvisors) {
//基于注解形式生成的Advisor均是PointcutAdvisor,所以条件均不符合
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
//pca.getPointcut()返回的是一个AspectJExpressionPointcut类型对象
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
//先对类做匹配,如果结果为false则说明不匹配,代码详解看代码块4
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
//再对方法做匹配,有些匹配规则只作用在类上,那么方法的匹配确定返回true,
//很多规则是针对方法的代理,所以需要继续对合适的类里的所有方法做验证
MethodMatcher methodMatcher = pc.getMethodMatcher();
//methodMatcher 一般是AspectJExpressionPointcut对象自身,所有此步不符合
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
//获取类所实现的所有接口和所有类层级的方法,循环验证
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
public boolean matches(Method method, Class<?> targetClass) {
return matches(method, targetClass, false);
}
public boolean matches(Method method, Class<?> targetClass, boolean beanHasIntroductions) {
checkReadyToMatch();
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
//getShadowMatch方法的调用繁杂,有点类似Class的匹配,最终也会调用到Pointcut的match(Shadow shadow)方法
//Pointcut对方法的匹配看下一个方法
ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);
// Special handling for this, target, @this, @target, @annotation
// in Spring - we can optimize since we know we have exactly this class,
// and there will never be matching subclass at runtime.
//this, target, @this, @target, @annotation这些匹配规则都是匹配类的,当类的匹配通过时,方法均通过
if (shadowMatch.alwaysMatches()) {
return true;
}
else if (shadowMatch.neverMatches()) {
return false;
}
else {
// the maybe case
if (beanHasIntroductions) {
return true;
}
//如果FuzzyBoolean 即不确定错误,也不确定是正确的,那么就需要实际的验证,
//比如args(...)则验证方法的参数是否有指定的类型,@args则验证方法的参数是否标识了指定的注解
// A match test returned maybe - if there are any subtype sensitive variables
// involved in the test (this, target, at_this, at_target, at_annotation) then
// we say this is not a match as in Spring there will never be a different
// runtime subtype.
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
}
}
public abstract class Pointcut extends PatternNode {
public final FuzzyBoolean match(Shadow shadow) {
if (shadow.shadowId == lastMatchedShadowId) {
return lastMatchedShadowResult;
}
FuzzyBoolean ret;
// this next test will prevent a lot of un-needed matching going on....
if (shadow.getKind().isSet(couldMatchKinds())) {
//不同的Pointcut实例对此方法做了不同的实现,比如args,this,target等等,
//不是实实在在的根据表达式去验证方法,而仅仅只是粗略的返回一个模糊的结果,比如可能为真,也可能为假
ret = matchInternal(shadow);
} else {
ret = FuzzyBoolean.NO;
}
lastMatchedShadowId = shadow.shadowId;
lastMatchedShadowResult = ret;
return ret;
}
}
}
表达式形式的切入点对类的匹配验证:
代码块4
public class AspectJExpressionPointcut extends AbstractExpressionPointcut implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware {
public boolean matches(Class<?> targetClass) {
checkReadyToMatch(); //确保生成表达式解析的Context环境
try {
try { //根据表达式的解析实例,验证此类是否匹配,代码解析看下一块代码(代码块6)
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
catch (ReflectionWorldException ex) {
logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
if (fallbackExpression != null) {
return fallbackExpression.couldMatchJoinPointsInType(targetClass);
}
}
}
catch (Throwable ex) {
logger.debug("PointcutExpression matching rejected target class", ex);
}
return false;
}
private void checkReadyToMatch() {
if (getExpression() == null) {
throw new IllegalStateException("Must set property 'expression' before attempting to match");
}
if (this.pointcutExpression == null) {
this.pointcutClassLoader = determinePointcutClassLoader();
//这一步很重要,根据切面注解的value属性,生成切入点表达式实例,代码解析看下一块代码(代码块5)
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
}
}
根据切面注解的value值,比如@After(“@args(….)”),生成不同实例的切入点表达式实例,即Pointcut实现类,切入点的实现类有很多,但Spring并不是每种都支持,支持的类型可以在AspectJExpressionPointcut的SUPPORTED_PRIMITIVES属性中看到。
代码块5
public class AspectJExpressionPointcut extends AbstractExpressionPointcut implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware {
private void checkReadyToMatch() {
if (getExpression() == null) {
throw new IllegalStateException("Must set property 'expression' before attempting to match");
}
if (this.pointcutExpression == null) {
this.pointcutClassLoader = determinePointcutClassLoader();
//第一步
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
}
private PointcutExpression buildPointcutExpression(ClassLoader classLoader) {
PointcutParser parser = initializePointcutParser(classLoader);
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
for (int i = 0; i < pointcutParameters.length; i++) {
pointcutParameters[i] = parser.createPointcutParameter(
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
}
//第二步
return parser.parsePointcutExpression(replaceBooleanOperators(getExpression()),
this.pointcutDeclarationScope, pointcutParameters);
}
}
public class PointcutParser {
public PointcutExpression parsePointcutExpression(String expression, Class inScope, PointcutParameter[] formalParameters)
throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {
PointcutExpressionImpl pcExpr = null;
try {
//第三步
Pointcut pc = resolvePointcutExpression(expression, inScope, formalParameters);
pc = concretizePointcutExpression(pc, inScope, formalParameters);
validateAgainstSupportedPrimitives(pc, expression); // again, because we have now followed any ref'd pcuts
pcExpr = new PointcutExpressionImpl(pc, expression, formalParameters, getWorld());
} catch (ParserException pEx) {
throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
} catch (ReflectionWorld.ReflectionWorldException rwEx) {
throw new IllegalArgumentException(rwEx.getMessage());
}
return pcExpr;
}
protected Pointcut resolvePointcutExpression(String expression, Class inScope, PointcutParameter[] formalParameters) {
try {
PatternParser parser = new PatternParser(expression);
parser.setPointcutDesignatorHandlers(pointcutDesignators, world);
Pointcut pc = parser.parsePointcut(); //第四步
validateAgainstSupportedPrimitives(pc, expression);
IScope resolutionScope = buildResolutionScope((inScope == null ? Object.class : inScope), formalParameters);
pc = pc.resolve(resolutionScope);
return pc;
} catch (ParserException pEx) {
throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
}
}
public Pointcut parsePointcut() {
//第五步,最关键的一步
Pointcut p = parseAtomicPointcut();
if (maybeEat("&&")) {
p = new AndPointcut(p, parseNotOrPointcut());
}
if (maybeEat("||")) {
p = new OrPointcut(p, parsePointcut());
}
return p;
}
//根据切面注解的value属性的值上的特殊字符串,解析成不同的Pointcut的实例
private Pointcut parseAtomicPointcut() {
if (maybeEat("!")) { //解析字符串以"!"开头
int startPos = tokenSource.peek(-1).getStart();
Pointcut p = new NotPointcut(parseAtomicPointcut(), startPos);
return p;
}
if (maybeEat("(")) { //解析value值以"("开头
Pointcut p = parsePointcut();
eat(")");
return p;
}
if (maybeEat("@")) { //解析value值以"@"开头
int startPos = tokenSource.peek().getStart();
Pointcut p = parseAnnotationPointcut();
int endPos = tokenSource.peek(-1).getEnd();
p.setLocation(sourceContext, startPos, endPos);
return p;
}
int startPos = tokenSource.peek().getStart();
Pointcut p = parseSinglePointcut(); //如果均不是
int endPos = tokenSource.peek(-1).getEnd();
p.setLocation(sourceContext, startPos, endPos);
return p;
}
//解析value值以"@"开头
public Pointcut parseAnnotationPointcut() {
int start = tokenSource.getIndex();
IToken t = tokenSource.peek();
String kind = parseIdentifier();
IToken possibleTypeVariableToken = tokenSource.peek();
String[] typeVariables = maybeParseSimpleTypeVariableList();
if (typeVariables != null) {
String message = "(";
assertNoTypeVariables(typeVariables, message, possibleTypeVariableToken);
}
tokenSource.setIndex(start);
if (kind.equals("annotation")) {
return parseAtAnnotationPointcut();
} else if (kind.equals("args")) {
return parseArgsAnnotationPointcut();
} else if (kind.equals("this") || kind.equals("target")) {
return parseThisOrTargetAnnotationPointcut();
} else if (kind.equals("within")) {
return parseWithinAnnotationPointcut();
} else if (kind.equals("withincode")) {
return parseWithinCodeAnnotationPointcut();
}
throw new ParserException("pointcut name", t);
}
//解析普通的单例的切入点实例
public Pointcut parseSinglePointcut() {
int start = tokenSource.getIndex();
IToken t = tokenSource.peek();
Pointcut p = t.maybeGetParsedPointcut();
if (p != null) {
tokenSource.next();
return p;
}
String kind = parseIdentifier();
// IToken possibleTypeVariableToken = tokenSource.peek();
// String[] typeVariables = maybeParseSimpleTypeVariableList();
if (kind.equals("execution") || kind.equals("call") || kind.equals("get") || kind.equals("set")) {
p = parseKindedPointcut(kind);
} else if (kind.equals("args")) {
p = parseArgsPointcut();
} else if (kind.equals("this")) {
p = parseThisOrTargetPointcut(kind);
} else if (kind.equals("target")) {
p = parseThisOrTargetPointcut(kind);
} else if (kind.equals("within")) {
p = parseWithinPointcut();
} else if (kind.equals("withincode")) {
p = parseWithinCodePointcut();
} else if (kind.equals("cflow")) {
p = parseCflowPointcut(false);
} else if (kind.equals("cflowbelow")) {
p = parseCflowPointcut(true);
} else if (kind.equals("adviceexecution")) {
eat("(");
eat(")");
p = new KindedPointcut(Shadow.AdviceExecution, new SignaturePattern(Member.ADVICE, ModifiersPattern.ANY,
TypePattern.ANY, TypePattern.ANY, NamePattern.ANY, TypePatternList.ANY, ThrowsPattern.ANY,
AnnotationTypePattern.ANY));
} else if (kind.equals("handler")) {
eat("(");
TypePattern typePat = parseTypePattern(false, false);
eat(")");
p = new HandlerPointcut(typePat);
} else if (kind.equals("lock") || kind.equals("unlock")) {
p = parseMonitorPointcut(kind);
} else if (kind.equals("initialization")) {
eat("(");
SignaturePattern sig = parseConstructorSignaturePattern();
eat(")");
p = new KindedPointcut(Shadow.Initialization, sig);
} else if (kind.equals("staticinitialization")) {
eat("(");
TypePattern typePat = parseTypePattern(false, false);
eat(")");
p = new KindedPointcut(Shadow.StaticInitialization, new SignaturePattern(Member.STATIC_INITIALIZATION,
ModifiersPattern.ANY, TypePattern.ANY, typePat, NamePattern.ANY, TypePatternList.EMPTY, ThrowsPattern.ANY,
AnnotationTypePattern.ANY));
} else if (kind.equals("preinitialization")) {
eat("(");
SignaturePattern sig = parseConstructorSignaturePattern();
eat(")");
p = new KindedPointcut(Shadow.PreInitialization, sig);
} else if (kind.equals("if")) {
// - annotation style only allows if(), if(true) or if(false)
// - if() means the body of the annotated method represents the if expression
// - anything else is an error because code cannot be put into the if()
// - code style will already have been processed and the call to maybeGetParsedPointcut()
// at the top of this method will have succeeded.
eat("(");
if (maybeEatIdentifier("true")) {
eat(")");
p = new IfPointcut.IfTruePointcut();
} else if (maybeEatIdentifier("false")) {
eat(")");
p = new IfPointcut.IfFalsePointcut();
} else {
if (!maybeEat(")")) {
throw new ParserException(
"in annotation style, if(...) pointcuts cannot contain code. Use if() and put the code in the annotated method",
t);
}
// TODO - Alex has some token stuff going on here to get a readable name in place of ""...
p = new IfPointcut("");
}
} else {
boolean matchedByExtensionDesignator = false;
// see if a registered handler wants to parse it, otherwise
// treat as a reference pointcut
for (PointcutDesignatorHandler pcd : pointcutDesignatorHandlers) {
if (pcd.getDesignatorName().equals(kind)) {
p = parseDesignatorPointcut(pcd);
matchedByExtensionDesignator = true;
}
}
if (!matchedByExtensionDesignator) {
tokenSource.setIndex(start);
p = parseReferencePointcut();
}
}
return p;
}
}
切入点表达式实例即PointcutExpression验证一个类是否匹配表达式,主要是根据其内部持有的Pointcut实例来匹配验证,而Pointcut实例则根据切面注解的value值如@After(“@args(…..)”)来生成相应的Pointcut实现类,以这个实现类来验证:
代码块6
public class PointcutExpressionImpl implements PointcutExpression {
private Pointcut pointcut;
private String expression;
public boolean couldMatchJoinPointsInType(Class aClass) {
ResolvedType matchType = world.resolve(aClass.getName());
if (matchType.isMissing() && (world instanceof ReflectionWorld)) {
// Class is a generated class that cannot be 'looked up' via getResource.
// For example a proxy or lambda.
// Use the class itself in this case
matchType = ((ReflectionWorld)world).resolveUsingClass(aClass);
}
ReflectionFastMatchInfo info = new ReflectionFastMatchInfo(matchType, null, this.matchContext, world);
//关键看这步,不同的实现类返回不同的值,maybeTrue代表是可能为真,比如很多适配的原则是在方法上的,那么这步就会返回true
//有些规则是要在类上做匹配的,则会在此步骤做验证,通过后在方法上的验证直接返回true
boolean couldMatch = pointcut.fastMatch(info).maybeTrue();
if (MATCH_INFO) {
System.out.println("MATCHINFO: fast match for '" + this.expression + "' against '" + aClass.getName() + "': "
+ couldMatch);
}
return couldMatch;
}
}