Spring AOP 基本概念

Spring AOP 基本概念

一、基本概念

关于 AOP 的概念定义如果只是上百度查找一些文字描述,看完之后也是一脸懵逼,根据本无法理解。下面我们结合代码来解释这些羞涩难懂的概念。
Spring AOP 基本概念

1.1 切面(Aspect)

Aspect 是由 PointCut 和 Advice 组成。由于 PointCut 也可以定义多个,准确的说是多个 PointCut 和 多个Advice 组成。
如果从逻辑角度看切面,Spring中的配置事务管理就是一个很好的例子,当然像这样的例子还包括Spring中缓存的功能。

1.2 切点(Pointcut)

切点就是定义拦截(增强)哪些对象中的哪些方法的,简单点说就是拦截的条件定义。

1.3 连接点(JoinPoint)

程序执行过程中明确的点,如方法的调用或特定的异常被抛出。连接点由两个信息确定:

  • 方法(表示程序执行点,即在哪个目标方法)

  • 相对点(表示方位,即目标方法的什么位置,比如调用前,后等)

    简单来说,连接点就是被拦截到的程序执行点,因为Spring只支持方法类型的连接点,所以在Spring中连接点就是被拦截到的方法。

1.4 通知(Advice)

通知是指拦截到连接点之后要执行的代码,包括了 “around”、“before” 和 “after” 等不同类型的通知。
Spring AOP框架以拦截器来实现通知模型,并维护一个以连接点为中心的拦截器链。

1.5 目标对象(Target)

目标对象指将要被增强的对象,即包含主业务逻辑的类对象。或者说是被一个或者多个切面所通知的对象。
例如:example.spring.aop.Calculator 就是目标对象,div 就是被拦截的方法。

public class Calculator {
	public int div(int i, int j){
		return i/j;
	}
}

1.6 总结

  1. 通过切点(Pointcut)寻找需要增强的目标对象方法
  2. 目标方法被调用时,需要按通知(Advice)的顺序依次执行 logStart() -> div() -> logEnd() -> logReturn() 。 如果目标方法抛出异常,则执行 logException() 方法。
  3. 所有的通知(Advice)通过连接点(JoinPoint)获取目标方法的信息。

二、相关概念

2.1 织入(Weaving)

织入是将切面和业务逻辑对象连接起来, 并创建通知代理的过程。可以理解为就是 1.6 总结 的描述过程。织入可以在编译时类加载时运行时完成。
在编译时进行织入就是静态代理,而在运行时进行织入则是动态代理。

在Spring中 当bean实现接口时,使用 JDK 动态代理。当 bean 没实现接口,使用 CGLib 动态代理。
配置 CGLib 的两种方式:

  1. 通过配置强制走cglib,<aop:aspectj-autoproxy proxy-target-class=“true”/>
  2. 注解的方式,例如 SpringBoot 项目的启动类上添加 @EnableAspectJAutoProxy(proxyTargetClass=true)

Calculator 类被 CGLib 织入后的代码

public class Calculator$$EnhancerBySpringCGLIB$$b212acf extends Calculator implements SpringProxy, Advised, Factory {
    ..... 此处省略部分代码
	static void CGLIB$STATICHOOK3() {
		CGLIB$THREAD_CALLBACKS = new ThreadLocal();
		CGLIB$emptyArgs = new Object[0];
		Class arg = Class.forName("example.spring.aop.Calculator$$EnhancerBySpringCGLIB$$b212acf");
		Class arg0;
		CGLIB$div$0$Method = ReflectUtils.findMethods(new String[]{"div", "(II)I"},
				(arg0 = Class.forName("example.spring.aop.Calculator")).getDeclaredMethods())[0];
		CGLIB$div$0$Proxy = MethodProxy.create(arg0, arg, "(II)I", "div", "CGLIB$div$0");
		Method[] arg9999 = ReflectUtils.findMethods(
				new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I",
						"clone", "()Ljava/lang/Object;"},
				(arg0 = Class.forName("java.lang.Object")).getDeclaredMethods());
		CGLIB$equals$1$Method = arg9999[0];
		CGLIB$equals$1$Proxy = MethodProxy.create(arg0, arg, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
		CGLIB$toString$2$Method = arg9999[1];
		CGLIB$toString$2$Proxy = MethodProxy.create(arg0, arg, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
		CGLIB$hashCode$3$Method = arg9999[2];
		CGLIB$hashCode$3$Proxy = MethodProxy.create(arg0, arg, "()I", "hashCode", "CGLIB$hashCode$3");
		CGLIB$clone$4$Method = arg9999[3];
		CGLIB$clone$4$Proxy = MethodProxy.create(arg0, arg, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
	}

	final int CGLIB$div$0(int arg0, int arg1) {
		return super.div(arg0, arg1);
	}

	public final int div(int arg0, int arg1) {
		try {
			MethodInterceptor arg9999 = this.CGLIB$CALLBACK_0;
			if (this.CGLIB$CALLBACK_0 == null) {
				CGLIB$BIND_CALLBACKS(this);
				arg9999 = this.CGLIB$CALLBACK_0;
			}

			if (arg9999 != null) {
				Object arg4 = arg9999.intercept(this, CGLIB$div$0$Method,
						new Object[]{new Integer(arg0), new Integer(arg1)}, CGLIB$div$0$Proxy);
				return arg4 == null ? 0 : ((Number) arg4).intValue();
			} else {
				return super.div(arg0, arg1);
			}
		} catch (Error | RuntimeException arg2) {
			throw arg2;
		} catch (Throwable arg3) {
			throw new UndeclaredThrowableException(arg3);
		}
	}
 ..... 以下代码省略
 }

2.2 增强器(Advisor)

InstantiationModelAwarePointcutAdvisorImpl 是 Advisor的一个实现类,从这个类的源码中可以看出。
Advisor 由切点和一个通知组成,由于它只有一个通知,所以也可以理解为切面的另外一种实现。
Spring AOP 基本概念

上一篇:消息中间件ActiveMQ的简单使用-Spring整合开发(2)


下一篇:FirstJavaWeb