Spring AOP 源码分析

Spring AOP 源码分析

基本概念

AOP全名 Aspect-Oriented Programming 面向切面编程大法。

  1. 切面(Aspect):横切关注点的模块化,一个切面能够包含同一个类型的不同增强方法,比如说事务处理和日志处理可以理解为两个切面。切面由切入点和通知组成,它既包含了横切逻辑的定义,也包括了切入点的定义。 Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。可以简单地认为, 使用 @Aspect 注解的类就是切面
@Component
@Aspect
public class LogAspect {
}
  1. Target(目标对象):目标对象指将要被增强的对象,即包含主业务逻辑的类对象。或者说是被一个或者多个切面所通知的对象。
  2. 连接点(JoinPoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。简单来说,连接点就是被拦截到的程序执行点,因为Spring只支持方法类型的连接点,所以在Spring中连接点就是被拦截到的方法。连接点由两个信息确定:
    • 方法(表示程序执行点,即在哪个目标方法)
    • 相对点(表示方位,即目标方法的什么位置,比如调用前,后等)
@Before("pointcut()")
public void log(JoinPoint joinPoint) { //这个JoinPoint参数就是连接点
}
  1. 切入点(PointCut):切入点是对连接点进行拦截的条件定义。切入点表达式如何和连接点匹配是AOP的核心,Spring缺省使用AspectJ切入点语法。  一般认为,所有的方法都可以认为是连接点,但是我们并不希望在所有的方法上都添加通知,而切入点的作用就是提供一组规则(使用 AspectJ pointcut expression language 来描述) 来匹配连接点,给满足规则的连接点添加通知。
//切入点的匹配规则是com.remcarpediem.test.aop.service包下的所有类的所有函数。
@Pointcut("execution(* com.remcarpediem.test.aop.service..*(..))")
public void pointcut() {
}
  1. 通知(Advice):通知是指拦截到连接点之后要执行的代码,包括了“around”、“before”和“after”等不同类型的通知。Spring AOP框架以拦截器来实现通知模型,并维护一个以连接点为中心的拦截器链。
@Around("(service())")
public Object doAroundMethod(ProceedingJoinPoint pig) throws Throwable {
	System.out.println("doAroundMethod --- before");
	// 执行controller
	Object obj = pig.proceed();
	System.out.println("doAroundMethod --- after");
	return obj;
}
  1. 织入(Weaving):织入是将切面和业务逻辑对象连接起来, 并创建通知代理的过程。织入可以在编译时,类加载时和运行时完成。在编译时进行织入就是静态代理,而在运行时进行织入则是动态代理。
  2. 增强器(Adviser):Advisor是切面的另外一种实现,能够将通知以更为复杂的方式织入到目标对象中,是将通知包装为更复杂切面的装配器。Advisor由切入点和Advice组成。 Advisor这个概念来自于Spring对AOP的支撑,在AspectJ中是没有等价的概念的。Advisor就像是一个小的自包含的切面,这个切面只有一个通知。切面自身通过一个Bean表示,并且必须实现一个默认接口。
Spring 动态代理实现

动态代理就是说AOP框架不会去修改编译时生成的字节码,而是在运行时在内存中生成一个 AOP代理对象,这个 AOP 对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。Spring AOP中的动态代理主要有两种方式:JDK动态代理和CGLIB动态代理。

  • JDK动态代理

JDK代理通过反射来处理被代理的类,并且要求被代理类必须实现一个接口。核心类是 InvocationHandler接口 和 Proxy类。

  • CGLIB动态代理

是一个代码生成的类库,可以在运行时动态的生成某个类的子类。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。核心类是 MethodInterceptor 接口和Enhancer 类。

AOP 的流程

在 bean 的加载中,主要分为实例化、注入属性、初始化。这三个大的步骤,表示了 bean 的生产流程,如果 bean 需要进行增强(AOP),那么在初始化这一步中,就会对 bean 进行 AOP,生成动态代理对象。

开启 AOP 动态代理

spring 通过 @EnableAspectJAutoProxy 开启aop切面,在注解类上面发现@Import(AspectJAutoProxyRegistrar.class)
AspectJAutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar,所以他会通过 registerBeanDefinitions 方法为我们容器导入 beanDefinition

  1. EnableAspectJAutoProxy 注解: 开启动态代理,然后扫描 @Aspect 注解的类,进行将切面类进行注册。每一个PointCut 通知都会是一个增强 adviser
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * 表示子类是否基于 cglib 还是 jdk。默认为 jdk
	 */
	boolean proxyTargetClass() default false;

	/**
	 * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
	 * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
	 * Off by default, i.e. no guarantees that {@code AopContext} access will work.
	 * @since 4.3.1
	 */
	boolean exposeProxy() default false;
}
bena 初始化时动态代理
/**
* 定义切面,扫描 @service 的注解
*/
@Component
@Aspect
public class ServiceAspect {

	//扫描所有加上@service注解,这就是切点
	@Pointcut("@within(org.springframework.stereotype.Service)")
	public void service() {
	}

	/**
	 * 环绕,包括前置、后置方法
	 *
	 * @param pig pig
	 * @return Object object
	 * @throws Throwable 异常
	 */
	@Around("(service())")
	public Object doAroundMethod(ProceedingJoinPoint pig) throws Throwable {
		System.out.println("doAroundMethod --- before");
		// 执行controller
		Object obj = pig.proceed();
		System.out.println("doAroundMethod --- after");
		return obj;
	}
}

/**
 * 定义接口,service 去实现,jdk动态代理需要类实现接口
 * @author jarryl on 7/21/2021 9:32 AM
 */
public interface IDo {
    void say();
}

/**
 * service 实现类,代理类
 */
@Service("a")
@Lazy
public class A implements IDo{

    public A() {
        System.out.println("a create");
    }

    @Override
    public void say() {
        System.out.println("A say hello world");
    }

    @Before("execution(public void com.demo.test.A.say())")
    public void beforeA() {
        System.out.println("before A.say 执行");
    }
}
生成动态代理类
  1. 在 bean 的后置处理器中,有很多的 postProcess 接口,其中 AbstractAutoProxyCreator 负责生成代理对象, AbstractAutoProxyCreator#postProcessAfterInitialization 方法中,最重要的就是 wrapIfNecessary(Object bean, String beanName, Object cacheKey) ,这一步就是创建代理对象。
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		// 判断早期代理的引用缓存中能否找到,如果找到,则使用之前生成的代理对象,否则重新生成
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}
  1. AbstractAutoProxyCreator#wrapIfNecessary(Object bean, String beanName, Object cacheKey) : 判断 bean 是否需要增强,如果需要那么就会创建代理工厂,然后使用代理工厂创建代理对象。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	// beanName 是否有效,在生成代理对象的缓存中能否获取到
	if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}
	// bean 没有增强则直接返回
	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
		return bean;
	}
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}
	// 创建代理,如果我们有对 bean 进行增强
	// Create proxy if we have advice.
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	if (specificInterceptors != DO_NOT_PROXY) {
		this.advisedBeans.put(cacheKey, Boolean.TRUE);
		// 开始创建代理
		Object proxy = createProxy(
				bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
		this.proxyTypes.put(cacheKey, proxy.getClass());
		logger.info(" ============= 创建代理对象,beanName: " + beanName + ", bean: " + bean + bean.hashCode()
			+ ", proxy: " + proxy + proxy.hashCode() + " ============= ");
		return proxy;
	}
	this.advisedBeans.put(cacheKey, Boolean.FALSE);
	return bean;
}
  1. AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean :获取advisors,创建代理之前首先要判断当前 bean 是否满足被代理,所以需要将 advisor 从之前的缓存中拿出来和当前 bean 根据表达式进行匹配。
public List<Advisor> buildAspectJAdvisors() {
	List<String> aspectNames = this.aspectBeanNames;
	// 切面类名
	if (aspectNames == null) {
		synchronized (this) {
			aspectNames = this.aspectBeanNames;
			if (aspectNames == null) {
				List<Advisor> advisors = new ArrayList<>();
				aspectNames = new ArrayList<>();
				String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
						this.beanFactory, Object.class, true, false);
				for (String beanName : beanNames) {
					if (!isEligibleBean(beanName)) {
						continue;
					}
					// We must be careful not to instantiate beans eagerly as in this case they
					// would be cached by the Spring container but would not have been weaved.
					Class<?> beanType = this.beanFactory.getType(beanName);
					if (beanType == null) {
						continue;
					}
					// 判断类是否为切面类,则加入缓存中
					if (this.advisorFactory.isAspect(beanType)) {
						aspectNames.add(beanName);
						AspectMetadata amd = new AspectMetadata(beanType, beanName);
						if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
							MetadataAwareAspectInstanceFactory factory =
									new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
							List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
							// bean 为单例加入增强缓存中
							if (this.beanFactory.isSingleton(beanName)) {
								this.advisorsCache.put(beanName, classAdvisors);
							}
							else {
								this.aspectFactoryCache.put(beanName, factory);
							}
							advisors.addAll(classAdvisors);
						}
						else {
							// Per target or per this.
							if (this.beanFactory.isSingleton(beanName)) {
								throw new IllegalArgumentException("Bean with name '" + beanName +
										"' is a singleton, but aspect instantiation model is not singleton");
							}
							MetadataAwareAspectInstanceFactory factory =
									new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
							this.aspectFactoryCache.put(beanName, factory);
							advisors.addAll(this.advisorFactory.getAdvisors(factory));
						}
					}
				}
				this.aspectBeanNames = aspectNames;
				return advisors;
			}
		}
	}

	if (aspectNames.isEmpty()) {
		return Collections.emptyList();
	}
	List<Advisor> advisors = new ArrayList<>();
	for (String aspectName : aspectNames) {
		// 直接从缓存获取
		List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
		if (cachedAdvisors != null) {
			advisors.addAll(cachedAdvisors);
		}
		else {
			// 手动添加
			MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
			advisors.addAll(this.advisorFactory.getAdvisors(factory));
		}
	}
	return advisors;
}

  1. ProxyFactory#getProxy():创建代理工厂,使用使用对应的代理工厂,分为 JdkDynamicAopProxy, CglibAopProxy
public Object getProxy(@Nullable ClassLoader classLoader) {
	// 创建aop代理,获取代理对象
	return createAopProxy().getProxy(classLoader);
}
  1. DefaultAopProxyFactory#createAopProxy(): 根据目标类判断生成对应的动态代理方法,如果目标类存在接口或者该类是动态类,那么采用 Jdk动态代理,否则使用 Cglib。
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	/**
	 * isOptimize():官方文档翻译为设置代理是否应执行积极的优化,默认为false。
	 * isProxyTargetClass(): AopAutoConfiguration中指定,默认为true,也就是选择使用 cglib 代理
	 * hasNoUserSuppliedProxyInterfaces: 是否设置了实现接口。
	 */
	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.");
		}
		// 目标类是接口或者是动态类时,使用 jdk 动态代理
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		// 否则使用 cglib 动态代理
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}
  1. JdkDynamicAopProxy.getProxy(ClassLoader classLoader):Jdk 动态代理方式,就是使用 jdk 中的方式。
public Object getProxy(@Nullable ClassLoader classLoader) {
	if (logger.isTraceEnabled()) {
		logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
	}
	// 获取 classLoader 的代理接口
	Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
	findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
	// 这就是 jdk 原生的动态代理方式,这也是为啥必须要目标类实现接口
	return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
  1. CglibAopProxy.getProxy(ClassLoader classLoader):CGLIB 通过 Enhancer 生成代理类的子类,并使用 DynamicAdvisedInterceptor 封装了增强方法,再把 DynamicAdvisedInterceptor 实现放入到callbacks 中就是通过对callbacks 的封装来完成aop的实现。当调用代理对象的方法,会被 DynamicAdvisedInterceptor.intercept() 方法拦截。
public Object getProxy(@Nullable ClassLoader classLoader) {
	if (logger.isTraceEnabled()) {
		logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
	}

	try {
		// 目前类的类对象
		Class<?> rootClass = this.advised.getTargetClass();
		Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
		Class<?> proxySuperClass = rootClass;
		// 判断目标类是否是 cglib 代理类
		if (ClassUtils.isCglibProxyClass(rootClass)) {
			/**
			 * 如果目标对象已经是CGLIB 生成代理对象(就是比较类名称中有 $$ 字符串),
			 * 那么就取目标对象的父类作为目标对象的类
			 */
			proxySuperClass = rootClass.getSuperclass();
			Class<?>[] additionalInterfaces = rootClass.getInterfaces();
			for (Class<?> additionalInterface : additionalInterfaces) {
				this.advised.addInterface(additionalInterface);
			}
		}

		// Validate the class, writing log messages as necessary.
		// 打印出不能代理的方法名,CGLIB 是使用继承实现的,所以final , static 的方法不能被增强
		validateClassIfNecessary(proxySuperClass, classLoader);

		// Configure CGLIB Enhancer...
		// 配置 cglib 增强
		Enhancer enhancer = createEnhancer();
		if (classLoader != null) {
			enhancer.setClassLoader(classLoader);
			if (classLoader instanceof SmartClassLoader &&
					((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
				enhancer.setUseCache(false);
			}
		}
		// 设置 super 类,cglib 是通过继承实现动态代理
		enhancer.setSuperclass(proxySuperClass);
		enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
		enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
		enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
		// 获取callBasks
		Callback[] callbacks = getCallbacks(rootClass);
		Class<?>[] types = new Class<?>[callbacks.length];
		for (int x = 0; x < types.length; x++) {
			types[x] = callbacks[x].getClass();
		}
		// fixedInterceptorMap only populated at this point, after getCallbacks call above
		enhancer.setCallbackFilter(new ProxyCallbackFilter(
				this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
		enhancer.setCallbackTypes(types);

		// Generate the proxy class and create a proxy instance.
		//通过 Enhancer 生成代理对象,并设置回调。
		return createProxyClassAndInstance(enhancer, callbacks);
	}
	catch (CodeGenerationException | IllegalArgumentException ex) {
		throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
				": Common causes of this problem include using a final class or a non-visible class",
				ex);
	}
	catch (Throwable ex) {
		// TargetSource.getTarget() failed
		throw new AopConfigException("Unexpected AOP exception", ex);
	}
}

从上面代码中可以看到,实现方式和 jdk 动态代理是一样的,只是方法入口和MethodInvocation 实现类使用的不一样, JdkDynamicAopProxy 入口方法是动态代理的 invoke() 方法,CGLIB 使用的是 DynamicAdvisedInterceptor.intercept() 方法,JdkDynamicAopProxy 使用的MethodInvocation 是 ReflectiveMethodInvocation 子类,CGLIB 使用的是 CglibMethodInvocation

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值