Spring AOP源码分析(深入原理)创建通知、切面匹配与创建代理

37 篇文章 1 订阅
29 篇文章 1 订阅

在之前的三篇文章中已经梳理了spring aop的核心内容:

  1. AnnotationAwareAspectJAutoProxyCreator的注入
  2. AnnotationAwareAspectJAutoProxyCreator获取Advisor集、bean匹配、创建代理等
  3. 切面拦截器的执行流程

但是由于时间和个人水平限制,有几个内容记录的不是很详细,比如:

  • 事件通知何时创建
  • cglib代理的原理
  • Pointcut如何匹配

本文将继续阅读spring aop源码,并结合示例代码,深入分析上述的问题。

创建事件通知

创建代理回顾

前面的文章分析过,创建代理入口在AbstractAutoProxyCreator的postProcessAfterInitialization方法:

// Create a proxy with the configured interceptors
// if the bean is identified as one to proxy by the subclass.
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	// 略

	// 获取通知
	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;
}

// Return whether the given bean is to be proxied,
// what additional advices (e.g. AOP Alliance interceptors) and advisors to apply.
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();
}

// Find all eligible Advisors for auto-proxying this class.
// 查找可以用于当前bean的所有通知
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 查找所有通知,此方法里面有查找、创建通知的逻辑
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 查找可以用于当前bean的所有通知,下一章节分析这个方法
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	extendAdvisors(eligibleAdvisors);
	if (!eligibleAdvisors.isEmpty()) {
        // 排序
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
	}
	return eligibleAdvisors;
}

查找所有通知集

查找、创建通知的逻辑在findCandidateAdvisors方法中:

// Find all candidate Advisors to use in auto-proxying.
protected List<Advisor> findCandidateAdvisors() {
	// Add all the Spring advisors found according to superclass rules.
	List<Advisor> advisors = super.findCandidateAdvisors();
	// Build Advisors for all AspectJ aspects in the bean factory.
	if (this.aspectJAdvisorsBuilder != null) {
		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
	}
	return advisors;
}

aspectJAdvisorsBuilder.buildAspectJAdvisors方法:

  • Look for AspectJ-annotated aspect beans in the current bean factory, and return to a list of Spring AOP Advisors representing them.
  • Creates a Spring Advisor for each AspectJ advice method.
public List<Advisor> buildAspectJAdvisors() {
	List<String> aspectNames = this.aspectBeanNames;

	if (aspectNames == null) {
		synchronized (this) {
			aspectNames = this.aspectBeanNames;
			if (aspectNames == null) {
				List<Advisor> advisors = new ArrayList<>();
				aspectNames = new ArrayList<>();
				String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
						this.beanFactory, Object.class, true, false);
				for (String beanName : beanNames) {
					if (!isEligibleBean(beanName)) {
						continue;
					}
					// We must be careful not to instantiate beans eagerly as in this case they
					// would be cached by the Spring container but would not have been weaved.
					Class<?> beanType = this.beanFactory.getType(beanName, false);
					if (beanType == null) {
						continue;
					}
                    // 判断是切面bean
					if (this.advisorFactory.isAspect(beanType)) {
						aspectNames.add(beanName);
						AspectMetadata amd = new AspectMetadata(beanType, beanName);
						if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
							MetadataAwareAspectInstanceFactory factory =
									new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
							List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
							if (this.beanFactory.isSingleton(beanName)) {
								this.advisorsCache.put(beanName, classAdvisors);
							} else {
								this.aspectFactoryCache.put(beanName, factory);
							}
							advisors.addAll(classAdvisors);
						} else {
							// Per target or per this.
							if (this.beanFactory.isSingleton(beanName)) {
								throw new IllegalArgumentException("...");
							}
							MetadataAwareAspectInstanceFactory factory =
									new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
							this.aspectFactoryCache.put(beanName, factory);
							advisors.addAll(this.advisorFactory.getAdvisors(factory));
						}
					}
				}
				this.aspectBeanNames = aspectNames;
				return advisors;
			}
		}
	}

	if (aspectNames.isEmpty()) {
		return Collections.emptyList();
	}
	List<Advisor> advisors = new ArrayList<>();
	for (String aspectName : aspectNames) {
		List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
		if (cachedAdvisors != null) {
			advisors.addAll(cachedAdvisors);
		} else {
			MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
			advisors.addAll(this.advisorFactory.getAdvisors(factory));
		}
	}
	return advisors;
}

getAdvisors

ReflectiveAspectJAdvisorFactory.getAdvisors方法:

// Build Spring AOP Advisors for all annotated At-AspectJ methods on the specified aspect instance.
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
	Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
	String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
	validate(aspectClass);

	// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
	// so that it will only instantiate once.
	MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
			new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

	List<Advisor> advisors = new ArrayList<>();
    // 获取到Aspect Bean中的切面方法,比如被@Before、@After等
	for (Method method : getAdvisorMethods(aspectClass)) {
        // 创建Advisor
		Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
		if (advisor != null) {
			advisors.add(advisor);
		}
	}

	// If it's a per target aspect, emit the dummy instantiating aspect.
    // Aspect Bean为prototype时执行此分支
	if (!advisors.isEmpty() && 
        lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
		Advisor instantiationAdvisor = 
            new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
		advisors.add(0, instantiationAdvisor);
	}

	// Find introduction fields.
    // IntroductionAdvisor和@DeclareParents注解支持
	for (Field field : aspectClass.getDeclaredFields()) {
		Advisor advisor = getDeclareParentsAdvisor(field);
		if (advisor != null) {
			advisors.add(advisor);
		}
	}

	return advisors;
}

// Build a Spring AOP Advisor for the given AspectJ advice method.
public Advisor getAdvisor(
    	Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
		int declarationOrderInAspect, String aspectName) {

    // 创建AspectJExpressionPointcut
    // 这个Pointcut实现支持@annotation(..)、execution(..)表达式
	AspectJExpressionPointcut expressionPointcut = getPointcut(
			candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
	if (expressionPointcut == null) {
		return null;
	}

    // 创建Advisor
	return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
			this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

创建Advisor和Advice

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
		Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
		MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

	this.declaredPointcut = declaredPointcut;
	this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
	this.methodName = aspectJAdviceMethod.getName();
	this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
	this.aspectJAdviceMethod = aspectJAdviceMethod;
    // ReflectiveAspectJAdvisorFactory对象
	this.aspectJAdvisorFactory = aspectJAdvisorFactory;
	this.aspectInstanceFactory = aspectInstanceFactory;
	this.declarationOrder = declarationOrder;
	this.aspectName = aspectName;

	if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
		// 略
	} else {
		// A singleton aspect.
		this.pointcut = this.declaredPointcut;
		this.lazy = false;
        // 创建Advisor
		this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
	}
}

private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
	Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
			this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
	return (advice != null ? advice : EMPTY_ADVICE);
}

创建Advice

创建Advice

aspectJAdvisorFactory.getAdvice创建Advice对象:

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
		MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

	Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
	validate(candidateAspectClass);

	AspectJAnnotation<?> aspectJAnnotation =
			AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
	if (aspectJAnnotation == null) {
		return null;
	}

	// 判断目标类是Aspect
	if (!isAspect(candidateAspectClass)) {
		throw new AopConfigException("...");
	}

	AbstractAspectJAdvice springAdvice;

	switch (aspectJAnnotation.getAnnotationType()) {
		case AtPointcut:
			// 方法被Pointcut标注,什么都不做
			return null;
		case AtAround:
            // Around通知
			springAdvice = new AspectJAroundAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtBefore:
            // Before通知
			springAdvice = new AspectJMethodBeforeAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtAfter:
            // After通知
			springAdvice = new AspectJAfterAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			break;
		case AtAfterReturning:
            // AfterReturning通知
			springAdvice = new AspectJAfterReturningAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                // 设置return注入参数名
				springAdvice.setReturningName(afterReturningAnnotation.returning());
			}
			break;
		case AtAfterThrowing:
            // AfterThrowing通知
			springAdvice = new AspectJAfterThrowingAdvice(
					candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
			AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
			if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                // 设置throw注入参数名
				springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
			}
			break;
		default:
			throw new UnsupportedOperationException("...");
	}

	// Now to configure the advice...
	springAdvice.setAspectName(aspectName);
	springAdvice.setDeclarationOrder(declarationOrder);
	String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
	if (argNames != null) {
        // 切面方法参数列表名称
		springAdvice.setArgumentNamesFromStringArray(argNames);
	}
	springAdvice.calculateArgumentBindings();

	return springAdvice;
}

AspectJAroundAdvice

在这里插入图片描述

AspectJMethodBeforeAdvice

在这里插入图片描述

AspectJAfterAdvice

在这里插入图片描述

AspectJAfterReturningAdvice

在这里插入图片描述

AspectJAfterThrowingAdvice

在这里插入图片描述

匹配事件通知

上一章节,介绍了创建、查找通知的逻辑,查找到通知后,就需要将通知与当前Bean进行匹配,以确定是否需要为当前Bean创建代理。

入口

// 查找可以用于当前bean的所有通知
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 查找可以用于当前bean的所有通知
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	extendAdvisors(eligibleAdvisors);
	if (!eligibleAdvisors.isEmpty()) {
        // 排序
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
	}
	return eligibleAdvisors;
}

// Search the given candidate Advisors to find all Advisors that can apply to the specified bean.
protected List<Advisor> findAdvisorsThatCanApply(
		List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
	ProxyCreationContext.setCurrentProxiedBeanName(beanName);
	try {
		return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
	} finally {
		ProxyCreationContext.setCurrentProxiedBeanName(null);
	}
}

通知匹配

AopUtils.findAdvisorsThatCanApply方法:

// Determine the sublist of the candidateAdvisors list that is applicable to the given class.
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
	List<Advisor> eligibleAdvisors = new ArrayList<>();
    // 匹配IntroductionAdvisor
	for (Advisor candidate : candidateAdvisors) {
		if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
			eligibleAdvisors.add(candidate);
		}
	}
	boolean hasIntroductions = !eligibleAdvisors.isEmpty();
    // 匹配非IntroductionAdvisor
	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) {
	return canApply(advisor, targetClass, false);
}

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) {
        // 在上一章节介绍了,spring aop创建的是InstantiationModelAwarePointcutAdvisorImpl对象
        // Pointcut是AspectJExpressionPointcut对象
		PointcutAdvisor pca = (PointcutAdvisor) advisor;
		return canApply(pca.getPointcut(), targetClass, hasIntroductions);
	} else {
		return true;
	}
}

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
	if (!pc.getClassFilter().matches(targetClass)) {
		return false;
	}

    // methodMatcher是AspectJExpressionPointcut对象
    // 里面封装着切面表达式和切入点信息
	MethodMatcher methodMatcher = pc.getMethodMatcher();
	if (methodMatcher == MethodMatcher.TRUE) {
		return true;
	}

	IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
	if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
		introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
	}

	Set<Class<?>> classes = new LinkedHashSet<>();
	if (!Proxy.isProxyClass(targetClass)) {
		classes.add(ClassUtils.getUserClass(targetClass));
	}
	classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(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;
}

AspectJExpressionPointcut

在这里插入图片描述

实现了AbstractExpressionPointcut和IntroductionAwareMethodMatcher接口。

这个类里面封装着:

  • PointcutExpression - 当前切面表达式对象,这个类由aspectj提供,底层使用aspectj框架的api做的切面匹配
  • String expression - 当前切面表达式字符串
  • BeanFactory - spring工厂
  • Class pointcutDeclarationScope - 当前切面类,可以用于获取@Pointcut信息

看一下match方法:

public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
    // 封装PointcutExpression
	obtainPointcutExpression();
    // 匹配
	ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);

	if (shadowMatch.alwaysMatches()) {
		return true;
	} else if (shadowMatch.neverMatches()) {
		return false;
	} else {
		if (hasIntroductions) {
			return true;
		}
		RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
		return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
	}
}

private PointcutExpression obtainPointcutExpression() {
	if (this.pointcutExpression == null) {
		this.pointcutClassLoader = determinePointcutClassLoader();
        // 构建PointcutExpression
		this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
	}
	return this.pointcutExpression;
}

// 构建PointcutExpression
// 使用aspectj框架的api
// 不做深入解析了
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]);
	}
    // 构建PointcutExpression
    // 第1个参数是切面字符串表达式
    // 第2个参数是切面类Class对象,用于获取@Pointcut信息
    // 第3个参数是切面的参数列表
	return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()),
			this.pointcutDeclarationScope, pointcutParameters);
}

private ShadowMatch getTargetShadowMatch(Method method, Class<?> targetClass) {
	// ...
    // 使用PointcutExpression来匹配目标方法
	return getShadowMatch(targetMethod, method);
}

匹配目标方法的逻辑封装在aspectj框架中,此处就不继续深入分析了,只使用一个例子看一下aspectj框架如何匹配切面和目标方法。

Aspectj框架PointcutExpression示例

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParameter;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive;
import org.aspectj.weaver.tools.ShadowMatch;
import org.junit.Test;
import org.springframework.asm.ClassReader;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.asm.SpringAsmInfo;
import org.springframework.asm.Type;
import org.springframework.util.ClassUtils;

public class AspectjExpressionPointcutTest {

  private final static Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>() {{
    add(PointcutPrimitive.EXECUTION);
    add(PointcutPrimitive.ARGS);
    add(PointcutPrimitive.REFERENCE);
    add(PointcutPrimitive.THIS);
    add(PointcutPrimitive.TARGET);
    add(PointcutPrimitive.WITHIN);
    add(PointcutPrimitive.AT_ANNOTATION);
    add(PointcutPrimitive.AT_WITHIN);
    add(PointcutPrimitive.AT_ARGS);
    add(PointcutPrimitive.AT_TARGET);
  }};

  // 演示@annotation(..)表达式匹配
  @Test
  public void testAnnotation() throws Exception {

    // 创建PointcutParser
    PointcutParser parser = PointcutParser
        .getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
            SUPPORTED_PRIMITIVES, AspectjExpressionPointcutTest.class.getClassLoader());

    // 获取目标方法
    Method method = LogService.class.getDeclaredMethod("testServiceLog");

    // 获取切面方法
    Method before = ServiceAop.class.getDeclaredMethod("before", ServiceLog.class);
    // 获取切面方法参数列表
    Parameter[] parameters = before.getParameters();
    // 使用asm获取切面方法参数名
    String[] parameterNames = getParameterNames(before);

    // 构建aspectj切面解析器
    // 参数列表只有一个ServiceLog sl
    PointcutParameter[] pointcutParameters = new PointcutParameter[parameters.length];
    for (int i = 0; i < pointcutParameters.length; i++) {
      pointcutParameters[i] = parser.createPointcutParameter(
          parameterNames[i], parameters[i].getType());
    }
    PointcutExpression pointcutExpression = parser
        .parsePointcutExpression("@annotation(sl)", ServiceAop.class, pointcutParameters);

    // 使用aspectj切面解析器判断目标方法与切面方法是否匹配
    ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);

    System.out.println(shadowMatch.alwaysMatches());
    System.out.println(shadowMatch.neverMatches());
    System.out.println(shadowMatch.maybeMatches());
  }

  // 演示@execution(..)表达式匹配
  @Test
  public void testExecution() throws Exception {

    PointcutParser parser = PointcutParser
        .getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
            SUPPORTED_PRIMITIVES, AspectjExpressionPointcutTest.class.getClassLoader());

    // 获取目标方法
    Method method = LogService.class.getDeclaredMethod("testServiceLog1", List.class);

    // 构建aspectj切面解析器
    // 此时需要ServiceAop.class中存在serviceAopPointCut()切入点
    PointcutExpression pointcutExpression = parser.parsePointcutExpression(
        "serviceAopPointCut()",
        ServiceAop.class, new PointcutParameter[]{});

    // 使用aspectj切面解析器判断目标方法与切面方法是否匹配
    ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);

    System.out.println(shadowMatch.alwaysMatches());
    System.out.println(shadowMatch.neverMatches());
    System.out.println(shadowMatch.maybeMatches());
  }

  private static String[] getParameterNames(Method before) throws IOException {
    InputStream is = ServiceAop.class.getClassLoader().getResourceAsStream(
        "org/net5ijy/mybatis/test/AspectjExpressionPointcutTest$ServiceAop.class");
    assert is != null;
    ClassReader classReader = new ClassReader(is);
    Map<Executable, String[]> map = new ConcurrentHashMap<>(32);
    classReader.accept(new ParameterNameDiscoveringVisitor(ServiceAop.class, map), 0);
    return map.get(before);
  }

  public static class ServiceAop {

    @Pointcut("execution(public * org.net5ijy.mybatis.test..*.*(..))")
    public void serviceAopPointCut() {}

    public void before(ServiceLog sl) {
      System.out.println("ServiceAop.before");
      System.out.printf("ServiceAop.before: %s\n", sl.toString());
    }
  }

  public static class LogService {

    @ServiceLog
    public void testServiceLog() {
      System.out.println(this.getClass().getName() + ".testServiceLog");
    }

    public void testServiceLog1(List<String> list) {
      System.out.println(this.getClass().getName() + ".testServiceLog1");
    }
  }

  @Target(ElementType.METHOD)
  @Retention(RetentionPolicy.RUNTIME)
  public @interface ServiceLog {}

  /**
   * 以下为从spring源码拷贝的asm工具类
   */

  private static class ParameterNameDiscoveringVisitor extends ClassVisitor {

    private static final String STATIC_CLASS_INIT = "<clinit>";

    private final Class<?> clazz;

    private final Map<Executable, String[]> executableMap;

    public ParameterNameDiscoveringVisitor(Class<?> clazz,
        Map<Executable, String[]> executableMap) {
      super(SpringAsmInfo.ASM_VERSION);
      this.clazz = clazz;
      this.executableMap = executableMap;
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature,
        String[] exceptions) {
      if (!isSyntheticOrBridged(access) && !STATIC_CLASS_INIT.equals(name)) {
        return new LocalVariableTableVisitor(this.clazz, this.executableMap, name, desc,
            isStatic(access));
      }
      return null;
    }

    private static boolean isSyntheticOrBridged(int access) {
      return (((access & Opcodes.ACC_SYNTHETIC) | (access & Opcodes.ACC_BRIDGE)) > 0);
    }

    private static boolean isStatic(int access) {
      return ((access & Opcodes.ACC_STATIC) > 0);
    }
  }

  private static class LocalVariableTableVisitor extends MethodVisitor {

    private static final String CONSTRUCTOR = "<init>";

    private final Class<?> clazz;

    private final Map<Executable, String[]> executableMap;

    private final String name;

    private final Type[] args;

    private final String[] parameterNames;

    private final boolean isStatic;

    private boolean hasLvtInfo = false;

    /*
     * The nth entry contains the slot index of the LVT table entry holding the
     * argument name for the nth parameter.
     */
    private final int[] lvtSlotIndex;

    public LocalVariableTableVisitor(Class<?> clazz, Map<Executable, String[]> map, String name,
        String desc, boolean isStatic) {
      super(SpringAsmInfo.ASM_VERSION);
      this.clazz = clazz;
      this.executableMap = map;
      this.name = name;
      this.args = Type.getArgumentTypes(desc);
      this.parameterNames = new String[this.args.length];
      this.isStatic = isStatic;
      this.lvtSlotIndex = computeLvtSlotIndices(isStatic, this.args);
    }

    @Override
    public void visitLocalVariable(String name, String description, String signature, Label start,
        Label end, int index) {
      this.hasLvtInfo = true;
      for (int i = 0; i < this.lvtSlotIndex.length; i++) {
        if (this.lvtSlotIndex[i] == index) {
          this.parameterNames[i] = name;
        }
      }
    }

    @Override
    public void visitEnd() {
      if (this.hasLvtInfo || (this.isStatic && this.parameterNames.length == 0)) {
        // visitLocalVariable will never be called for static no args methods
        // which doesn't use any local variables.
        // This means that hasLvtInfo could be false for that kind of methods
        // even if the class has local variable info.
        this.executableMap.put(resolveExecutable(), this.parameterNames);
      }
    }

    private Executable resolveExecutable() {
      ClassLoader loader = this.clazz.getClassLoader();
      Class<?>[] argTypes = new Class<?>[this.args.length];
      for (int i = 0; i < this.args.length; i++) {
        argTypes[i] = ClassUtils.resolveClassName(this.args[i].getClassName(), loader);
      }
      try {
        if (CONSTRUCTOR.equals(this.name)) {
          return this.clazz.getDeclaredConstructor(argTypes);
        }
        return this.clazz.getDeclaredMethod(this.name, argTypes);
      } catch (NoSuchMethodException ex) {
        throw new IllegalStateException("Method [" + this.name +
            "] was discovered in the .class file but cannot be resolved in the class object", ex);
      }
    }

    private static int[] computeLvtSlotIndices(boolean isStatic, Type[] paramTypes) {
      int[] lvtIndex = new int[paramTypes.length];
      int nextIndex = (isStatic ? 0 : 1);
      for (int i = 0; i < paramTypes.length; i++) {
        lvtIndex[i] = nextIndex;
        if (isWideType(paramTypes[i])) {
          nextIndex += 2;
        } else {
          nextIndex++;
        }
      }
      return lvtIndex;
    }

    private static boolean isWideType(Type aType) {
      // float is not a wide type
      return (aType == Type.LONG_TYPE || aType == Type.DOUBLE_TYPE);
    }
  }
}

创建cglib代理

入口

在《spring-aop源码分析(2)_AnnotationAwareAspectJAutoProxyCreator后置处理器》一文中,我们了解到,spring使用CglibAopProxy.getProxy方法创建代理。

当时的那篇文章没有详细介绍这个过程,本文将继续深入分析一下,最后会给一个示例。

public Object getProxy(ClassLoader classLoader) {

	try {
		// ...

		// Configure CGLIB Enhancer...
		Enhancer enhancer = createEnhancer();
		if (classLoader != null) {
			enhancer.setClassLoader(classLoader);
			if (classLoader instanceof SmartClassLoader &&
					((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
				enhancer.setUseCache(false);
			}
		}
        // 继承的父类
		enhancer.setSuperclass(proxySuperClass);
        // 实现的接口
		enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
		enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
		enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));

        // 通过advisor创建cglib代理callback
        // 返回的是MethodInterceptor集:
        // aopInterceptor、targetInterceptor、EqualsInterceptor、HashCodeInterceptor等
		Callback[] callbacks = getCallbacks(rootClass);
		Class<?>[] types = new Class<?>[callbacks.length];
		for (int x = 0; x < types.length; x++) {
			types[x] = callbacks[x].getClass();
		}
		// 由于上面的callbacks是多个,此处的Filter将确定出最终使用哪个MethodInterceptor拦截目标方法
		enhancer.setCallbackFilter(
            new ProxyCallbackFilter(
				this.advised.getConfigurationOnlyCopy(),
                this.fixedInterceptorMap,
                this.fixedInterceptorOffset));
		enhancer.setCallbackTypes(types);

		// Generate the proxy class and create a proxy instance.
        // 使用cglib生成代理对象并返回
		return createProxyClassAndInstance(enhancer, callbacks);
	} catch (CodeGenerationException | IllegalArgumentException ex) {
		// throw new AopConfigException
	} catch (Throwable ex) {
		// throw new AopConfigException
	}
}

示例

public class SpringCglibDemo {

  public static void main(String[] args) throws InstantiationException, IllegalAccessException {

    // 设置cglib生成的class文件存放位置
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:/download");

    ClassLoader classLoader = SpringCglibDemo.class.getClassLoader();

    Enhancer enhancer = createEnhancer();

    // 设置目标类型
    enhancer.setSuperclass(LogService.class);

    enhancer.setClassLoader(classLoader);
    enhancer.setUseCache(false);
    enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));

    // callback集
    Callback[] callbacks = new Callback[]{
        new MyMethodInterceptor(),
        new MyMethodInterceptor2()
    };
    Class<?>[] types = new Class<?>[callbacks.length];
    for (int x = 0; x < types.length; x++) {
      types[x] = callbacks[x].getClass();
    }
    enhancer.setCallbackTypes(types);
    // Filter选择使用第1个MethodInterceptor拦截目标方法
    enhancer.setCallbackFilter(method -> 0);

    // 创建代理类并实例化
    Class<?> proxyClass = enhancer.createClass();
    Object proxyInstance = proxyClass.newInstance();

    // 设置callback
    ((Factory) proxyInstance).setCallbacks(callbacks);

    LogService o = (LogService) proxyInstance;
    o.testServiceLog();
  }

  private static Enhancer createEnhancer() {
    return new Enhancer();
  }

  private static class MyMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(
        Object enhancedConfigInstance, Method beanMethod,
        Object[] beanMethodArgs, MethodProxy cglibMethodProxy) throws Throwable {

      System.out.printf("MyMethodInterceptor %s args: %s\n",
          beanMethod.getName(), Arrays.toString(beanMethodArgs));

      return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
    }
  }

  private static class MyMethodInterceptor2 implements MethodInterceptor {

    @Override
    public Object intercept(
        Object enhancedConfigInstance, Method beanMethod,
        Object[] beanMethodArgs, MethodProxy cglibMethodProxy) throws Throwable {

      System.out.printf("MyMethodInterceptor2 %s args: %s\n",
          beanMethod.getName(), Arrays.toString(beanMethodArgs));

      return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
    }
  }
}

反编译cglib生成的class文件

cglib为目标类生成了一个子类,我们可以找到这个类的class文件,然后使用工具做反编译,得到下面的java文件,此处只记录相对重要的代码段,不做过多描述:

import java.lang.reflect.Method;
import org.net5ijy.mybatis.test.service.LogService;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class LogService$$EnhancerBySpringCGLIB$$e25335ef extends LogService implements Factory {
  private boolean CGLIB$BOUND;
  public static Object CGLIB$FACTORY_DATA;
  private static ThreadLocal CGLIB$THREAD_CALLBACKS;
  private static Callback[] CGLIB$STATIC_CALLBACKS;

  // MethodInterceptor相关字段,示例中是两个,spring aop是六个
  private MethodInterceptor CGLIB$CALLBACK_0;
  private MethodInterceptor CGLIB$CALLBACK_1;

  private static Object CGLIB$CALLBACK_FILTER;
  private static Method CGLIB$testServiceLog$0$Method;
  private static MethodProxy CGLIB$testServiceLog$0$Proxy;
  private static Object[] CGLIB$emptyArgs;
  private static Method CGLIB$equals$1$Method;
  private static MethodProxy CGLIB$equals$1$Proxy;
  private static Method CGLIB$toString$2$Method;
  private static MethodProxy CGLIB$toString$2$Proxy;
  private static Method CGLIB$hashCode$3$Method;
  private static MethodProxy CGLIB$hashCode$3$Proxy;
  private static Method CGLIB$clone$4$Method;
  private static MethodProxy CGLIB$clone$4$Proxy;

  static {
    try {
      LogService$$EnhancerBySpringCGLIB$$e25335ef.CGLIB$STATICHOOK1();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  static void CGLIB$STATICHOOK1() throws Exception {
    // 很多初始化代码,略
  }

  // 业务方法
  public final void testServiceLog() {
    // 因为我们的Filter返回0所以使用了CALLBACK_0来拦截目标方法
    MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
    if (methodInterceptor == null) {
      LogService$$EnhancerBySpringCGLIB$$e25335ef.CGLIB$BIND_CALLBACKS((Object)this);
      methodInterceptor = this.CGLIB$CALLBACK_0;
    }
    if (methodInterceptor != null) {
      try {
        // 执行拦截方法
        Object object = methodInterceptor.intercept(
                (Object)this, 
                CGLIB$testServiceLog$0$Method, 
                CGLIB$emptyArgs, 
                CGLIB$testServiceLog$0$Proxy);
      } catch (Throwable e) {
        throw new RuntimeException(e);
      }
      return;
    }
    super.testServiceLog();
  }

  public void setCallback(int n, Callback callback) {
    switch (n) {
      case 0: {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)callback;
        break;
      }
      case 1: {
        this.CGLIB$CALLBACK_1 = (MethodInterceptor)callback;
        break;
      }
    }
  }

  public void setCallbacks(Callback[] callbackArray) {
    this.CGLIB$CALLBACK_0 = (MethodInterceptor)callbackArray[0];
    Callback[] callbackArray2 = callbackArray;
    LogService$$EnhancerBySpringCGLIB$$e25335ef logService$$EnhancerBySpringCGLIB$$e25335ef = this;
    this.CGLIB$CALLBACK_1 = (MethodInterceptor)callbackArray[1];
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值