SpringAOP源码解析DayTwo

回顾

我们的AOP实现大致分为3块

  1. 解析切面,将所有带aspect的切面和所有的通知解析成advisor,advisor中就带了通知和pointCut
    在这里插入图片描述

  2. 根据ponitcut去匹配,如果匹配上就会创建动态代理
    在这里插入图片描述

  3. 调用的时候通过责任链的方式,去调用
    在这里插入图片描述

解析advisor过程

使用@EnableAspectJAutoProxy注解开启aop

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
	 * to standard Java interface-based proxies. The default is {@code false}.
	 */
	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;

}

import导入1个实现了ImportBeanDefinitionRegistrar接口的类,调用
在这里插入图片描述
往bean定义中注册个AnnotationAwareAspectJAutoProxyCreator
在这里插入图片描述
这个就是aop最核心的类,包括解析切面,创建动态代理,创建循环依赖下的动态代理。

那么这个方法registerBeanDefinitions会在哪里调用呢?invokeBeanFactoryPostProcessors这里
在这里插入图片描述
最终排好序后,把这些后置处理器放到集合中去
在这里插入图片描述
在createBean的时候,调用createBean方法,
在这里插入图片描述
在这里插入图片描述
拿到我们刚刚注册进来的所有的bean的后置处理器
在这里插入图片描述
调用AnnotationAwareAspectJAutoProxyCreator的
在这里插入图片描述
shouldSkip找到候选的Advisors(通知 前置通知、后置通知等…)
在这里插入图片描述

具体是调用
在这里插入图片描述

去容器中获取到所有的切面信息保存到缓存中
在这里插入图片描述
放到存所有切面的list中。解析过程是非常耗资源的。
在这里插入图片描述
advisor里就包含了advice和pointCut
在这里插入图片描述
放到缓存中
在这里插入图片描述

创建动态代理

所有的advisor都解析完了,就要创建动态代理,根据pointCut去做匹配。如果匹配上就创建
创建动态代理会在哪里呢?
正常的bean会在初始化之后
在这里插入图片描述
我们只看正常的
在这里插入图片描述

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

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}
		//创建一个代理对象工厂
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		//为proxyFactory设置创建jdk代理还是cglib代理
		// 如果设置了 <aop:aspectj-autoproxy proxy-target-class="true"/>不会进if,说明强制使用cglib
		if (!proxyFactory.isProxyTargetClass()) {
			// 内部设置的 ,   配置类就会设置这个属性
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				// 检查有没有接口
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		//把我们的specificInterceptors数组中的Advisor转化为数组形式的
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		//为我们的代理工厂加入通知器,
		proxyFactory.addAdvisors(advisors);
		//设置targetSource对象
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		// 代表之前是否筛选advise.
		// 因为继承了AbstractAdvisorAutoProxyCreator , 并且之前调用了findEligibleAdvisors进行筛选, 所以是true
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
		//真正的创建代理对象
		return proxyFactory.getProxy(getProxyClassLoader());
	}

设置ProxyTargetClass就会用cglib进行动态代理,如果没有设置并且有接口就会使用jdk动态代理

/**
	 *
	 * @param config 用来为我们指定我们advisor信息
	 * 该方法用来创建我们的代理对象
	 * 所我们的targetClass对象实现了接口,且  ProxyTargetClass 没有指定强制的走cglib代理,那么就是创建jdk代理
	 * 我们代理的类没有实现接口,那么会直接走cglib代理
	 * 若我们   ProxyTargetClass 指定为false 且代理类是接口才会走jdk代理 否在我们还是cglib代理
	 * @return
	 * @throws AopConfigException
	 */
	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		//判断我们是否前置指定使用cglib代理ProxyTargetClass =true   或者没有接口
		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.");
			}
			//所targetClass是接口 使用的就是jdk代理
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			//cglib代理
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			//动态代理
			return new JdkDynamicAopProxy(config);
		}
	}

最终放到一级缓存中

如何调用

在这里插入图片描述
调用这个div方法就会来到
在这里插入图片描述

这里面有个细节
在这里插入图片描述

这个if只有@EnableAspectJAutoProxy(exposeProxy = true)才会进入,

现在我们加上,进入断点
在这里插入图片描述
把我们当前的动态代理对象set到ThreadLocal里去,
在这里插入图片描述

private static final ThreadLocal<Object> currentProxy = 
					new NamedThreadLocal<>("Current AOP proxy");
那有什么用呢?

假如是JDK的动态代理,在本类里调用本类的方法。是不会再次执行动态代理的方法。
所以JDK动态代理必须把代理暴露到ThreadLocal里面。看下面例子

public int mod(int numA,int numB){
        System.out.println("执行目标方法:mod");
		int retVal = ((Calculate)AopContext.currentProxy()).add(numA,numB);
        //int retVal = this.add(numA,numB);
        return retVal%numA;
 }

比如说在mod里调用add方法,就可以通过AopContext,拿到theadLocal里的动态代理去调用

public static Object currentProxy() throws IllegalStateException {
		Object proxy = currentProxy.get();
		if (proxy == null) {
			throw new IllegalStateException(
					"Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.");
		}
		return proxy;
	}

currentProxy是

	private static final ThreadLocal<Object> currentProxy = 
					new NamedThreadLocal<>("Current AOP proxy");

ThreadLocal不懂的看我这篇文章ThreadLocal初探

jdk动态代理不可以本类里调用其他方法,但是cglib是可以的

继续往下看
在这里插入图片描述
转为interceptor调用invoke方法,因为之前说过要用责任链调用必须用统一的接口,只有interceptor才有invoke方法
这里就是责任链递归调用,这里太复杂知道责任链递归调用,执行完所有通知就行了,

invocation.proceed()
至此AOP源码的解析就走完了,下一篇Spring事务
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值