你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

Spring原理篇(14)--Spring AOP源码的实现<一>

2021/11/3 7:14:48

@TOC# Spring系列
记录在程序走的每一步___auth:huf


非常感谢各位同学们;各位同事以及开发好友的关注与支持; 上一篇文章非常荣幸的冲到了热榜第一; Spring连载内容 剩余内容不多了; 一个就是AOP的源码实现; 还有一个就是想说Spring 事务的源码实现; 就会进入其他源码的连载;
对于AOP Spring并不是首创,首创是 AspectJ,而且也不仅仅只有Spring提供了一套机制来支持AOP Spring是依赖了AspectJ的,或者说, Spring是直接把AspectJ中所定义的那些注解直接拿过来用,自己没有再重复定义了,不过也仅仅只 是把注解的定义赋值过来了
上一章节我们讲到; CGLIB 以及 JDK代理的基本实现;

介绍了AOP 的 , 下面给大家补齐AOP 切面的其他知识点;

Pointcut :切点

Advice :通知

Advisor :一个Advisor 就等于 一个Advice 加一个Pointcut;

Aspect : 表示切面,比如被@Aspect注解的类就是切面

join point :表示连接点;一个程序执行过程中的点.在Spring中一个连接点通常表示一个方法的执行;

Introduction :可以使用@DeclareParents来给所匹配的类添加一个接口,并指定一个默认实现

Target object:目标对象,被代理对象 也就是Spring 使用BeanDefinition 创建出来的对象;在没有使用代理的时候; 我们用的那个容器当中的对象;

AOP proxy:表示代理工厂,用来创建代理对象的 在Spring中 要么是CGLIB 代理 要么是JDK代理;

Weaving:表示织入,表示创建代理对象的动作,这个动作可以发生在编译时期(在Java 语言中,从织入切面的方式上来看,存在三种织入方式:编译期织入、类加载期织入和运行期织入。编译期织入是指在Java编译期,采用特殊的编译器,将切面织入到Java类中;而类加载期织入则指通过特殊的类加载器,在类字节码加载到JVM时,织入切面;运行期织入则是采用CGLib工具或JDK动态代理进行切面的织入。)


以上 几个关键的知识点; 请务必熟悉;因为在面试中 有非常大的可能性会被问到;
以下是我找源码起源的方法:

我们在Spring启动的时候; 大体可以分为这三部分. 如果看过我这一系列的同学应该知道. 这一个系列 都是围绕着 Spring5.3.5 版本进行讲解;
第一部分 为系统参数配置;
第二部分 为BeanPostProcessor ,BeanFactory 等主类进行一个实例化 初始化;
第三部分 为配置过的单例Bean进行一个实例化 初始化;

我们在启动的时候 在console的地方 就可以看到 我们创建的细节过程; 例如 我们要找AOP 的起源;
在这里插入图片描述
我们全局搜索这个org.springframework.aop.config.internalAutoProxyCreator 这样 我们就可以找到AopConfigUtils 这个类;
在这个变量中 我们发现;
在这里插入图片描述
下面有方法引用这个参数 进行BeanDefinition 的注册; 一眼就可以看出来了 万变不离其宗.在手写Mybatis-Spring.jar的时候 作者明确的说明 如果 有插件 或者是 其他架构 需要跟Spring整合 就必须往Spring中的BeanDefinition 进行注册.例如AOP ;
在这里插入图片描述
我们继续往深追溯 这个方法由谁调用(这个不会的 自己的百度一下)
在这里插入图片描述
最后我们找到了这个类: AspectJAutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar

在我们手写Mybatis-Spring.jar 的时候 我介绍了几种注册Beandefinition的方式. 着是第三种方式; 有兴趣可以看本系列 第十二章; 我为什么要这样找; 原因是什么 ;这些都可以在第十二章找到相对应的答案; 通过这样的方式 我们就可以知道代理对象是怎么创建的. OK 接下来我们分析源码:


开始前 我问几个问题

1.我们的代理对象是怎么创建的? 2.在什么时候置换成为代理对象? 3.是什么条件 让Spring去选择使用CGLIB代理 还是 JDK代理?(我个人去面试别人的时候 非常喜欢问的问题;)

第一答: 我们的代理对象 是由 DefaultAopProxyFactory 创建的
在这里插入图片描述
第二答: 在初始化对象之后开始置换AOP
在这里插入图片描述
第三答: 在第一答的源码中已经明确回答了

  1. 被代理对象是否是接口?
  2. 被代理对象是否实现接口?
    如果没有 就使用CGLIB代理 如果有 就使用JDK代理; 当然也有其他几种情况. 其他几种情况
    代码给大家贴下来:
@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		optimize为true,或proxyTargetClass为true,或用户没有给ProxyFactory对象添加interface
		if (!NativeDetector.inNativeImage() &&
				(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);
		}
	上面判断都为false 或者 !NativeDetector.inNativeImage()false 直接使用JDK代理;
		else {
		
			return new JdkDynamicAopProxy(config);
		}
	}

总结:

1:本章介绍了 (我个人) 寻找源码的方式;

2:介绍了AOP 的几个知识点(还未分析每个知识点的具体逻辑;)

3:介绍了AOP 是通过什么创建代理对象的 是在什么时机创建的.是怎么判断是CGLIB代理 还是JDK代理 的


下一篇知识点. 我们将会展开整个AOP 使用代理类; 使用AspectJ 彻底讲解注解的应用. 执行顺序; 以及AOP使用的责任链模式执行过程;沉浸式学习 Spring AOP 将会理解的透彻.

[因为工作缘故,更新速度较慢.作者也是特别无奈.因为一片文章需要我大量的阅读源码;]
[希望能尽自己所能,把自己理解的东西.呈现出来给读者.]

seeyou