5.Spring揭秘-Spring中的AOP概念

5.Spring揭秘-Spring中的AOP概念

萤火虫 931 2021-10-22

Spring中Aop概念

Joinpoint(连接点)

在Spring中仅支持方法调用级别的joinpoint

为什么不支持其它的joinpoint?

  • 仅付出20%的努力,兼容80%的需求。使得Spring的框架不会臃肿
  • 如果有特殊需求可以使用aspectj来实现

Pointcut(切点)

spring中通过定义一个pointcut接口作为描述,因为只支持方法级别的joinpoint,所需这里pointcut只需要只需要描述,哪些类里的哪些方法需要增强即可。

Pointcut

/**
 * Core Spring pointcut abstraction.
 *
 * Spring切点核心抽象
 *
 * <p>A pointcut is composed of a {@link ClassFilter} and a {@link MethodMatcher}.
 * Both these basic terms and a Pointcut itself can be combined to build up combinations
 * (e.g. through {@link org.springframework.aop.support.ComposablePointcut}).
 *
 * 切点由ClassFilter接口 和 MethodMatcher接口组成
 * 这些接口和Pointcut可以通过ComposablePointcut类来进行逻辑运算组合
 *
 * @author Rod Johnson
 * @see ClassFilter
 * @see MethodMatcher
 * @see org.springframework.aop.support.Pointcuts
 * @see org.springframework.aop.support.ClassFilters
 * @see org.springframework.aop.support.MethodMatchers
 */
public interface Pointcut {

	/**
	 * Return the ClassFilter for this pointcut.
	 * @return the ClassFilter (never {@code null})
	 */
	ClassFilter getClassFilter();

	/**
	 * Return the MethodMatcher for this pointcut.
	 * @return the MethodMatcher (never {@code null})
	 */
	MethodMatcher getMethodMatcher();


	/**
	 * Canonical Pointcut instance that always matches.
	 *
	 * 如果为TruePointcut,默认会对系统中所有对象,以及对象上所有被支持的Joinpoint进行匹配
	 */
	Pointcut TRUE = TruePointcut.INSTANCE;

}

可以看到这里引出了两个类ClassFilter和MethodMatcher,Pointcut使用这两个类来作为工具来具体过滤class和匹配method。接下来看看这两个接口都有什么方法。

ClassFilter

/**
 * Filter that restricts matching of a pointcut or introduction to
 * a given set of target classes.
 *
 * 对joinpoint所处的对象进行class级别的类型匹配
 *
 * <p>Can be used as part of a {@link Pointcut} or for the entire
 * targeting of an {@link IntroductionAdvisor}.
 *
 * 可以作为pointcut中的class级别匹配,也可以是IntroductionAdvisor类中的class级别匹配
 *
 * <p>Concrete implementations of this interface typically should provide proper
 * implementations of {@link Object#equals(Object)} and {@link Object#hashCode()}
 * in order to allow the filter to be used in caching scenarios &mdash; for
 * example, in proxies generated by CGLIB.
 *
 * 接口的实现类通常需要实现equals和hashCode方法。
 * 因为matches是匹配类型,想要为ClassFilter生成代理的时候需要知道它能处理的类因此需要实现equals和hashCode方法(猜测)
 * 例如,在CGLIB中生成代理
 *
 * @author Rod Johnson
 * @see Pointcut
 * @see MethodMatcher
 */
@FunctionalInterface
public interface ClassFilter {

	/**
	 * Should the pointcut apply to the given interface or target class?
	 * 织入的目标对象Class类型与Pointcut所规定的类型相符时,matches方法将会返回true
	 * @param clazz the candidate target class
	 * @return whether the advice should apply to the given target class
	 */
	boolean matches(Class<?> clazz);

	/**
	 * Canonical instance of a ClassFilter that matches all classes.
	 * 如果返回TrueClassFilter,则会对系统中所有的目标类和对象进行调用增强实现
	 */
	ClassFilter TRUE = TrueClassFilter.INSTANCE;
}

ClassFilter接口很简单只有一个方法,就是匹配类,判断目标类是否符合匹配。还有一个默认实现类TrueClassFilter。来看看这个类是做啥的?

/**
 * Canonical ClassFilter instance that matches all classes.
 *
 * 与所有类都匹配
 *
 * @author Rod Johnson
 */
@SuppressWarnings("serial")
final class TrueClassFilter implements ClassFilter, Serializable {

	public static final TrueClassFilter INSTANCE = new TrueClassFilter();

	/**
	 * Enforce Singleton pattern.
	 */
	private TrueClassFilter() {
	}

	@Override
	public boolean matches(Class<?> clazz) {
		return true;
	}

	/**
	 * Required to support serialization. Replaces with canonical
	 * instance on deserialization, protecting Singleton pattern.
	 * Alternative to overriding {@code equals()}.
	 */
	private Object readResolve() {
		return INSTANCE;
	}

	@Override
	public String toString() {
		return "ClassFilter.TRUE";
	}
}

可以看到默认的实现类matches方法返回true,也就是说所有class都能匹配,因此所有对象都可以被增强。

再开看看MethodMatcher接口

MethodMatcher

/**
 * Part of a {@link Pointcut}: Checks whether the target method is eligible for advice.
 *
 * Pointcut的以部分,用来检查目标方法是否符合用来增强
 *
 * <p>A MethodMatcher may be evaluated <b>statically</b> or at <b>runtime</b> (dynamically).
 * Static matching involves method and (possibly) method attributes. Dynamic matching
 * also makes arguments for a particular call available, and any effects of running
 * previous advice applying to the joinpoint.
 *
 * MethodMatcher可以在静态和动态两种情况下对方法进行匹配。静态匹配忽略方法传入的参数,动态匹配则每次都检查这些方法调用参数
 *
 * <p>If an implementation returns {@code false} from its {@link #isRuntime()}
 * method, evaluation can be performed statically, and the result will be the same
 * for all invocations of this method, whatever their arguments. This means that
 * if the {@link #isRuntime()} method returns {@code false}, the 3-arg
 * {@link #matches(java.lang.reflect.Method, Class, Object[])} method will never be invoked.
 *
 * 如果isRuntime方法返回false将调用2个参数的matches,并且由于不会匹配参数,因此每次调用这个方法都是幂等的
 * 同时也就是意味着3个参数的matches将不会被调用。
 *
 * <p>If an implementation returns {@code true} from its 2-arg
 * {@link #matches(java.lang.reflect.Method, Class)} method and its {@link #isRuntime()} method
 * returns {@code true}, the 3-arg {@link #matches(java.lang.reflect.Method, Class, Object[])}
 * method will be invoked <i>immediately before each potential execution of the related advice</i>,
 * to decide whether the advice should run. All previous advice, such as earlier interceptors
 * in an interceptor chain, will have run, so any state changes they have produced in
 * parameters or ThreadLocal state will be available at the time of evaluation.
 *
 * 如果2个参数matches方法返回true,并且isRuntime方法返回true,则会调用3个参数的matches方法,并且由于需要根据参数进行判断
 * 方法的调用将不再是幂等的,并且不能对调用链进行缓存。
 *
 * <p>Concrete implementations of this interface typically should provide proper
 * implementations of {@link Object#equals(Object)} and {@link Object#hashCode()}
 * in order to allow the matcher to be used in caching scenarios &mdash; for
 * example, in proxies generated by CGLIB.
 *
 * 实现本接口的类通常应该实现equals和hashCode方法。
 *
 * @author Rod Johnson
 * @since 11.11.2003
 * @see Pointcut
 * @see ClassFilter
 */
public interface MethodMatcher {

	/**
	 * Perform static checking whether the given method matches.
	 * <p>If this returns {@code false} or if the {@link #isRuntime()}
	 * method returns {@code false}, no runtime check (i.e. no
	 * {@link #matches(java.lang.reflect.Method, Class, Object[])} call)
	 * will be made.
	 * @param method the candidate method
	 * @param targetClass the target class
	 * @return whether or not this method matches statically
	 */
	boolean matches(Method method, Class<?> targetClass);

	/**
	 * Is this MethodMatcher dynamic, that is, must a final call be made on the
	 * {@link #matches(java.lang.reflect.Method, Class, Object[])} method at
	 * runtime even if the 2-arg matches method returns {@code true}?
	 * <p>Can be invoked when an AOP proxy is created, and need not be invoked
	 * again before each method invocation,
	 * @return whether or not a runtime match via the 3-arg
	 * {@link #matches(java.lang.reflect.Method, Class, Object[])} method
	 * is required if static matching passed
	 */
	boolean isRuntime();

	/**
	 * Check whether there a runtime (dynamic) match for this method,
	 * which must have matched statically.
	 * <p>This method is invoked only if the 2-arg matches method returns
	 * {@code true} for the given method and target class, and if the
	 * {@link #isRuntime()} method returns {@code true}. Invoked
	 * immediately before potential running of the advice, after any
	 * advice earlier in the advice chain has run.
	 * @param method the candidate method
	 * @param targetClass the target class
	 * @param args arguments to the method
	 * @return whether there&#039;s a runtime match
	 * @see MethodMatcher#matches(Method, Class)
	 */
	boolean matches(Method method, Class<?> targetClass, Object... args);


	/**
	 * Canonical instance that matches all methods.
	 */
	MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}

MethodMatcher接口定义了三个方法,方法具体逻辑注释里有写。这里也有一个默认实现类TrueMethodMatcher,来看看这个类是如何实现的。

/**
 * Canonical MethodMatcher instance that matches all methods.
 *
 * 与所有方法匹配
 *
 * @author Rod Johnson
 */
@SuppressWarnings("serial")
final class TrueMethodMatcher implements MethodMatcher, Serializable {

	public static final TrueMethodMatcher INSTANCE = new TrueMethodMatcher();


	/**
	 * Enforce Singleton pattern.
	 */
	private TrueMethodMatcher() {
	}


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

	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		return true;
	}

	@Override
	public boolean matches(Method method, Class<?> targetClass, Object... args) {
		// Should never be invoked as isRuntime returns false.
		throw new UnsupportedOperationException();
	}


	@Override
	public String toString() {
		return "MethodMatcher.TRUE";
	}

	/**
	 * Required to support serialization. Replaces with canonical
	 * instance on deserialization, protecting Singleton pattern.
	 * Alternative to overriding {@code equals()}.
	 */
	private Object readResolve() {
		return INSTANCE;
	}
}

这里可以看到isRuntime方法返回false说明三个参数matches方法不会调用,并且防止你反射调用也给出了UnsupportedOperationException异常,两个参数matches返回true说明所有方法都会处理。

其实看到这里可以看到这两个实现类都是,都是默认可以处理全部。

为啥Pointcut 内要使用两个接口ClassFilter和MethodMatcher而不是直接定义到一个接口里?

  • 可以重用不同级别的匹配定义,然后在后边需要对pointcut进行逻辑运算时,可以重用不同的定义。

MethodMatcher分类

因为Spring主要是对于方法级别的增强,因此在MethodMatcher上又分成两个类型

第一种:isRuntime方法返回false,表示不会考虑joinpoint的方法参数,这种类型的MethodMatcher称之为StaticMethodMatcher。因为不用每次都检查参数,那么对于同样类型的方法匹配结果,就可以在框架内不进行缓存以提高性能。

第二种:isRuntime方法返回true,表明该MethodMatcher将会每次都对方法调用的参数进行匹配检查,这种类型的MethodMatcher称之为DynamicMethodMatcher。因为每次都要对方法参数进行检查无法对匹配结果进行缓存,所以,匹配效率相对于StaticMethodMatcher要差。而且大部分情况下,StaticMethodMatcher已经可以满足需求,最好避免使用DynamicMethodMatcher类型。

image-20201128152739016

pointcut内部依赖MethodMatcher,而MethodMatcher又两开花,StaticMethodMatcher和DynamicMethodMatcher,DynamicMethodMatcher比较单薄只有一个抽象类DynamicMethodMatcherPointcut。而StaticMethodMatcher比较多

StaticMethodMatcherPointcut和其更近一步的实现类与抽象类。

StaticMethodMatcherPointcut抽象类

在展开StaticMethodMatcherPointcut前先看看这个抽象类都定义了啥东西。

/**
 * Convenient superclass when we want to force subclasses to implement the
 * {@link MethodMatcher} interface but subclasses will want to be pointcuts.
 *
 * 强制子类实现MethodMatcher接口成为切入点,是方便的超类。
 *
 * <p>The {@link #setClassFilter "classFilter"} property can be set to customize
 * {@link ClassFilter} behavior. The default is {@link ClassFilter#TRUE}.
 *
 * classFilter属性可以设置自定义的,默认值为ClassFilter.TRUE
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 */
public abstract class StaticMethodMatcherPointcut extends StaticMethodMatcher implements Pointcut {

	private ClassFilter classFilter = ClassFilter.TRUE;


	/**
	 * Set the {@link ClassFilter} to use for this pointcut.
	 * Default is {@link ClassFilter#TRUE}.
	 */
	public void setClassFilter(ClassFilter classFilter) {
		this.classFilter = classFilter;
	}

	@Override
	public ClassFilter getClassFilter() {
		return this.classFilter;
	}


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

}

非常简单Pointcut接口定义的两个方法,getClassFilter方法返回默认实现匹配所有的类,getMethodMatcher方法直接就返回自身了。好家伙,让自己继承StaticMethodMatcher这样就具备了MethodMatcher的能力,并且StaticMethodMatcher抽象类有默认实现,因此本抽象类只需要覆写2个参数matches方法即可。为啥呢?因为StaticMethodMatcher抽象类实现MethodMatcher接口,三个方法它已经实现了两个了啊,可以回上看到,只有2个参数的方法没有实现。

DynamicMethodMatcherPointcut抽象类

那么想不想看看DynamicMethodMatcherPointcut是怎么玩的呢?在继续之前结合StaticMethodMatcherPointcut来想想你会如何做?

/**
 * Convenient superclass when we want to force subclasses to
 * implement MethodMatcher interface, but subclasses
 * will want to be pointcuts. The getClassFilter() method can
 * be overridden to customize ClassFilter behaviour as well.
 *
 * @author Rod Johnson
 */
public abstract class DynamicMethodMatcherPointcut extends DynamicMethodMatcher implements Pointcut {

	@Override
	public ClassFilter getClassFilter() {
		return ClassFilter.TRUE;
	}

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

}

好家伙,很相似的让自己继承DynamicMethodMatcher,getMethodMatcher把自己返回,然后只需要实现三个参数的matches即可。

MethodMatcher & Pointcut类图

image-20201128154858544

常见Pointcut

@ClassLevel
public class ServiceA {
  @MethodLevel
	public void method1() {
		System.out.println("method1");
	}
	public void method1(String arg) {
		System.out.println("method1 + arg=" + arg);
	}
	public void method2() {
		System.out.println("method2");
	}
	public String method3() {
		System.out.println("method3");
		return "method3";
	}
}
public class ServiceB {
	public void method1(String arg) {
		System.out.println("method1 + arg=" + arg);
	}
	public void method2() {
		System.out.println("method2");
	}
	public String method3() {
		System.out.println("method3");
		return "method3";
	}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassLevel {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodLevel {
}
  • NameMatchMethodPointcut:根据方法名进行匹配
public class PointcutMain {
	public static void main(String[] args) throws Exception {
		NameMatchMethodPointcut nameMatchMethodPointcut = new NameMatchMethodPointcut();
		nameMatchMethodPointcut.addMethodName("method1");
		Method method = ServiceA.class.getMethod("method1");
		boolean matchesA = nameMatchMethodPointcut.matches(method,ServiceA.class);
		boolean matchesB = nameMatchMethodPointcut.matches(method,ServiceB.class);
		System.out.println(matchesA);
		System.out.println(matchesB);
	}
}
//---
true
true
  • JdkRegexpMethodPointcut:正则表达式方式进行匹配。正则表达式必须以匹配整个方法签名
	public static void main(String[] args) throws NoSuchMethodException {
		JdkRegexpMethodPointcut jdkRegexpMethodPointcut = new JdkRegexpMethodPointcut();
		jdkRegexpMethodPointcut.setPattern(".*method1");
		Method method = ServiceA.class.getMethod("method1");
		boolean matches = jdkRegexpMethodPointcut.matches(method, ServiceA.class);
		System.out.println(matches);
	}
//---
true
  • AnnotationMatchingPointcut:通过对注解的匹配
	public static void main(String[] args) throws NoSuchMethodException {
		AnnotationMatchingPointcut annotationMatchingPointcut = new AnnotationMatchingPointcut(ClassLevel.class);
		boolean matches = annotationMatchingPointcut.getClassFilter().matches(ServiceA.class);
		System.out.println(matches);

		AnnotationMatchingPointcut classAnnotation = AnnotationMatchingPointcut.forClassAnnotation(ClassLevel.class);
		System.out.println(classAnnotation.getClassFilter().matches(ServiceA.class));

		AnnotationMatchingPointcut methodAnnotation = AnnotationMatchingPointcut.forMethodAnnotation(MethodLevel.class);
		Method methodWithArg = ServiceA.class.getMethod("method1",String.class);
		Method methodNoArg = ServiceA.class.getMethod("method1");
		System.out.println(methodAnnotation.getMethodMatcher().matches(methodWithArg,ServiceA.class));
		System.out.println(methodAnnotation.getMethodMatcher().matches(methodNoArg,ServiceA.class));
	}
//---
true
true
false
true
  • ComposablePointcut:对Pointcut进行逻辑运算
	public static void main(String[] args) {
		AnnotationMatchingPointcut annotationMatchingPointcut = new AnnotationMatchingPointcut(ClassLevel.class);
		ComposablePointcut composablePointcut = new ComposablePointcut();
		composablePointcut.intersection(annotationMatchingPointcut);
		composablePointcut.union(annotationMatchingPointcut);
	}
  • ControlFlowPointcut:匹配调用流程,指定某个类在调用这个方法时才进行增强

image-20201128171023047

Advice(通知)

SpringAop加入了[AOP Alliannce](http://aopalliance.sourceforge.net/)开源组织,目的在于标准化AOP的使用。Spring种的Advice实现全部遵循AOP AlLiance规定的接口。

Advice实现了将被织入到Pointcut规定的横切逻辑。也就是说确定好方法了,需要在方法前后增加的逻辑需要实现,这个实现就需要写在Advice中去。

Advice按照其自身实力能否走目标对象所有实例功效这一标准可以划分两大类,即per-class类型和per-instance类型

Per-Class类型的Advice

是指可以在目标对象类的所有实例之间共享。这种类型的Advice通常只提供方法拦截,不会为对象类保存任何状态或添加新的特性。

image-20201128180406065
advice

先来看看advice接口

/**
 * Tag interface for Advice. Implementations can be any type
 * of advice, such as Interceptors.
 *
 * @author Rod Johnson
 * @version $Id: Advice.java,v 1.1 2004/03/19 17:02:16 johnsonr Exp $
 */
public interface Advice {}

没有任何方法,仅仅是用来作为advice的标记接口,那来看看BeforeAdvice有啥

/**
 * Common marker interface for before advice, such as {@link MethodBeforeAdvice}.
 *
 * 通用前置通知标记advice接口,例如MethodBeforeAdvice
 *
 * &lt;p&gt;Spring supports only method before advice. Although this is unlikely to change,
 * this API is designed to allow field advice in future if desired.
 *
 * Spring仅支持方法级别前置advice。尽管这种情况不太可能改变,但是该接口api允许将来在必要时提供方法。
 *
 * @author Rod Johnson
 * @see AfterAdvice
 */
public interface BeforeAdvice extends Advice {}

发现也是一个标记接口,可能是考虑到Spring对前置通知的拦截的扩张性,将具体方法延迟到MethodBeforAdvice中了。这个也可以知道AdviceAdvice和Interceptor接口也就是一个标记接口。

MethodBeforAdvice

那来看看MethodBeforAdvice中有啥呢?

/**
 * Advice invoked before a method is invoked. Such advices cannot
 * prevent the method call proceeding, unless they throw a Throwable.
 *
 * 在方法调用之前进行调用的advice的before方法。此方法不能阻止调用被代理方法继续调用,除非抛出异常。
 *
 * @author Rod Johnson
 * @see AfterReturningAdvice
 * @see ThrowsAdvice
 */
public interface MethodBeforeAdvice extends BeforeAdvice {

	/**
	 * Callback before a given method is invoked.
	 * 调用给定方法之前的回调
	 * @param method the method being invoked
	 * @param args the arguments to the method
	 * @param target the target of the method invocation. May be {@code null}.
	 * @throws Throwable if this object wishes to abort the call.
	 * Any exception thrown will be returned to the caller if it&#039;s
	 * allowed by the method signature. Otherwise the exception
	 * will be wrapped as a runtime exception.
	 * 如果方法签名允许抛出任何异常,则将其返回给调用方。否则,异常将被包装为运行时异常。
	 */
	void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}
ThrowsAdvice

看一看ThrowsAdvice都有啥呢?

/**
 * Tag interface for throws advice.
 *
 * 异常advice接口
 *
 * <p>There are not any methods on this interface, as methods are invoked by
 * reflection. Implementing classes must implement methods of the form:
 * 该接口上没有任何方法,因为方法是通过反射调用的。实现类必须实现以下形式的方法:
 * <pre class="code">void afterThrowing([Method, args, target], ThrowableSubclass);</pre>
 *
 * <p>Some examples of valid methods would be:
 *
 * <pre class="code">public void afterThrowing(Exception ex)</pre>
 * <pre class="code">public void afterThrowing(RemoteException)</pre>
 * <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, Exception ex)</pre>
 * <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)</pre>
 *
 * The first three arguments are optional, and only useful if we want further
 * information about the joinpoint, as in AspectJ <b>after-throwing</b> advice.
 *
 * 前三个参数是可选的,仅在我需要知道joinpoint处的信息时有用
 *
 * <p><b>Note:</b> If a throws-advice method throws an exception itself, it will
 * override the original exception (i.e. change the exception thrown to the user).
 * The overriding exception will typically be a RuntimeException; this is compatible
 * with any method signature. However, if a throws-advice method throws a checked
 * exception, it will have to match the declared exceptions of the target method
 * and is hence to some degree coupled to specific target method signatures.
 * <b>Do not throw an undeclared checked exception that is incompatible with
 * the target method&#039;s signature!</b>
 *
 * 注意:如果一个异常advice的afterThrowing方法抛出异常,它将覆盖原方法中的异常,即如果目标方法抛出A异常而异常advice中的方法
 * afterThrowing抛出B异常则会给用户一个B异常。覆盖的异常通常是RuntimeException。
 * RuntimeException与任何方法签名兼容。
 * 然而如果一个异常advice方法抛出一个检查型异常,它必须与目标方法的声明的异常匹配,因此在某种程度上与特定的目标方法签名关联。
 * 不要抛出与目标方法签名不兼容的未声明检查异常!
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see AfterReturningAdvice
 * @see MethodBeforeAdvice
 */
public interface ThrowsAdvice extends AfterAdvice {}

发现ThrowsAdvice接口并没有方法,通过注释可以知道其实它是一个特殊方法

void afterThrowing([Method, args, target], ThrowableSubclass);

本方法通过反射调用,你需要的参数是可变化,只需要写上即可。并且ThrowableSubclass可以指定你想要拦截的异常类型。

AfterReturningAdvice
/**
 * After returning advice is invoked only on normal method return, not if an
 * exception is thrown. Such advice can see the return value, but cannot change it.
 *
 * 返回advice,仅在方法正常返回后调用,如果抛出异常则不会调用。例如advice可以看到返回值,但是不能修改它。
 *
 * @author Rod Johnson
 * @see MethodBeforeAdvice
 * @see ThrowsAdvice
 */
public interface AfterReturningAdvice extends AfterAdvice {

	/**
	 * Callback after a given method successfully returned.
	 * @param returnValue the value returned by the method, if any
	 * @param method the method being invoked
	 * @param args the arguments to the method
	 * @param target the target of the method invocation. May be {@code null}.
	 * @throws Throwable if this object wishes to abort the call.
	 * Any exception thrown will be returned to the caller if it&#039;s
	 * allowed by the method signature. Otherwise the exception
	 * will be wrapped as a runtime exception.
	 */
	void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;

}

AfterReturningAdvice接口中有一个方法,在成功调用方法后执行。

AroundAdvice

SpringAop并没有提供AroundAdvice接口,而是直接采用Aop Alliance的标准接口MethodInterceptor来作为AroundAdvice接口

/**
 * Intercepts calls on an interface on its way to the target. These
 * are nested "on top" of the target.
 *
 * 在方法调用过程中进行拦截。
 *
 * <p>The user should implement the {@link #invoke(MethodInvocation)}
 * method to modify the original behavior. E.g. the following class
 * implements a tracing interceptor (traces all the calls on the
 * intercepted method(s)):
 *
 * 用户应实现invoke方法以修改原方法行为
 *
 * <pre class=code>
 * class TracingInterceptor implements MethodInterceptor {
 *   Object invoke(MethodInvocation i) throws Throwable {
 *     System.out.println("method "+i.getMethod()+" is called on "+
 *                        i.getThis()+" with args "+i.getArguments());
 *     Object ret=i.proceed();
 *     System.out.println("method "+i.getMethod()+" returns "+ret);
 *     return ret;
 *   }
 * }
 * </pre>
 *
 * @author Rod Johnson
 */
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {

	/**
	 * Implement this method to perform extra treatments before and
	 * after the invocation. Polite implementations would certainly
	 * like to invoke {@link Joinpoint#proceed()}.
	 * 实现此方法以在目标方法调用之前和之后执行额外的处理。
	 * 实现invoke的类不要忘记调用Joinpoint#proceed()方法。
	 * @param invocation the method invocation joinpoint
	 * @return the result of the call to {@link Joinpoint#proceed()};
	 * might be intercepted by the interceptor
	 * @throws Throwable if the interceptors or the target object
	 * throws an exception
	 */
	Object invoke(MethodInvocation invocation) throws Throwable;

}

per-instance类型的advice

per-instance类型的advice会为不同实例对象保存它们各自的状态以及相关逻辑。在SpringAOP中,Introduction就是唯一的一种。

Introduction可以在不改动目标类定义的情况下为目标类添加新的属性和行为。使用不多就不做具体分析了。

image-20201129220356507

最后来一个全家福

image-20201129224055522

Aspect-(Advisor)

当准备好pointcut和advice以后就可以对这俩进行组合了。但是在Spring中并没有Aspect的概念,因为Aspect中容许持有有多个pointcut和advice,但在Spring中是Advisor,是一种特殊的Aspect,它只允许持有一个pointcut和advice。

先来看看advisor的实现体系。可以将advisor分为两大类。

image-20201129220818813

在深入研究具体两大类之前先看看Spring的advisor里都有啥

/**
 * Base interface holding AOP <b>advice</b> (action to take at a joinpoint)
 * and a filter determining the applicability of the advice (such as
 * a pointcut). <i>This interface is not for use by Spring users, but to
 * allow for commonality in support for different types of advice.</i>
 *
 * 包含AOP通知的基本接口(在连接点采取的操作)和一个确定建议的适用性的过滤器(例如一个切入点)。
 * 这个接口不是供Spring用户使用的,而是允许在支持不同类型的通知时具有通用性。
 *
 * <p>Spring AOP is based around <b>around advice</b> delivered via method
 * <b>interception</b>, compliant with the AOP Alliance interception API.
 * The Advisor interface allows support for different types of advice,
 * such as <b>before</b> and <b>after</b> advice, which need not be
 * implemented using interception.
 *
 * Spring AOP基于通过拦截方法的around advice传递,符合AOP联盟拦截API。
 * Advisor接口支持不同类型的建议,如before和after的通知,不需要使用拦截实现。
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 */
public interface Advisor {

	/**
	 * Common placeholder for an empty {@code Advice} to be returned from
	 * {@link #getAdvice()} if no proper advice has been configured (yet).
	 * @since 5.0
	 */
	Advice EMPTY_ADVICE = new Advice() {};


	/**
	 * Return the advice part of this aspect. An advice may be an
	 * interceptor, a before advice, a throws advice, etc.
	 * 返回这aspect的advice部分。 advice可以是interceptor,before advice,throws advice等。
	 * @return the advice that should apply if the pointcut matches
	 * @see org.aopalliance.intercept.MethodInterceptor
	 * @see BeforeAdvice
	 * @see ThrowsAdvice
	 * @see AfterReturningAdvice
	 */
	Advice getAdvice();

	/**
	 * Return whether this advice is associated with a particular instance
	 * (for example, creating a mixin) or shared with all instances of
	 * the advised class obtained from the same Spring bean factory.
	 * <p><b>Note that this method is not currently used by the framework.</b>
	 * Typical Advisor implementations always return {@code true}.
	 * Use singleton/prototype bean definitions or appropriate programmatic
	 * proxy creation to ensure that Advisors have the correct lifecycle model.
	 * 返回此建议是与特定实例关联(例如,创建一个mixin)还是与从同一Spring bean工厂获得的建议类的所有实例共享。
	 * 请注意,该框架当前未使用此方法。
	 * 典型的Advisor实现始终返回true。
	 * 使用单例/原型bean定义或适当的程序化代理创建,以确保Advisor具有正确的生命周期模型。
	 * @return whether this advice is associated with a particular target instance
	 */
	boolean isPerInstance();

}

Advisor接口只是返回一个Advice并没有持有Pointcut,同时isPerInstance方法用来判断是否需要检查当前方法父类类方法。

PointcutAdvisor

image-20201129223504032

在看具体实现类之前先看看顶层接口和抽象类,这样也好清楚。

/**
 * Superinterface for all Advisors that are driven by a pointcut.
 * This covers nearly all advisors except introduction advisors,
 * for which method-level matching doesn&#039;t apply.
 *
 * 由Pointcut驱动的所有Advisor的超级接口
 * 处理introduction advisors类型的Advisor以外涵盖里几乎全部的Advisor
 * 不适用于方法级匹配。
 *
 * @author Rod Johnson
 */
public interface PointcutAdvisor extends Advisor {

	/**
	 * Get the Pointcut that drives this advisor.
	 */
	Pointcut getPointcut();
}

瞬间清晰明了,说明本接口,是使用pointcut来确认对哪些方法进行增强的。那它的抽象类呢?

/**
 * Abstract base class for {@link org.springframework.aop.PointcutAdvisor}
 * implementations. Can be subclassed for returning a specific pointcut/advice
 * or a freely configurable pointcut/advice.
 * PointcutAdvisor接口的基类。可以返回一个特殊类型的pointcut/advic或一个可自由配置的pointcut/advic
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 1.1.2
 * @see AbstractGenericPointcutAdvisor
 */
@SuppressWarnings("serial")
public abstract class AbstractPointcutAdvisor implements PointcutAdvisor, Ordered, Serializable {

	@Nullable
	private Integer order;


	public void setOrder(int order) {
		this.order = order;
	}

	@Override
	public int getOrder() {
		if (this.order != null) {
			return this.order;
		}
		Advice advice = getAdvice();
		if (advice instanceof Ordered) {
			return ((Ordered) advice).getOrder();
		}
		return Ordered.LOWEST_PRECEDENCE;
	}

	@Override
	public boolean isPerInstance() {
		return true;
	}


	@Override
	public boolean equals(@Nullable Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof PointcutAdvisor)) {
			return false;
		}
		PointcutAdvisor otherAdvisor = (PointcutAdvisor) other;
		return (ObjectUtils.nullSafeEquals(getAdvice(), otherAdvisor.getAdvice()) &amp;&amp;
				ObjectUtils.nullSafeEquals(getPointcut(), otherAdvisor.getPointcut()));
	}

	@Override
	public int hashCode() {
		return PointcutAdvisor.class.hashCode();
	}

}

这个抽象类只是实现了一个抽象方法isPerInstance默认返回true,也就是检查方法父类。

/**
 * Abstract generic {@link org.springframework.aop.PointcutAdvisor}
 * that allows for any {@link Advice} to be configured.
 * 抽象的通用PointcutAdvisor ,允许配置任何Advice。
 * @author Juergen Hoeller
 * @since 2.0
 * @see #setAdvice
 * @see DefaultPointcutAdvisor
 */
@SuppressWarnings("serial")
public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor {

	private Advice advice = EMPTY_ADVICE;


	/**
	 * Specify the advice that this advisor should apply.
	 */
	public void setAdvice(Advice advice) {
		this.advice = advice;
	}

	@Override
	public Advice getAdvice() {
		return this.advice;
	}


	@Override
	public String toString() {
		return getClass().getName() + ": advice [" + getAdvice() + "]";
	}

}

到这里AbstractGenericPointcutAdvisor类表明advice可以是任何通用的类型,并且有一个默认空实现的advice。

那来看看DefaultBeanFactoryPointcutAdvisor类如何实现的。

DefaultBeanFactoryPointcutAdvisor

是最通用的ointcutAdvisor,可以接收任何类型的advice(除了Introduction类型的除外)和任何类型的pointcut。可以在构造的时候明确传入。也可以用set方法设置。

/**
 * Convenient Pointcut-driven Advisor implementation.
 *
 * 便捷的Pointcut驱动的Advisor实现。
 *
 * <p>This is the most commonly used Advisor implementation. It can be used
 * with any pointcut and advice type, except for introductions. There is
 * normally no need to subclass this class, or to implement custom Advisors.
 *
 * 这是最常用的Advisor实现,可以用大多数的advice,除了Introduction类型的。
 * 通常不需要继承此类或实现自定义Advisor
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see #setPointcut
 * @see #setAdvice
 */
@SuppressWarnings("serial")
public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {

	private Pointcut pointcut = Pointcut.TRUE;


	/**
	 * Create an empty DefaultPointcutAdvisor.
	 * <p>Advice must be set before use using setter methods.
	 * Pointcut will normally be set also, but defaults to {@code Pointcut.TRUE}.
	 *
	 * 创建一个空的DefaultPointcutAdvisor
	 * Advice必须在使用前set。其实继承的抽象类里也有advice空的实现。
	 * pointcut通常也需要设置,但是有默认值 Pointcut.TRUE
	 */
	public DefaultPointcutAdvisor() {
	}

	/**
	 * Create a DefaultPointcutAdvisor that matches all methods.
	 * <p>{@code Pointcut.TRUE} will be used as Pointcut.
	 * @param advice the Advice to use
	 */
	public DefaultPointcutAdvisor(Advice advice) {
		this(Pointcut.TRUE, advice);
	}

	/**
	 * Create a DefaultPointcutAdvisor, specifying Pointcut and Advice.
	 * @param pointcut the Pointcut targeting the Advice
	 * @param advice the Advice to run when Pointcut matches
	 */
	public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
		this.pointcut = pointcut;
		setAdvice(advice);
	}


	/**
	 * Specify the pointcut targeting the advice.
	 * <p>Default is {@code Pointcut.TRUE}.
	 * @see #setAdvice
	 */
	public void setPointcut(@Nullable Pointcut pointcut) {
		this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);
	}

	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}


	@Override
	public String toString() {
		return getClass().getName() + ": pointcut [" + getPointcut() + "]; advice [" + getAdvice() + "]";
	}

}

看了下源码发现额,其实advisor就是把pointcut和advice组合起来,持有一个引用并没有其它功能。

NameMatchMethodPointcutAdvisor

其实这里已经很明显了,就是使用NameMatchMethodPointcut的PointcutAdvisor,具体源码就不看了,想也知道了,应该会有一个设置advice的方法,然后类里有一个默认的NameMatchMethodPointcut,也可以传入进来。可以设置ClassFilter或MappedName

RegexpMethodPointcutAdvisor

同NameMatchMethodPointcutAdvisor一样,就不具体分析了。

DefaultBeanFactoryPointcutAdvisor

DefaultBeanFactoryPointcutAdvisor是绑定了BeanFactory的Advisor。作用是我们可以通过容器中的Advice注册的beanName来关联对应的Advice。只有当对应的Pointcut匹配成功后,才去实例化对应的Advice,减少了容器启动初期Advisor和advice之间的耦合性。

IntroductionAdvisor分支

IntroductionAdvisor与pointcutAdvisor最本质的区别就是IntroductionAdvisor只能用于类级别的拦截,只能使用introduction类型的advice。

image-20201129232605296

织入

我们准备好pointcut和advice以后,组合成advisor。但是到目前为止并没有把任何增强代码作用到类上。接下啦织入操作,将会见证魔法的时刻。

ProxyFactory

先来看看功能最简单的织入器是如何使用的。
public static void main(String[] args) {
		ServiceA serviceA = new ServiceA();

		//创建织入器
		ProxyFactory weaver = new ProxyFactory();
		weaver.setTarget(serviceA);

		//默认advisor
		DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();

		//设置pointcut
		NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
		pointcut.setMappedName("getInfo");
		defaultPointcutAdvisor.setPointcut(pointcut);

		//设置advice
		MethodBeforeAdvice methodBeforeAdvice = new MethodBeforeAdvice() {
			@Override
			public void before(Method method, Object[] args, Object target) throws Throwable {
				System.out.println("前置通知");
			}
		};
		defaultPointcutAdvisor.setAdvice(methodBeforeAdvice);

		//advisor交给织入器
		weaver.addAdvisors(defaultPointcutAdvisor);

		//织入获取代理
		ServiceA proxy = (ServiceA) weaver.getProxy();

		System.out.println(proxy.getInfo());

}
//---
前置通知
ServiceA用法简单,跟我们的想法也一样,先构造出一个织入器,创建一个advisor然后为它添加pointcut属性和advice属性。获取代理对象。
  • 基于接口的代理,可以通过setInterfaces方法设置

  • 基于类的代理,如果没实现对应接口,则会通过CGLIB代理,也可以通过setProxyTargetClass方法强制

ProxyFactory本质
image-20201201222446859

在看ProxyFactory之前先做点准备工作,先来看看Spring中是如何使用动态代理和Cglib生成代理的。

AopProxy

AopProxy是做为生产aop代理工具的接口顶级抽象。

/**
 * Delegate interface for a configured AOP proxy, allowing for the creation
 * of actual proxy objects.
 *
 * 用于配置的AOP代理的委托接口,允许创建实际的代理对象。
 *
 * <p>Out-of-the-box implementations are available for JDK dynamic proxies
 * and for CGLIB proxies, as applied by {@link DefaultAopProxyFactory}.
 *
 * 如DefaultAopProxyFactory默认的实现可用于JDK动态代理和CGLIB代理
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see DefaultAopProxyFactory
 */
public interface AopProxy {

	/**
	 * Create a new proxy object.
	 * <p>Uses the AopProxy&#039;s default class loader (if necessary for proxy creation):
	 * usually, the thread context class loader.
	 * @return the new proxy object (never {@code null})
	 * @see Thread#getContextClassLoader()
	 */
	Object getProxy();

	/**
	 * Create a new proxy object.
	 * <p>Uses the given class loader (if necessary for proxy creation).
	 * {@code null} will simply be passed down and thus lead to the low-level
	 * proxy facility&#039;s default, which is usually different from the default chosen
	 * by the AopProxy implementation&#039;s {@link #getProxy()} method.
	 * @param classLoader the class loader to create the proxy with
	 * (or {@code null} for the low-level proxy facility&#039;s default)
	 * @return the new proxy object (never {@code null})
	 */
	Object getProxy(@Nullable ClassLoader classLoader);
}

简简单单的两个方法,功能相同获取代理对象。只有两个直接子类Cglib2AopProxy类和JdkDynamicAopProxy类,并且JdkDynamicAopProxy类实现了InvocationHandler接口,看过前边jdk如何实现的动态代理应该知道,InvocationHandler接口就是增强功能的接口。两个类内部具体实现就不看了。为啥嘞?因为后边会单独分析!!!,本次只是在宏观上看清楚。

AopProxyFactory

接口AopProxyFactory就是创建AopProxy的工厂。参数呢就是根据AdvisedSupport来创建。

/**
 * Interface to be implemented by factories that are able to create
 * AOP proxies based on {@link AdvisedSupport} configuration objects.
 *
 * 接口实现类是一个工厂,根据AdvisedSupport的配置可以去创建一个AopProxy
 *
 * <p>Proxies should observe the following contract:
 * <ul>
 * <li>They should implement all interfaces that the configuration
 * indicates should be proxied.
 * <li>They should implement the {@link Advised} interface.
 * <li>They should implement the equals method to compare proxied
 * interfaces, advice, and target.
 * <li>They should be serializable if all advisors and target
 * are serializable.
 * <li>They should be thread-safe if advisors and target
 * are thread-safe.
 * </ul>
 *
 * 代理应该遵守以下规则
 * 代理应该实现配置的所有接口
 * 代理应该实现Advised接口
 * 代理应该实现equals方法来兼容被代理的接口,advice,目标类的比较
 * 如果所有advisors和目标可序列化,则它们应可序列化
 * 如果advisor和target是线程安全的,则它们应该是线程安全的
 *
 * <p>Proxies may or may not allow advice changes to be made.
 * If they do not permit advice changes (for example, because
 * the configuration was frozen) a proxy should throw an
 * {@link AopConfigException} on an attempted advice change.
 *
 * 代理可以允许也可以不允许更改advice
 * 如果配置不允许更改advice(例如,由于配置被frozen(意思是frozen参数为true))
 * 则代理应在尝试更改advice时抛出AopConfigException。
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 */
public interface AopProxyFactory {

	/**
	 * Create an {@link AopProxy} for the given AOP configuration.
	 * 为给定的AOP配置创建一个AopProxy 。
	 * @param config the AOP configuration in the form of an
	 * AdvisedSupport object
	 * @return the corresponding AOP proxy
	 * @throws AopConfigException if the configuration is invalid
	 */
	AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;

}

接口方法接收一个参数AdvisedSupport,返回一个对应的AopProxy。就目前来说只有jdk和cglib两种代理也就这两种了。

接口目前有且只有一个实现类就是DefaultAopProxyFactory,既然如此就去看看怎么实现的,或者说是如何根据AdvisedSupport生产AopProxy的

/**
 * Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy
 * or a JDK dynamic proxy.
 *
 * 默认的AopProxyFactory实现类,创建CGLIB代理或JDK动态代理两者之一
 *
 * <p>Creates a CGLIB proxy if one the following is true for a given
 * {@link AdvisedSupport} instance:
 * <ul>
 * <li>the {@code optimize} flag is set
 * <li>the {@code proxyTargetClass} flag is set
 * <li>no proxy interfaces have been specified
 * </ul>
 *
 * 如果AdvisedSupport中条件满足则使用cglib创建代理
 * optimize设置为true
 * proxyTargetClass设置为true
 * 没有指定代理接口,或者被代理的类没有实现接口
 *
 * <p>In general, specify {@code proxyTargetClass} to enforce a CGLIB proxy,
 * or specify one or more interfaces to use a JDK dynamic proxy.
 *
 * 通常proxyTargetClass参数会强制使用cglib代理,或者指定一个或多个接口则使用jdk动态代理
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 12.03.2004
 * @see AdvisedSupport#setOptimize
 * @see AdvisedSupport#setProxyTargetClass
 * @see AdvisedSupport#setInterfaces
 */
@SuppressWarnings("serial")
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

	/**
	 * Determine whether the supplied {@link AdvisedSupport} has only the
	 * {@link org.springframework.aop.SpringProxy} interface specified
	 * (or no proxy interfaces specified at all).
	 * 确定提供的AdvisedSupport是否仅指定了SpringProxy接口(或完全没有指定代理接口)。
	 */
	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
		Class<?>[] ifcs = config.getProxiedInterfaces();
		return (ifcs.length == 0 || (ifcs.length == 1 &amp;&amp; SpringProxy.class.isAssignableFrom(ifcs[0])));
	}

}
AdvisedSupport
image-20201201225324324

AdvisedSupport很简单就是一个生产AopProxy的所需要的信息载体,可以说就是一个配置类。

可以看到AdvisedSupport继承了ProxyConfig和实现了Advise接口,ProxyConfig记载的是生产代理对象的控制信息,而Advised则记载生产代理对象的必要信息,如代理类,Advice,Advisor等。

ProxyConfig

ProxyConfig内部只有5个boolean值,用来统一aop创建代理时的属性。

/**
 * Convenience superclass for configuration used in creating proxies,
 * to ensure that all proxy creators have consistent properties.
 *
 * 用于创建代理的配置的便利超类,以确保所有代理创建者都具有一致的属性。
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see AdvisedSupport
 */
public class ProxyConfig implements Serializable {

	/** use serialVersionUID from Spring 1.2 for interoperability. */
	private static final long serialVersionUID = -8409359707199703185L;


	private boolean proxyTargetClass = false;

	private boolean optimize = false;

	boolean opaque = false;

	boolean exposeProxy = false;

	private boolean frozen = false;


	/**
	 * Set whether to proxy the target class directly, instead of just proxying
	 * specific interfaces. Default is "false".
	 * <p>Set this to "true" to force proxying for the TargetSource&#039;s exposed
	 * target class. If that target class is an interface, a JDK proxy will be
	 * created for the given interface. If that target class is any other class,
	 * a CGLIB proxy will be created for the given class.
	 * <p>Note: Depending on the configuration of the concrete proxy factory,
	 * the proxy-target-class behavior will also be applied if no interfaces
	 * have been specified (and no interface autodetection is activated).
	 * @see org.springframework.aop.TargetSource#getTargetClass()
	 *
	 * 设置是否直接代理目标类,而不是仅代理特定的接口。 默认值为“false”。
	 * 将此设置为“true”可强制代理TargetSource的公开目标类。
	 * 如果该目标类是接口,则将为给定接口创建一个JDK代理。
	 * 如果该目标类是任何其他类,则将为给定类创建CGLIB代理。
	 * 注意:如果未指定接口(并且未激活接口自动检测),则根据具体代理工厂的配置,也会应用代理目标类行为。
	 */
	public void setProxyTargetClass(boolean proxyTargetClass) {
		this.proxyTargetClass = proxyTargetClass;
	}

	/**
	 * Return whether to proxy the target class directly as well as any interfaces.
	 */
	public boolean isProxyTargetClass() {
		return this.proxyTargetClass;
	}

	/**
	 * Set whether proxies should perform aggressive optimizations.
	 * The exact meaning of "aggressive optimizations" will differ
	 * between proxies, but there is usually some tradeoff.
	 * Default is "false".
	 * <p>For example, optimization will usually mean that advice changes won&#039;t
	 * take effect after a proxy has been created. For this reason, optimization
	 * is disabled by default. An optimize value of "true" may be ignored
	 * if other settings preclude optimization: for example, if "exposeProxy"
	 * is set to "true" and that&#039;s not compatible with the optimization.
	 *
	 * 设置代理是否应执行积极的优化。 代理之间“积极优化”的确切含义会有所不同,但通常会有一些权衡。 默认值为“ false”。
	 * 例如,优化通常将意味着在创建代理后更改advice不会生效。
	 * 因此,默认情况下禁用优化。 如果其他设置无法进行优化,则可以忽略优化值“ true”:例如,如果“ exposeProxy”设置为“ true”,并且与优化不兼容。
	 */
	public void setOptimize(boolean optimize) {
		this.optimize = optimize;
	}

	/**
	 * Return whether proxies should perform aggressive optimizations.
	 */
	public boolean isOptimize() {
		return this.optimize;
	}

	/**
	 * Set whether proxies created by this configuration should be prevented
	 * from being cast to {@link Advised} to query proxy status.
	 * <p>Default is "false", meaning that any AOP proxy can be cast to
	 * {@link Advised}.
	 * 设置是否应防止将此配置创建的代理Advised转换为“Advised查询代理状态”。
	 * 默认值为“ false”,表示任何AOP代理都可以转换为Advised 。
	 * 就是说是否容许创建出来的代理类强转为Advised
	 */
	public void setOpaque(boolean opaque) {
		this.opaque = opaque;
	}

	/**
	 * Return whether proxies created by this configuration should be
	 * prevented from being cast to {@link Advised}.
	 */
	public boolean isOpaque() {
		return this.opaque;
	}

	/**
	 * Set whether the proxy should be exposed by the AOP framework as a
	 * ThreadLocal for retrieval via the AopContext class. This is useful
	 * if an advised object needs to call another advised method on itself.
	 * (If it uses {@code this}, the invocation will not be advised).
	 * <p>Default is "false", in order to avoid unnecessary extra interception.
	 * This means that no guarantees are provided that AopContext access will
	 * work consistently within any method of the advised object.
	 * 设置代理是否应由AOP框架公开为ThreadLocal以便通过AopContext类进行检索。 如果advised对象需要自己调用另一个advised方法,这将很有用。 (如果使用this ,则不建议调用)。
	 * 默认值为“ false”,以避免不必要的额外拦截。 这意味着,不能保证AopContext访问将在advised对象的任何方法中都能一致地工作。
	 */
	public void setExposeProxy(boolean exposeProxy) {
		this.exposeProxy = exposeProxy;
	}

	/**
	 * Return whether the AOP proxy will expose the AOP proxy for
	 * each invocation.
	 */
	public boolean isExposeProxy() {
		return this.exposeProxy;
	}

	/**
	 * Set whether this config should be frozen.
	 * <p>When a config is frozen, no advice changes can be made. This is
	 * useful for optimization, and useful when we don&#039;t want callers to
	 * be able to manipulate configuration after casting to Advised.
	 * 设置是否应冻结此配置。
	 * 冻结配置后,将无法进行任何建议更改。 这对于优化很有用,在我们不希望调用者在转换为Advised之后能够操纵配置时有用。
	 */
	public void setFrozen(boolean frozen) {
		this.frozen = frozen;
	}

	/**
	 * Return whether the config is frozen, and no advice changes can be made.
	 */
	public boolean isFrozen() {
		return this.frozen;
	}


	/**
	 * Copy configuration from the other config object.
	 * @param other object to copy configuration from
	 */
	public void copyFrom(ProxyConfig other) {
		Assert.notNull(other, "Other ProxyConfig object must not be null");
		this.proxyTargetClass = other.proxyTargetClass;
		this.optimize = other.optimize;
		this.exposeProxy = other.exposeProxy;
		this.frozen = other.frozen;
		this.opaque = other.opaque;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("proxyTargetClass=").append(this.proxyTargetClass).append("; ");
		sb.append("optimize=").append(this.optimize).append("; ");
		sb.append("opaque=").append(this.opaque).append("; ");
		sb.append("exposeProxy=").append(this.exposeProxy).append("; ");
		sb.append("frozen=").append(this.frozen);
		return sb.toString();
	}

}
Advised
/**
 * Interface to be implemented by classes that hold the configuration
 * of a factory of AOP proxies. This configuration includes the
 * Interceptors and other advice, Advisors, and the proxied interfaces.
 *
 * 被代理接口的实现类同时内部保留AOP代理工厂的配置,配置包含Interceptor、advice、Advisors和代理接口
 *
 * <p>Any AOP proxy obtained from Spring can be cast to this interface to
 * allow manipulation of its AOP advice.
 *
 * 从Spring获得的任何AOP代理都可以转换为此接口,以允许对其AOP进行操作和获取数据
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 13.03.2003
 * @see org.springframework.aop.framework.AdvisedSupport
 */
public interface Advised extends TargetClassAware {

	/**
	 * Return whether the Advised configuration is frozen,
	 * in which case no advice changes can be made.
	 * 返回advised的配置是否被冻结,在这种情况下,无法对advice进行更改。
	 */
	boolean isFrozen();

	/**
	 * Are we proxying the full target class instead of specified interfaces?
	 * 是否使用CGLIB进行代理对象
	 */
	boolean isProxyTargetClass();

	/**
	 * Return the interfaces proxied by the AOP proxy.
	 * 返回由AOP代理代理的接口。
	 * <p>Will not include the target class, which may also be proxied.
	 * 将不包括目标类,也可以将其作为代理
	 */
	Class<?>[] getProxiedInterfaces();

	/**
	 * Determine whether the given interface is proxied.
	 * 确定是否代理给定的接口。
	 * @param intf the interface to check
	 */
	boolean isInterfaceProxied(Class<?> intf);

	/**
	 * Change the {@code TargetSource} used by this {@code Advised} object.
	 * <p>Only works if the configuration isn&#039;t {@linkplain #isFrozen frozen}.
	 *
	 * 通过Advised改变TargetSource
	 * 仅在isFrozen为false时才可以更改
	 * @param targetSource new TargetSource to use
	 */
	void setTargetSource(TargetSource targetSource);

	/**
	 * Return the {@code TargetSource} used by this {@code Advised} object.
	 * 通过Advised获取TargetSource
	 */
	TargetSource getTargetSource();

	/**
	 * Set whether the proxy should be exposed by the AOP framework as a
	 * {@link ThreadLocal} for retrieval via the {@link AopContext} class.
	 * <p>It can be necessary to expose the proxy if an advised object needs
	 * to invoke a method on itself with advice applied. Otherwise, if an
	 * advised object invokes a method on {@code this}, no advice will be applied.
	 * <p>Default is {@code false}, for optimal performance.
	 *
	 * 设置ExposeProxy为true,可以让SpringAop在生成代理对象时,将当前对象绑定到ThreadLocal上,并通过AopContext.currentProxy获取
	 * 如果advised对象需要在应用advice的情况下自行调用方法,则可能需要公开代理。
	 * 否则,如果advised对象在this上调用方法,则不会应用任何advice。
	 * 默认值为false,以实现最佳性能。
	 */
	void setExposeProxy(boolean exposeProxy);

	/**
	 * Return whether the factory should expose the proxy as a {@link ThreadLocal}.
	 * <p>It can be necessary to expose the proxy if an advised object needs
	 * to invoke a method on itself with advice applied. Otherwise, if an
	 * advised object invokes a method on {@code this}, no advice will be applied.
	 * <p>Getting the proxy is analogous to an EJB calling {@code getEJBObject()}.
	 * @see AopContext
	 *
	 * 返回工厂是否应将代理公开为ThreadLocal 。
	 * 如果建议对象需要在应用建议的情况下自行调用方法,则可能需要公开代理。 否则,如果建议对象在this上调用方法,则不会应用任何建议。
	 * 获取代理类似于调用getEJBObject()的EJB。
	 */
	boolean isExposeProxy();

	/**
	 * Set whether this proxy configuration is pre-filtered so that it only
	 * contains applicable advisors (matching this proxy&#039;s target class).
	 * <p>Default is "false". Set this to "true" if the advisors have been
	 * pre-filtered already, meaning that the ClassFilter check can be skipped
	 * when building the actual advisor chain for proxy invocations.
	 * @see org.springframework.aop.ClassFilter
	 *
	 * 设置此代理配置是否已预先过滤,以使其仅包含适用的advisors对象(与该代理的目标类匹配)。
	 * 默认值为“ false”。
	 * 如果已经对advisors进行了预过滤,则将其设置为“ true”,这意味着在为代理调用构建实际的advisors链时可以跳过ClassFilter检查。
	 */
	void setPreFiltered(boolean preFiltered);

	/**
	 * Return whether this proxy configuration is pre-filtered so that it only
	 * contains applicable advisors (matching this proxy&#039;s target class).
	 */
	boolean isPreFiltered();

	/**
	 * Return the advisors applying to this proxy.
	 * @return a list of Advisors applying to this proxy (never {@code null})
	 */
	Advisor[] getAdvisors();

	/**
	 * Add an advisor at the end of the advisor chain.
	 * <p>The Advisor may be an {@link org.springframework.aop.IntroductionAdvisor},
	 * in which new interfaces will be available when a proxy is next obtained
	 * from the relevant factory.
	 * @param advisor the advisor to add to the end of the chain
	 * @throws AopConfigException in case of invalid advice
	 *
	 * 在advisor链的末尾添加advisor。
	 * advisor可以是IntroductionAdvisor 。新增加的接口实现,在下一次从相关工厂获得代理时,其中的新接口就可用了
	 */
	void addAdvisor(Advisor advisor) throws AopConfigException;

	/**
	 * Add an Advisor at the specified position in the chain.
	 * 在链中的指定位置添加Advisor。
	 * @param advisor the advisor to add at the specified position in the chain
	 * @param pos position in chain (0 is head). Must be valid.
	 * @throws AopConfigException in case of invalid advice
	 */
	void addAdvisor(int pos, Advisor advisor) throws AopConfigException;

	/**
	 * Remove the given advisor.
	 * @param advisor the advisor to remove
	 * @return {@code true} if the advisor was removed; {@code false}
	 * if the advisor was not found and hence could not be removed
	 */
	boolean removeAdvisor(Advisor advisor);

	/**
	 * Remove the advisor at the given index.
	 * @param index the index of advisor to remove
	 * @throws AopConfigException if the index is invalid
	 */
	void removeAdvisor(int index) throws AopConfigException;

	/**
	 * Return the index (from 0) of the given advisor,
	 * or -1 if no such advisor applies to this proxy.
	 * <p>The return value of this method can be used to index into the advisors array.
	 * @param advisor the advisor to search for
	 * @return index from 0 of this advisor, or -1 if there&#039;s no such advisor
	 */
	int indexOf(Advisor advisor);

	/**
	 * Replace the given advisor.
	 * <p><b>Note:</b> If the advisor is an {@link org.springframework.aop.IntroductionAdvisor}
	 * and the replacement is not or implements different interfaces, the proxy will need
	 * to be re-obtained or the old interfaces won&#039;t be supported and the new interface
	 * won&#039;t be implemented.
	 * @param a the advisor to replace
	 * @param b the advisor to replace it with
	 * @return whether it was replaced. If the advisor wasn&#039;t found in the
	 * list of advisors, this method returns {@code false} and does nothing.
	 * @throws AopConfigException in case of invalid advice
	 */
	boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;

	/**
	 * Add the given AOP Alliance advice to the tail of the advice (interceptor) chain.
	 * <p>This will be wrapped in a DefaultPointcutAdvisor with a pointcut that always
	 * applies, and returned from the {@code getAdvisors()} method in this wrapped form.
	 * <p>Note that the given advice will apply to all invocations on the proxy,
	 * even to the {@code toString()} method! Use appropriate advice implementations
	 * or specify appropriate pointcuts to apply to a narrower set of methods.
	 * @param advice the advice to add to the tail of the chain
	 * @throws AopConfigException in case of invalid advice
	 * @see #addAdvice(int, Advice)
	 * @see org.springframework.aop.support.DefaultPointcutAdvisor
	 *
	 * 将给定的AOP联盟advice添加到advice(interceptor)链的末尾。
	 * 将生成一个DefaultPointcutAdvisor来存储advice。
	 * 并可以通过getAdvisors方法返回。
	 * 请注意,给出的advice将应用于代理对象上的所有方法,甚至适用于toString方法!
	 * 使用适当的advice实现或指定适当的pointcut以应用于需要的方法集。
	 *
	 */
	void addAdvice(Advice advice) throws AopConfigException;

	/**
	 * Add the given AOP Alliance Advice at the specified position in the advice chain.
	 * <p>This will be wrapped in a {@link org.springframework.aop.support.DefaultPointcutAdvisor}
	 * with a pointcut that always applies, and returned from the {@link #getAdvisors()}
	 * method in this wrapped form.
	 * <p>Note: The given advice will apply to all invocations on the proxy,
	 * even to the {@code toString()} method! Use appropriate advice implementations
	 * or specify appropriate pointcuts to apply to a narrower set of methods.
	 * @param pos index from 0 (head)
	 * @param advice the advice to add at the specified position in the advice chain
	 * @throws AopConfigException in case of invalid advice
	 */
	void addAdvice(int pos, Advice advice) throws AopConfigException;

	/**
	 * Remove the Advisor containing the given advice.
	 * @param advice the advice to remove
	 * @return {@code true} of the advice was found and removed;
	 * {@code false} if there was no such advice
	 */
	boolean removeAdvice(Advice advice);

	/**
	 * Return the index (from 0) of the given AOP Alliance Advice,
	 * or -1 if no such advice is an advice for this proxy.
	 * <p>The return value of this method can be used to index into
	 * the advisors array.
	 * @param advice the AOP Alliance advice to search for
	 * @return index from 0 of this advice, or -1 if there&#039;s no such advice
	 */
	int indexOf(Advice advice);

	/**
	 * As {@code toString()} will normally be delegated to the target,
	 * this returns the equivalent for the AOP proxy.
	 * @return a string description of the proxy configuration
	 * 由于toString()通常将委托给目标,因此它返回AOP代理的等效项。
	 */
	String toProxyConfigString();

}

方法很多,总结下来就是干了几件事

  • 判断是否代理了给定的接口
  • 增删改advisor和advice
  • 获取ProxyConfig的3个属性,Frozen,ProxyTargetClass,ExposeProxy
  • 3个特有属性,代理的接口ProxiedInterfaces,TargetSource,PreFiltered

至此我们已经看到了支持ProxyFactory的工具的脉络

image-20201201233445254

AopProxyFatory用来生产AopProxy根据AdvisedSupport配置,来生产Cglib类型还是Jdk类型。并且AdvisedSupport内存储的需要创建代理对象所需要的一切信息。那么都已经到这里了,ProxyFactory想必也知道它是干嘛的了。