Spring AOP源码篇一之 PointCut、Advice、Advisor学习

 基本概念:

  • AOP( Aspect-Oriented Programming):直译过来就是面向切面编程。最早是由AOP联盟(AOP Alliance)组织提出来的概念。解决的问题场景:将一些公共代码(日志记录,性能统计,安全控制,事务处理,异常处理等等)抽离出来,系统运行时可动态的应用到业务系统上。
  • 通知(Advice):也称增强,用于实现增强功能的.
  • 连接点(Joinpoint):在匹配目标的哪个位置做增强(before、after、around、return、throw).
  • 切点(Pointcut):用于匹配类或方法,一个切点可以对应多个连接点.
  • 织入 (Weaving):织入是把切面应用到目标对象,一般是通过代理对象实现.

   Spring中另外两个术语:

  •    Advisor:可以理解为是个组件,包含advice和pointcut两个组件
  •    Advised:它是spring AOP代理工厂的配置类接口,负责操作和管理 Advisor 的

Spring AOP与AspectJ:

        AOP是一种概念,Spring AOP和AspectJ都实现了AOP;Spring使用了AspectJ的部分API,生成代理对象Spring用的是JDK动态代理和CGLIB,而AspectJ是通过修改字节码来完成。

        Aspectj可参考另外博文:Java Agent【java探针】及AspectJ-优快云博客

PointCut继承体系:

Pointcut:有两部分组成:ClassFilter 、MethodMatcher;ClassFilter用于过滤Class;MethodMatcher用于匹配方法
package org.springframework.aop

import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;

/**
 * Pointcut由ClassFilter和MethodMatcher构成
 */
public interface Pointcut {

	/**
	 * 返回用于匹配Class的过滤器
	 */
	ClassFilter getClassFilter();

	/**
	 * 返回用于匹配方法的过滤器
	 */
	MethodMatcher getMethodMatcher();


	/**
	 * Pointcut实例: 切点可以匹配适用于所有Class以及方法
	 */
	Pointcut TRUE = TruePointcut.INSTANCE;
}
package org.spring.aop.pointcut;

import org.springframework.aop.IntroductionAdvisor;

/**
 * 切点与目标Class做匹配的过滤器
 *
 * 可以用作{@link Pointcut}的一部分功能,也可以用在引介增强{@link IntroductionAdvisor}匹配目标类
 * 在Spring AOP中主要是为目标类的原有方法增强功能,但是还有一种特殊增强叫引介增强,它不是增强原有的方法而是为原有目标类增加新的方法。
 */
public interface ClassFilter {

	/**
	 * 切点与目标Class进行匹配,判断切点与其是否匹配适用
	 */
	boolean matches(Class<?> clazz);

	/**
	 * ClassFilter实例,切点可以匹配适用于所有目标Class
	 */
	ClassFilter TRUE = TrueClassFilter.INSTANCE;
}
package org.springframework.aop;

import java.lang.reflect.Method;

/**
 * 切点与目标方法做匹配的过滤器
 */
public interface MethodMatcher {

	/**
	 * 静态匹配:只匹配方法对象
	 */
	boolean matches(Method method, Class<?> targetClass);

	/**
	 * 标注动态匹配的,如果返回true,进行动态匹配;返回false,不需要动态匹配
	 */
	boolean isRuntime();

	/**
	 * 动态匹配:匹配方法对象和方法参数对象
	 *  匹配方法:匹配名称、方法注解、方法返回类型、方法返回类型的注解
	 *  匹配参数:匹配参数个数、参数的类型、参数类型的注解
	 */
	boolean matches(Method method, Class<?> targetClass, Object[] args);

	/**
	 * MethodMatcher实例,切点可以匹配适用于所有目标方法
	 */
	MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
MethodMatcher有个特殊子类IntroductionAwareMethodMatcher,处理<引介增强>这种特殊情况。
<引介增强>与Spring AOP中的普通增强有些不同,普通增强是为目标类的原有方法增强功能,而引介增强是为目标类增加新方法来达到增强的能力
/**
 * MethodMatcher的一种特殊子接口。对方法进行匹配时,将<引介增强>考虑进去,做一些特殊逻辑处理
 */
public interface IntroductionAwareMethodMatcher extends MethodMatcher {
	/**
	 * 与目标方法进行静态匹配时.将<引介增强>因素考虑进去
	 * 
	 * @param hasIntroductions
	 * 		是否有<引介增强>
	 * @return
	 */
	boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions);

}

定义一个普通类,用于演示用例
import org.springframework.transaction.annotation.Transactional;

public class UserService {

    @Transactional
    public void say() {
        System.out.println("Hello World!!");
    }
}
自定义类,实现接口Pointcut, ClassFilter, MethodMatcher
import org.springframework.aop.Pointcut;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;

public class CustomPointcut implements Pointcut, ClassFilter, MethodMatcher {

    //---------------------------------------------------------------------
    // Implementation of Pointcut
    //---------------------------------------------------------------------
    @Override
    public ClassFilter getClassFilter() {
        return this;
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return this;
    }

    //---------------------------------------------------------------------
    // Implementation of ClassFilter
    //---------------------------------------------------------------------
    @Override
    public boolean matches(Class<?> clazz) {
        //判断目标类是否存在注解@Service
        if (clazz.isAnnotationPresent(Service.class)) {
            return true;
        }
        return false;
    }

    //---------------------------------------------------------------------
    // Implementation of MethodMatcher
    //---------------------------------------------------------------------
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        //判断目标方法是否存在注解@Transactional
        if (method.isAnnotationPresent(Transactional.class)) {
            return true;
        }
        return false;
    }

    @Override
    public boolean isRuntime() {
        return false;
    }

    @Override
    public boolean matches(Method method, Class<?> targetClass, Object[] args) {
        throw new UnsupportedOperationException("Illegal MethodMatcher usage");
    }
}
测试代码:
public static void main(String[] args) throws Exception {
        CustomPointcut pointcut = new CustomPointcut();
        boolean matchResult = pointcut.matches(UserService.class);
        System.out.println("ClassFilter.matches(Class<?>)===匹配结果==>" + matchResult);

        Method method = UserService.class.getDeclaredMethod("say", new Class[]{String.class});
        matchResult = pointcut.matches(method, UserService.class);
        System.out.println("MethodMatcher.matches(Method, Class<?>)===匹配结果==>" + matchResult);

        matchResult = pointcut.matches(method, UserService.class, new Class[]{String.class});
        System.out.println("MethodMatcher.matches(Method, Class<?>, args)===匹配结果==>" + matchResult);
    }

执行结果:

Spring2.0开始引入AspectJ,AspectJExpressionPointcut是Spring基于AspectJ表达式而实现的一个Pointcut,AspectJExpressionPointcut在目前spring中使用非常频繁,所以非常重要。
package org.springframework.aop.aspectj;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.weaver.BCException;
import org.aspectj.weaver.patterns.NamePattern;
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
import org.aspectj.weaver.reflect.ShadowMatchImpl;
import org.aspectj.weaver.tools.ContextBasedMatcher;
import org.aspectj.weaver.tools.FuzzyBoolean;
import org.aspectj.weaver.tools.JoinPointMatch;
import org.aspectj.weaver.tools.MatchingContext;
import org.aspectj.weaver.tools.PointcutDesignatorHandler;
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.springframework.aop.ClassFilter;
import org.springframework.aop.IntroductionAwareMethodMatcher;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.ProxyMethodInvocation;
import org.springframework.aop.framework.autoproxy.ProxyCreationContext;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.aop.support.AbstractExpressionPointcut;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

/**
 * 基于AspectJ表达式功能实现的一个Pointcut子类
 * @since 2.0
 */
public class AspectJExpressionPointcut extends AbstractExpressionPointcut
		implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware {

	private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>();

	static {
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET);
	}


	private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class);

	/**
	 * 切点声明范围
	 */
	private Class<?> pointcutDeclarationScope;

	/**
	 * 切点参数名称列表
	 */
	private String[] pointcutParameterNames = new String[0];

	/**
	 * 切点参数类型列表
	 */
	private Class<?>[] pointcutParameterTypes = new Class<?>[0];

	/**
	 * Spring bean工厂
	 */
	private BeanFactory beanFactory;

	/**
	 * AspectJ切点类加载器,构建AspectJ切点时使用
	 */
	private transient ClassLoader pointcutClassLoader;

	/**
	 * AspectJ表达式
	 * AspectJ包内的类org.aspectj.weaver.tools.PointcutExpression
	 * 封装解析execution(* org.spring.aop.service..*.*(..))的对象
	 */
	private transient PointcutExpression pointcutExpression;

	/**
	 * 缓存切点与方法匹配的结果
	 * ShadowMatch属于AspectJ包内的类org.aspectj.weaver.tools.ShadowMatch
	 *
	 * ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(methodToMatch);
	 *
	 * 切点与目标方法匹配后返回ShadowMatch对象,shadowMatch.alwaysMatches()为true代表二者匹配;shadowMatch.neverMatches()为true代表二者不匹配
	 */
	private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);

	/**
	 * 无参构造函数
	 */
	public AspectJExpressionPointcut() {
	}

	/**
	 * 有参构造函数
	 * @param declarationScope
	 * @param paramNames
	 * 		切点参数名称列表
	 * @param paramTypes
	 * 		切点参数名称列表
	 */
	public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) {
		this.pointcutDeclarationScope = declarationScope;
		if (paramNames.length != paramTypes.length) {
			throw new IllegalStateException(
					"Number of pointcut parameter names must match number of pointcut parameter types");
		}
		this.pointcutParameterNames = paramNames;
		this.pointcutParameterTypes = paramTypes;
	}


	/**
	 * 设置切点声明范围
	 */
	public void setPointcutDeclarationScope(Class<?> pointcutDeclarationScope) {
		this.pointcutDeclarationScope = pointcutDeclarationScope;
	}

	/**
	 * 设置切点参数名称
	 */
	public void setParameterNames(String... names) {
		this.pointcutParameterNames = names;
	}

	/**
	 * 设置切点参数类型
	 */
	public void setParameterTypes(Class<?>... types) {
		this.pointcutParameterTypes = types;
	}

	/**
	 * 设置bean工厂
	 */
	public void setBeanFactory(BeanFactory beanFactory) {
		this.beanFactory = beanFactory;
	}

	/**
	 * 返回自身对象,AspectJExpressionPointcut实现了接口ClassFilter
	 */
	public ClassFilter getClassFilter() {
		checkReadyToMatch();
		return this;
	}

	/**
	 * 返回自身对象,AspectJExpressionPointcut实现了接口IntroductionAwareMethodMatcher
	 */
	public MethodMatcher getMethodMatcher() {
		checkReadyToMatch();
		return this;
	}

	/**
	 * 检查切入点是否准备好匹配,惰性构建(用到时再构建)AspectJ切入点表达式
	 *  - 就是将字符串表达式转化为AspectJ表达式对象
	 * 	String expression = execution(* org.spring.aop.service..*.*(..))
	 * 	PointcutExpression pointcutExpression=new PointcutExpressionImpl(Pointcut pointcut, String expression, PointcutParameter[] params, World inWorld)
	 */
	private void checkReadyToMatch() {
		//判断表达式expression是否为空
		if (getExpression() == null) {
			throw new IllegalStateException("Must set property 'expression' before attempting to match");
		}
		if (this.pointcutExpression == null) {
			//创建AspectJ切点类加载器
			this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
					((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
					ClassUtils.getDefaultClassLoader());
			//创建AspectJ切点表达式
			this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
		}
	}

	/**
	 * 创建AspectJ切点表达式
	 */
	private PointcutExpression buildPointcutExpression(ClassLoader classLoader) {
		//创建并初始化AspectJ切点解析器
		PointcutParser parser = initializePointcutParser(classLoader);

		//构建AspectJ切点参数对象数组
		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]);
		}

		// 创建AspectJ切点表达式
		return parser.parsePointcutExpression(
				replaceBooleanOperators(getExpression()),
				this.pointcutDeclarationScope, pointcutParameters);
	}

	/**
	 * 创建并初始化AspectJ切点解析器
	 */
	private PointcutParser initializePointcutParser(ClassLoader cl) {
		//创建AspectJ切点解析器
		PointcutParser parser = PointcutParser
				.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
						SUPPORTED_PRIMITIVES, cl);
		parser.registerPointcutDesignatorHandler(new BeanNamePointcutDesignatorHandler());
		return parser;
	}


	/**
	 * 将xml配置中的切点表达式中的特殊符号转化为AspectJ切点解析器可识别的
	 * " and " 替换为 " && "
	 * " or " 替换为 " || "
	 * " not " 替换为 " ! "
	 */
	private String replaceBooleanOperators(String pcExpr) {
		String result = StringUtils.replace(pcExpr, " and ", " && ");
		result = StringUtils.replace(result, " or ", " || ");
		result = StringUtils.replace(result, " not ", " ! ");
		return result;
	}


	/**
	 * 返回AspectJ切点表达式
	 */
	public PointcutExpression getPointcutExpression() {
		checkReadyToMatch();
		return this.pointcutExpression;
	}


	//---------------------------------------------------------------------
	// Implementation of ClassFilter
	//---------------------------------------------------------------------

	/**
	 * 切点与目标class匹配
	 */
	public boolean matches(Class<?> targetClass) {
		checkReadyToMatch();
		try {
			try {
				return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
			}
			catch (ReflectionWorldException ex) {
				logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
				PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
				if (fallbackExpression != null) {
					return fallbackExpression.couldMatchJoinPointsInType(targetClass);
				}
			}
		}
		catch (BCException ex) {
			logger.debug("PointcutExpression matching rejected target class", ex);
		}
		return false;
	}

	//---------------------------------------------------------------------
	// Implementation of IntroductionAwareMethodMatcher
	//---------------------------------------------------------------------

	/**
	 * 静态匹配,考虑引介增强场景
	 */
	public boolean matches(Method method, Class<?> targetClass, boolean beanHasIntroductions) {
		checkReadyToMatch();
		Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
		ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);

		if (shadowMatch.alwaysMatches()) {
			return true;
		}
		else if (shadowMatch.neverMatches()) {
			return false;
		}
		else {
			// the maybe case
			if (beanHasIntroductions) { //引介增强直接返回true,因为引介增强的方法是新增的,不可能通过表达式能匹配上
				return true;
			}
			return false;
		}
	}

	//---------------------------------------------------------------------
	// Implementation of MethodMatcher
	//---------------------------------------------------------------------

	/**
	 * 静态匹配
	 */
	public boolean matches(Method method, Class<?> targetClass) {
		return matches(method, targetClass, false);
	}

	/**
	 * 标注动态匹配的,如果返回true,进行动态匹配;返回false,不需要动态匹配
	 * AspectJ表达式:this()、target()、@annotation()、@within()、@target()、args()、@args()等都视为动态匹配,一般会进入3个参数的matches方法中
	 */
	public boolean isRuntime() {
		checkReadyToMatch();
		return this.pointcutExpression.mayNeedDynamicTest();
	}

	/**
	 * 动态匹配的
	 * AspectJ表达式:this()、target()、@annotation()、@within()、@target()、args()、@args()等都视为动态匹配,一般会进入3个参数的matches方法中
	 *
	 * 如何理解Spring的动态匹配,动态匹配一般是无法直接和目标类或方法匹配的,可能是和他们的代理对象、注解、方法注解、方法返回类型等等做比较,总之就是无法直接做匹配,还需要进一步的处理
	 */
	public boolean matches(Method method, Class<?> targetClass, Object[] args) {
		checkReadyToMatch();
		ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method);
		ShadowMatch originalShadowMatch = getShadowMatch(method, method);

		ProxyMethodInvocation pmi = null;
		//aop目标对象
		Object targetObject = null;
		//aop代理对象
		Object thisObject = null;
		try {
			/**
			 * 在spring AOP框架中,advisor一般是个list链,Spring AOP一般会在第一个位置默认添加一个全匹配的拦截器ExposeInvocationInterceptor
			 * ExposeInvocationInterceptor在第一次被调用的时候会将对应的MethodInvocation放到ThreadLocal中,MethodInvocation中含有目标对象和代理对象
			 * 这个地方就是从ThreadLocal中拿到MethodInvocation,进而拿到目标对象和代理对象,像表达式this(),是用this中的表达式和代理对象做比较,此处正好可以应用上
			 */
			MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
			targetObject = mi.getThis();
			if (!(mi instanceof ProxyMethodInvocation)) {
				throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
			}
			pmi = (ProxyMethodInvocation) mi;
			thisObject = pmi.getProxy();
		}
		catch (IllegalStateException ex) {
			// No current invocation...
			// TODO: Should we really proceed here?
			logger.debug("Couldn't access current invocation - matching with limited context: " + ex);
		}

		JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);

		/*
		 * Do a final check to see if any this(TYPE) kind of residue match. For
		 * this purpose, we use the original method's (proxy method's) shadow to
		 * ensure that 'this' is correctly checked against. Without this check,
		 * we get incorrect match on this(TYPE) where TYPE matches the target
		 * type but not 'this' (as would be the case of JDK dynamic proxies).
		 * <p>See SPR-2979 for the original bug.
		 */
		if (pmi != null) {  // there is a current invocation
			/*RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(originalShadowMatch);
			if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
				return false;
			}*/
			if (joinPointMatch.matches()) {
				bindParameters(pmi, joinPointMatch);
			}
		}
		return joinPointMatch.matches();
	}

	protected String getCurrentProxiedBeanName() {
		return ProxyCreationContext.getCurrentProxiedBeanName();
	}


	//------------------------------------------------------------------------------------------------------------
	//   下方属于AspectJ框架的API,基本掌握上面的代码逻辑即可,Spring源码用到很多其它知识,理解会用即可,暂时没必要深究
	//------------------------------------------------------------------------------------------------------------

	/**
	 * Get a new pointcut expression based on a target class's loader rather than the default.
	 */
	private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
		try {
			ClassLoader classLoader = targetClass.getClassLoader();
			if (classLoader != null && classLoader != this.pointcutClassLoader) {
				return buildPointcutExpression(classLoader);
			}
		}
		catch (Throwable ex) {
			logger.debug("Failed to create fallback PointcutExpression", ex);
		}
		return null;
	}

	private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
		if (shadowMatch instanceof DefensiveShadowMatch) {
			return new RuntimeTestWalker(((DefensiveShadowMatch) shadowMatch).primary);
		}
		return new RuntimeTestWalker(shadowMatch);
	}

	private void bindParameters(ProxyMethodInvocation invocation, JoinPointMatch jpm) {
		// Note: Can't use JoinPointMatch.getClass().getName() as the key, since
		// Spring AOP does all the matching at a join point, and then all the invocations
		// under this scenario, if we just use JoinPointMatch as the key, then
		// 'last man wins' which is not what we want at all.
		// Using the expression is guaranteed to be safe, since 2 identical expressions
		// are guaranteed to bind in exactly the same way.
		invocation.setUserAttribute(getExpression(), jpm);
	}

	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;
				Method methodToMatch = targetMethod;
				shadowMatch = this.shadowMatchCache.get(targetMethod);
				if (shadowMatch == null) {
					try {
						shadowMatch = this.pointcutExpression.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 (shadowMatch == null && targetMethod != originalMethod) {
						methodToMatch = originalMethod;
						try {
							shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
						}
						catch (ReflectionWorldException ex3) {
							// 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 ex4) {
								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));
					}
					this.shadowMatchCache.put(targetMethod, shadowMatch);
				}
			}
		}
		return shadowMatch;
	}


	@Override
	public boolean equals(Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof AspectJExpressionPointcut)) {
			return false;
		}
		AspectJExpressionPointcut otherPc = (AspectJExpressionPointcut) other;
		return ObjectUtils.nullSafeEquals(this.getExpression(), otherPc.getExpression()) &&
				ObjectUtils.nullSafeEquals(this.pointcutDeclarationScope, otherPc.pointcutDeclarationScope) &&
				ObjectUtils.nullSafeEquals(this.pointcutParameterNames, otherPc.pointcutParameterNames) &&
				ObjectUtils.nullSafeEquals(this.pointcutParameterTypes, otherPc.pointcutParameterTypes);
	}

	@Override
	public int hashCode() {
		int hashCode = ObjectUtils.nullSafeHashCode(this.getExpression());
		hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutDeclarationScope);
		hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutParameterNames);
		hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutParameterTypes);
		return hashCode;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("AspectJExpressionPointcut: ");
		if (this.pointcutParameterNames != null && this.pointcutParameterTypes != null) {
			sb.append("(");
			for (int i = 0; i < this.pointcutParameterTypes.length; i++) {
				sb.append(this.pointcutParameterTypes[i].getName());
				sb.append(" ");
				sb.append(this.pointcutParameterNames[i]);
				if ((i+1) < this.pointcutParameterTypes.length) {
					sb.append(", ");
				}
			}
			sb.append(")");
		}
		sb.append(" ");
		if (getExpression() != null) {
			sb.append(getExpression());
		}
		else {
			sb.append("<pointcut expression not set>");
		}
		return sb.toString();
	}


	/**
	 * Handler for the Spring-specific {@code bean()} pointcut designator
	 * extension to AspectJ.
	 * <p>This handler must be added to each pointcut object that needs to
	 * handle the {@code bean()} PCD. Matching context is obtained
	 * automatically by examining a thread local variable and therefore a matching
	 * context need not be set on the pointcut.
	 */
	private class BeanNamePointcutDesignatorHandler implements PointcutDesignatorHandler {

		private static final String BEAN_DESIGNATOR_NAME = "bean";

		public String getDesignatorName() {
			return BEAN_DESIGNATOR_NAME;
		}

		public ContextBasedMatcher parse(String expression) {
			return new BeanNameContextMatcher(expression);
		}
	}


	/**
	 * Matcher class for the BeanNamePointcutDesignatorHandler.
	 * <p>Dynamic match tests for this matcher always return true,
	 * since the matching decision is made at the proxy creation time.
	 * For static match tests, this matcher abstains to allow the overall
	 * pointcut to match even when negation is used with the bean() pointcut.
	 */
	private class BeanNameContextMatcher implements ContextBasedMatcher {

		private final NamePattern expressionPattern;

		public BeanNameContextMatcher(String expression) {
			this.expressionPattern = new NamePattern(expression);
		}

		public boolean couldMatchJoinPointsInType(Class someClass) {
			return (contextMatch(someClass) == FuzzyBoolean.YES);
		}

		public boolean couldMatchJoinPointsInType(Class someClass, MatchingContext context) {
			return (contextMatch(someClass) == FuzzyBoolean.YES);
		}

		public boolean matchesDynamically(MatchingContext context) {
			return true;
		}

		public FuzzyBoolean matchesStatically(MatchingContext context) {
			return contextMatch(null);
		}

		public boolean mayNeedDynamicTest() {
			return false;
		}

		private FuzzyBoolean contextMatch(Class<?> targetType) {
			String advisedBeanName = getCurrentProxiedBeanName();
			if (advisedBeanName == null) {  // no proxy creation in progress
				// abstain; can't return YES, since that will make pointcut with negation fail
				return FuzzyBoolean.MAYBE;
			}
			if (BeanFactoryUtils.isGeneratedBeanName(advisedBeanName)) {
				return FuzzyBoolean.NO;
			}
			if (targetType != null) {
				boolean isFactory = FactoryBean.class.isAssignableFrom(targetType);
				return FuzzyBoolean.fromBoolean(
						matchesBeanName(isFactory ? BeanFactory.FACTORY_BEAN_PREFIX + advisedBeanName : advisedBeanName));
			}
			else {
				return FuzzyBoolean.fromBoolean(matchesBeanName(advisedBeanName) ||
						matchesBeanName(BeanFactory.FACTORY_BEAN_PREFIX + advisedBeanName));
			}
		}

		private boolean matchesBeanName(String advisedBeanName) {
			if (this.expressionPattern.matches(advisedBeanName)) {
				return true;
			}
			if (beanFactory != null) {
				String[] aliases = beanFactory.getAliases(advisedBeanName);
				for (String alias : aliases) {
					if (this.expressionPattern.matches(alias)) {
						return true;
					}
				}
			}
			return false;
		}
	}


	//---------------------------------------------------------------------
	// Serialization support
	//---------------------------------------------------------------------

	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
		// Rely on default serialization, just initialize state after deserialization.
		ois.defaultReadObject();

		// Initialize transient fields.
		// pointcutExpression will be initialized lazily by checkReadyToMatch()
		this.shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
	}


	private static class DefensiveShadowMatch implements ShadowMatch {

		private final ShadowMatch primary;

		private final ShadowMatch other;

		public DefensiveShadowMatch(ShadowMatch primary, ShadowMatch other) {
			this.primary = primary;
			this.other = other;
		}

		public boolean alwaysMatches() {
			return this.primary.alwaysMatches();
		}

		public boolean maybeMatches() {
			return this.primary.maybeMatches();
		}

		public boolean neverMatches() {
			return this.primary.neverMatches();
		}

		public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
			try {
				return this.primary.matchesJoinPoint(thisObject, targetObject, args);
			}
			catch (ReflectionWorldException ex) {
				return this.other.matchesJoinPoint(thisObject, targetObject, args);
			}
		}

		public void setMatchingContext(MatchingContext aMatchContext) {
			this.primary.setMatchingContext(aMatchContext);
			this.other.setMatchingContext(aMatchContext);
		}
	}

}
关于AspectJ表达式的使用可以参考:Spring AOP之Aspectj表达式-优快云博客
Advice继承体系:

图中所示接口皆为标识接口,接口内容为空.

例如:Advice

package org.aopalliance.aop;

public interface Advice {

}
接口全路径:
  • Advice:org.aopalliance.aop.Advice
  • Interceptor:org.aopalliance.intercept.Interceptor
  • BeforeAdvice:org.springframework.aop.BeforeAdvice
  • AfterAdvice:org.springframework.aop.AfterAdvice
  • ThrowsAdvice:org.springframework.aop.ThrowsAdvice
AOP联盟定义接口:Advice、Interceptor
Spring AOP定义接口:BeforeAdvide(标识:前置增强)、AfterAdvice(标识:后置增强)、ThrowsAdvice(标识:异常增强)
注:AOP联盟组织定义了一套AOP标准接口,供各个AOP框架使用,位于aopalliance.jar中
类关系图继续延伸:

Spring AOP内部针对AspectJ方式的每种连接点(around、before、after、after-returning、after-throwing)都实现了相应的Advice
  • <aop:around> ===> AspectJAroundAdvice
  • <aop:before> ===> AspectJMethodBeforeAdvice
  • <aop:after> ===> AspectJAfterAdvice
  • <aop:after-returning> ===> AspectJAfterReturningAdvice
  • <aop:after-throwing> ===> AspectJAfterThrowingAdvice
定义Advice方法行为的三个接口:MethodBeforeAdvice、MethodInterceptor、AfterReturningAdvice、
重点关注MethodBeforeAdvice、MethodInterceptor、AfterReturningAdvice,他们内部都有方法定义,决定了5中Advice(AspectJMethodBeforeAdvice、AspectJAroundAdvice、AspectJAfterAdvice、AspectJAfterThrowingAdvice、AspectJAfterReturningAdvice)的方法行为。
package org.aopalliance.intercept;

public interface MethodInterceptor extends Interceptor {
 
    Object invoke(MethodInvocation invocation) throws Throwable;
}

package org.springframework.aop;

import java.lang.reflect.Method;

public interface MethodBeforeAdvice extends BeforeAdvice {

	void before(Method method, Object[] args, Object target) throws Throwable;

}

package org.springframework.aop;

import java.lang.reflect.Method;

public interface AfterReturningAdvice extends AfterAdvice {

	void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;

}

单个Advice的类关系图:

观察上面拆分后的类关系图:
1、Interceptor、MethodInterceptor均属于AOP联盟接
  • org.aopalliance.Interceptor
  • org.aopalliance.MethodInterceptor
2、ThrowsAdvice(Spring aop内部没为其实现子的接口或类,需自行实现,如果发现Advice是ThrowsAdvice类型的,将会被转为ThrowsAdviceInterceptor处理)

        

3、AspectJMethodBeforeAdvice:标识接口为BeforeAdvice,方法行为来源MethodBeforeAdvice
4、AspectJAroundAdvice:标识接口为Interceptor,方法行为来源MethodInterceptor
5、AspectJAfterAdvice、AspectJAfterThrowingAdvice:标识接口为AfterAdvice,方法的行为来源于MethodInterceptor
6、AspectJAfterReturningAdvice:标识接口为AfterAdvice,方法行为来源AfterReturningAdvice

以AspectJAroundAdvice为例写个demo了解实现过程
普通业务类:
package org.spring.aop.advice.test;

public interface IUserService {
    void say();
}
package org.spring.aop.advice.test;

public class UserService implements IUserService {
    public void say() {
        System.out.println("Hello world!!");
    }
}

增强业务类:

package org.spring.aop.advice.test;

import org.aspectj.lang.ProceedingJoinPoint;

public class LogAdvice {
    public Object info(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("===============log record start==============");
        Object object = pjp.proceed();
        System.out.println("===============log record end================");
        return object;
    }
}

测试类:

package org.spring.aop.advice.test;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.aspectj.AspectJAroundAdvice;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.config.MethodLocatingFactoryBean;
import org.springframework.aop.config.SimpleBeanFactoryAwareAspectInstanceFactory;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;

import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;

public class AspectJAroundAdviceTest {
    public static void main(String[] args) throws Throwable {
        //===============准备测试数据=============start====
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(UserService.class);
        beanFactory.registerBeanDefinition("userService", beanDefinition);

        beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(LogAdvice.class);
        beanFactory.registerBeanDefinition("logAdvice", beanDefinition);
        //===============准备测试数据=============end====

        MethodLocatingFactoryBean methodLocatingFactoryBean = new MethodLocatingFactoryBean();
        methodLocatingFactoryBean.setTargetBeanName("logAdvice");
        methodLocatingFactoryBean.setMethodName("info");
        methodLocatingFactoryBean.setBeanFactory(beanFactory);
        //获取增强方法对象,获取的是logAdvice.info()对应的method对象
        Method aspectJAroundAdviceMethod = methodLocatingFactoryBean.getObject();

        //获取pointcut对象
        String expression = "execution(* org.spring.aop.advice.test.UserService.*(..))";
        AspectJExpressionPointcut expressionPointcut = new AspectJExpressionPointcut();
        expressionPointcut.setExpression(expression);

        //获取Advice对象
        SimpleBeanFactoryAwareAspectInstanceFactory aif = new SimpleBeanFactoryAwareAspectInstanceFactory();
        aif.setAspectBeanName("logAdvice");
        aif.setBeanFactory(beanFactory);

        //创建AspectJAroundAdvice对象
        AspectJAroundAdvice aspectJAroundAdvice = new AspectJAroundAdvice(aspectJAroundAdviceMethod, expressionPointcut, aif);

        UserService userService = beanFactory.getBean(UserService.class);
        JdkDynamicAopProxy jdkDynamicAopProxy = new JdkDynamicAopProxy(aspectJAroundAdvice, userService);

        //通过代理将通知应用到业务代码上
        IUserService userServiceProxy = (IUserService) jdkDynamicAopProxy.getProxy();
        userServiceProxy.say();
    }

    private static class MyMethodInvocation extends ReflectiveMethodInvocation {
        protected MyMethodInvocation(Object proxy, Object target, Method method, Object[] arguments, Class targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
            super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
        }
    }

    private static class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
        private AspectJAroundAdvice aspectJAroundAdvice;
        private UserService userService;

        public JdkDynamicAopProxy(AspectJAroundAdvice aspectJAroundAdvice, UserService userService) {
            this.aspectJAroundAdvice = aspectJAroundAdvice;
            this.userService = userService;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            MethodInvocation mi = new MyMethodInvocation(proxy, userService, method, args, UserService.class, Arrays.asList());
            //业务增强
            return aspectJAroundAdvice.invoke(mi);
        }

        @Override
        public Object getProxy() {
            return getProxy(Thread.currentThread().getContextClassLoader());
        }

        @Override
        public Object getProxy(ClassLoader classLoader) {
            return Proxy.newProxyInstance(classLoader, new Class[]{IUserService.class}, this);
        }
    }
}
执行结果:

Advisor继承体系:

Advisor比较简单,主要就是持有Advice和PointCut。

引介增强(Introduction):Spring中除了可以在方法维度上增强功能,还可以在类维度上增强功能,并且是不改变原有的类,通过动态新增方法
引介增强比较简单,只简单介绍使用方法
方式一:硬编码方式

普通业务类:

package org.spring.aop.introduction.service;

public interface IUserService {
    void say();
}
package org.spring.aop.introduction.service;

public class UserService implements IUserService {
    public void say() {
        System.out.println("Hello world!!");
    }
}

引介增强类:

package org.spring.aop.introduction.advice;

public interface ILogService {
    void logInfo();
}
package org.spring.aop.introduction.advice;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.IntroductionInfo;

public class LogAdvice implements MethodInterceptor, IntroductionInfo, ILogService {

    @Override
    public void logInfo() {
        System.out.println("======print log========");
    }

    @Override
    public Class[] getInterfaces() {
        return new Class[]{ILogService.class};
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        if(!invocation.getMethod().getName().equals("logInfo")) {
            return invocation.proceed();
        } else {
            logInfo();
            return null;
        }
    }
}
package org.spring.aop.introduction.advice;

public interface IAddService {
    void doSomething();
}
package org.spring.aop.introduction.advice;

public class AddService implements IAddService {
    @Override
    public void doSomething() {
        System.out.println("I am doing well!!!");
    }
}

测试代码:

package org.spring.aop.introduction;

import org.spring.aop.introduction.advice.AddService;
import org.spring.aop.introduction.advice.IAddService;
import org.spring.aop.introduction.advice.ILogService;
import org.spring.aop.introduction.advice.LogAdvice;
import org.spring.aop.introduction.service.IUserService;
import org.spring.aop.introduction.service.UserService;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.DeclareParentsAdvisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultIntroductionAdvisor;

public class MainTest {
    public static void main(String[] args) {
        IUserService service = new UserService();
        ProxyFactory proxyFactory = new ProxyFactory(service);
        IUserService serviceProxy = (IUserService) proxyFactory.getProxy();
        serviceProxy.say();

        System.out.println("\n-------------对目标对象增强功能-----------------\n");
        //创建advice
        LogAdvice advice = new LogAdvice();
        //创建advisor
        Advisor advisor = new DefaultIntroductionAdvisor(advice);
        proxyFactory.addAdvisor(advisor);
        serviceProxy.say();

        System.out.println("\n-------------对目标对象引介增强功能方式1-----------------\n");
        ILogService logService = (ILogService)proxyFactory.getProxy();
        logService.logInfo();


        proxyFactory.removeAdvisor(advisor);
        System.out.println("\n-------------对目标对象引介增强功能方式2-----------------\n");

        //创建advisor
        advisor = new DeclareParentsAdvisor(IAddService.class, "org.spring.aop.introduction.service.*", AddService.class);
        proxyFactory.addAdvisor(advisor);
        IAddService addService = (IAddService)proxyFactory.getProxy();
        addService.doSomething();
    }
}

执行结果:

方式二:xml配置方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

	<bean id="userService" class="org.spring.aop.introduction.service.UserService"/>
	<!--<bean id="addService" class="org.spring.aop.introduction.advice.AddService"/>-->

	<aop:config>
		<aop:aspect>
			<aop:declare-parents types-matching="org.spring.aop.introduction.service.*" implement-interface="org.spring.aop.introduction.advice.IAddService" default-impl="org.spring.aop.introduction.advice.AddService"/>
			<!--<aop:declare-parents types-matching="org.spring.aop.service.UserService" implement-interface="org.spring.aop.service.IAddService" delegate-ref="addService"/>-->
		</aop:aspect>
	</aop:config>
</beans>

测试代码:

package org.spring.aop.introduction;

import org.spring.aop.introduction.advice.IAddService;
import org.spring.aop.introduction.service.IUserService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XmlMainTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-aop.xml");
        applicationContext.start();

        Object objService = applicationContext.getBean("userService");
        IUserService userService = (IUserService)objService;
        userService.say();

        System.out.println("\n-------------对目标对象引介增强-----------------\n");

        IAddService addService = (IAddService)objService;
        addService.doSomething();

        applicationContext.stop();
    }
}

执行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值