@aspectJ机制剖析

@aspectJ机制剖析

@aspectj通过修改字节码文件来实现目标方法的增强。

image

image

准备几个测试类:

MyAOPConfig

@Configuration
@ComponentScan("com.coding.spring.aop")
@EnableAspectJAutoProxy
public class MyAOPConfig {
}

MyAspectJDemo

package com.coding.spring.aop.aspectj;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAspectJDemo {

	@Pointcut("execution(* com.coding.spring.aop.bean.*.*(..))")
//	@Pointcut("execution(* com.coding.spring.aop.bean.MyAOPBean.say(..))")
	public void pointCut() {
		System.out.println("1111111111");
	}

	@Before("pointCut()")
	public void before() {
		System.out.println("========= before =========");
	}

	@After("pointCut()")
	public void after() {
		System.out.println("========= after =========");
	}

	@Around("pointCut()")
	public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
		System.out.println("========= around start =========");
		Object proceed;
		try {
			proceed = proceedingJoinPoint.proceed();
			System.out.println("========= around end =========");
			return proceed;
		} catch (Throwable throwable) {
			System.out.println("========= around error =========");
			throw throwable;
		}
	}

	@AfterReturning("pointCut()")
	public void afterReturning() {
		System.out.println("========= afterReturning =========");
	}

	@AfterThrowing("pointCut()")
	public void afterThrowing() {
		System.out.println("========= afterThrowing =========");
	}
}

MyAOPBean

package com.coding.spring.aop.bean;

import org.springframework.stereotype.Component;

@Component
public class MyAOPBean {

	public String say() {
		System.out.println("--enter MyAOPBean.say()->>>");
		// int i = 1 / 0;
		return "return say";
	}

//	public String say2() {
//		System.out.println("--enter MyAOPBean.say2()->>>");
//		return "return say2";
//	}

}

测试类:

	@Test
	public void testAOPFromCGLIBProxy() {
		ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyAOPConfig.class);
		MyAOPBean myAOPBean = applicationContext.getBean(MyAOPBean.class);
		String say = myAOPBean.say();
//		String say2 = myAOPBean.say2();
		System.out.println(say);
//		System.out.println(say2);
	}

原理剖析:

org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

AbstractAutoProxyCreator的对应实现

@Override
	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;
	}
/**
	 * * 如有必要,包装给定的 bean,即如果它有资格被代理。
	 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
	 * @param bean the raw bean instance
	 * @param beanName the name of the bean
	 * @param cacheKey the cache key for metadata access
	 * @return a proxy wrapping the bean, or the raw bean instance as-is
	 */
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		// 如果是 基础设施类(Pointcut、Advice、Advisor 等) 或 需要 skip, 则不需要增强
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		// 为目标 bean 查找合适的通知器
		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;
	}

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation

AbstractAutoProxyCreator的对应实现

@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
            // 判断是不是基础设施类
            // 如果是 基础设施类(Pointcut、Advice、Advisor 等) 或 需要 skip, 则不需要增强
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

		// Create proxy here if we have a custom TargetSource.
		// Suppresses unnecessary default instantiation of the target bean:
		// The TargetSource will handle target instances in a custom fashion.
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		return null;
	}

org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip

@Override
	protected boolean shouldSkip(Class<?> beanClass, String beanName) {
		// TODO: Consider optimization by caching the list of the aspect names
		// 获取候选 Advisor
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		for (Advisor advisor : candidateAdvisors) {
			if (advisor instanceof AspectJPointcutAdvisor &&
					((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
				return true;
			}
		}
		return super.shouldSkip(beanClass, beanName);
	}

org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors

	@Override
	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;
	}

org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors

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<>();
                    // 获取spring容器中的所有bean实例对应的名称
					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是被@AspectJ注解进行修饰
						if (this.advisorFactory.isAspect(beanType)) {
                            // 将@AspectJ修饰的bean的名称添加到List<String> aspectNames集合中
							aspectNames.add(beanName); // beanName: myAspectJDemo
							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);
								}
                                // 通过上面的逻辑进行查找,将所有的切面逻辑都添加到List<Advisor> advisor集合中
								advisors.addAll(classAdvisors);
							}
							else {
								// Per target or per this.
								if (this.beanFactory.isSingleton(beanName)) {
									throw new IllegalArgumentException("Bean with name '" + beanName +
											"' is a singleton, but aspect instantiation model is not singleton");
								}
								MetadataAwareAspectInstanceFactory factory =
										new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
								this.aspectFactoryCache.put(beanName, factory);
								advisors.addAll(this.advisorFactory.getAdvisors(factory));
							}
						}
					}
					this.aspectBeanNames = aspectNames;
                    // 里面放的是这些玩意
                   // 0 = {InstantiationModelAwarePointcutAdvisorImpl@4231} expression [pointCut()]; advice method [public java.lang.Object com.coding.spring.aop.aspectj.MyAspectJDemo.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; 
// 1 = {InstantiationModelAwarePointcutAdvisorImpl@4232} expression [pointCut()]; advice method [public void com.coding.spring.aop.aspectj.MyAspectJDemo.before()]; 
// 2 = {InstantiationModelAwarePointcutAdvisorImpl@4233} expression [pointCut()]; advice method [public void com.coding.spring.aop.aspectj.MyAspectJDemo.after()]; 
// 3 = {InstantiationModelAwarePointcutAdvisorImpl@4234} expression [pointCut()]; advice method [public void com.coding.spring.aop.aspectj.MyAspectJDemo.afterReturning()]; 
// 4 = {InstantiationModelAwarePointcutAdvisorImpl@4235} expression [pointCut()]; advice method [public void com.coding.spring.aop.aspectj.MyAspectJDemo.afterThrowing()]; 
					return advisors; // 将切面逻辑集合进行返回
				}
			}
		}

通过以上步骤已经获取到了所有的通知器(也就是切面方法)List

// 为目标 bean 查找合适的通知器

getAdvicesAndAdvisorsForBean()逻辑

org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean

@Override
	@Nullable
	protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

		// 查找所有符合条件的通知器 封装成 Advisor 的集合
		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();
		// 筛选
		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 {
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}

org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new ArrayList<>();
		for (Advisor candidate : candidateAdvisors) {
			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;
            // 点进去
			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");
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}

		MethodMatcher methodMatcher = pc.getMethodMatcher();
		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<>();
		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;
	}

org.springframework.aop.aspectj.AspectJExpressionPointcut#matches(java.lang.reflect.Method, java.lang.Class<?>, boolean)

@Override
	public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
		obtainPointcutExpression();
		ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);

		// 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.
		if (shadowMatch.alwaysMatches()) {
			return true;
		}
		else if (shadowMatch.neverMatches()) {
			return false;
		}
		else {
			// the maybe case
			if (hasIntroductions) {
				return true;
			}
			// 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));
		}
	}
private ShadowMatch getTargetShadowMatch(Method method, Class<?> targetClass) {
		Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
		if (targetMethod.getDeclaringClass().isInterface()) {
			// Try to build the most specific interface possible for inherited methods to be
			// considered for sub-interface matches as well, in particular for proxy classes.
			// Note: AspectJ is only going to take Method.getDeclaringClass() into account.
			Set<Class<?>> ifcs = ClassUtils.getAllInterfacesForClassAsSet(targetClass);
			if (ifcs.size() > 1) {
				try {
					Class<?> compositeInterface = ClassUtils.createCompositeInterface(
							ClassUtils.toClassArray(ifcs), targetClass.getClassLoader());
					targetMethod = ClassUtils.getMostSpecificMethod(targetMethod, compositeInterface);
				}
				catch (IllegalArgumentException ex) {
					// Implemented interfaces probably expose conflicting method signatures...
					// Proceed with original target method.
				}
			}
		}
        // 点进去	
		return getShadowMatch(targetMethod, method);
	}
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<>(32);

private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
		// Avoid lock contention for known Methods through concurrent access...
		ShadowMatch shadowMatch = this.shadowMatchCache.get(targetMethod);
		if (shadowMatch == null) {
			synchronized (this.shadowMatchCache) {
				// Not found - now check again with full lock...
				PointcutExpression fallbackExpression = null;
				shadowMatch = this.shadowMatchCache.get(targetMethod);
				if (shadowMatch == null) {
					Method methodToMatch = targetMethod;
					try {
						try {
                            // 进行匹配 点进去
                            // 匹配上,就是YES,如果没有匹配上,就是NO
							shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch);
						}
						catch (ReflectionWorldException ex) {
							// Failed to introspect target method, probably because it has been loaded
							// in a special ClassLoader. Let's try the declaring ClassLoader instead...
							try {
								fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
								if (fallbackExpression != null) {
									shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
								}
							}
							catch (ReflectionWorldException ex2) {
								fallbackExpression = null;
							}
						}
						if (targetMethod != originalMethod && (shadowMatch == null ||
								(shadowMatch.neverMatches() && Proxy.isProxyClass(targetMethod.getDeclaringClass())))) {
							// Fall back to the plain original method in case of no resolvable match or a
							// negative match on a proxy class (which doesn't carry any annotations on its
							// redeclared methods).
							methodToMatch = originalMethod;
							try {
								shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch);
							}
							catch (ReflectionWorldException ex) {
								// Could neither introspect the target class nor the proxy class ->
								// let's try the original method's declaring class before we give up...
								try {
									fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
									if (fallbackExpression != null) {
										shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
									}
								}
								catch (ReflectionWorldException ex2) {
									fallbackExpression = null;
								}
							}
						}
					}
					catch (Throwable ex) {
						// Possibly AspectJ 1.8.10 encountering an invalid signature
						logger.debug("PointcutExpression matching rejected target method", ex);
						fallbackExpression = null;
					}
					if (shadowMatch == null) {
						shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
					}
					else if (shadowMatch.maybeMatches() && fallbackExpression != null) {
						shadowMatch = new DefensiveShadowMatch(shadowMatch,
								fallbackExpression.matchesMethodExecution(methodToMatch));
					}
                    // 将该方法的匹配结果放到map集合中
                    // targetMethod:方法
                    // shadowMatch:YES 匹配成功 NO 没有匹配上
					this.shadowMatchCache.put(targetMethod, shadowMatch);
				}
			}
		}
		return shadowMatch;
	}

image

org.aspectj.weaver.internal.tools.PointcutExpressionImpl#matchesMethodExecution

    public ShadowMatch matchesMethodExecution(Method aMethod) {
        ShadowMatch match = this.matchesExecution(aMethod);
        return match;
    }
    private ShadowMatch matchesExecution(Member aMember) {
        Shadow s = ReflectionShadow.makeExecutionShadow(this.world, aMember, this.matchContext);
        ShadowMatchImpl sm = this.getShadowMatch(s);
        sm.setSubject(aMember);
        sm.setWithinCode((Member)null);
        sm.setWithinType(aMember.getDeclaringClass());
        return sm;
    }

image

image

总的来说:在实例化之前就会将MyAspectJDemo类中所有的切面逻辑都封装到List集合中

0 = {InstantiationModelAwarePointcutAdvisorImpl@4218} "InstantiationModelAwarePointcutAdvisor: expression [pointCut()]; advice method [public java.lang.Object com.coding.spring.aop.aspectj.MyAspectJDemo.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; perClauseKind=SINGLETON"
1 = {InstantiationModelAwarePointcutAdvisorImpl@4219} "InstantiationModelAwarePointcutAdvisor: expression [pointCut()]; advice method [public void com.coding.spring.aop.aspectj.MyAspectJDemo.before()]; perClauseKind=SINGLETON"
2 = {InstantiationModelAwarePointcutAdvisorImpl@4220} "InstantiationModelAwarePointcutAdvisor: expression [pointCut()]; advice method [public void com.coding.spring.aop.aspectj.MyAspectJDemo.after()]; perClauseKind=SINGLETON"
3 = {InstantiationModelAwarePointcutAdvisorImpl@4221} "InstantiationModelAwarePointcutAdvisor: expression [pointCut()]; advice method [public void com.coding.spring.aop.aspectj.MyAspectJDemo.afterReturning()]; perClauseKind=SINGLETON"
4 = {InstantiationModelAwarePointcutAdvisorImpl@4222} "InstantiationModelAwarePointcutAdvisor: expression [pointCut()]; advice method [public void com.coding.spring.aop.aspectj.MyAspectJDemo.afterThrowing()]; perClauseKind=SINGLETON"

真正执行切面匹配逻辑的时候,是在初始化之后执行的。

这点一定要注意。面试可能会问到。

posted on 2024-08-28 17:43  ~码铃薯~  阅读(5)  评论(0编辑  收藏  举报

导航