摘要: 1.从架构进行说起 注释: CBO:基于成本的优化 RBO:基于效率的优化 2.分类阐述 3.二次提交 执行流程: 1、执行器先从引擎中找到数据,如果在内存中直接返回,如果不在内存中,查询后返回 2、执行器拿到数据之后会先修改数据,然后调用引擎接口重新写入数据 3、引擎将数据更新到内存,同时写数据到 阅读全文
posted @ 2022-10-10 19:35 湫龙 阅读(128) 评论(0) 推荐(0) 编辑

AOPSpring Core中几大重要能力之一,我们可以使用AOP实现很多功能,比如我们常用的日志处理与Spring中的声明式事务。

AOP的重要概念:

1.Aspect:切面,在Spring中意为所有通知方法所在的类
2.Join point:连接点,程序执行中的一点,在Spring中只表示方法执行(Spring只支持方法级别的拦截)
3.Advice:通知,在特定连接点上采取的操作,Spring将通知抽象为拦截器,并围绕连接点维护拦截器链。
4.Pointcut:切点,与通知一起出现,使用专门的切点表达式决定在何处执行通知方法。
5.Introduction:引入,为类添加新的方法或字段。
6.Target object:被代理的对象
7.AOP proxy:AOP代理对象,由JDK动态代理或CGLIB代理生成
8.Weaving:织入,将通知等织入代理类。Spring AOP是动态织入(运行时织入),AspectJ则是静态织入(编译时织入)

注:五种通知类型:

1.before(切点之前执行),
2.around(环绕执行,即切点前后执行),
3.After returning(切点正常执行完返回后执行),
4.After throwing(切点抛出异常后执行),
5.after(切点之后执行,不管是异常或正常结束)

几点注意:

  由于Spring AOP框架基于代理的特性,目标对象内的调用根据定义不会被拦截。
  自调用即类似this.bar()或this.foo()这样的调用,即使在bar方法上有通知方法通知也不会执行。
  对于JDK代理,只能拦截代理上的公共接口方法调用。
  使用CGLIB,可以拦截代理上的公共和受保护方法调用(Cglib基于子父类实现代理,而私有方法不会被子类继承)。
  当多个通知都想在同一个连接点上运行时,他们将按照优先级顺序执行,优先级顺序可以使用Order接口来定义。
总结一句:自调用通知方法不执行,私有方法通知不执行。

原理

接下来从源码角度分析下Spring AOP的实现原理。

在Spring中我们使用@EnableAspectJautoProxy开启AOP功能,我们以此为入口。(其他的Enable注解分析原理都是一样的,比如EnableAsync等)

 

 它使用@Import注解导入了AspectJAutoProxyRegistrar类,该类实现了ImportBeanDefinitionRegistrar接口,用于向Spring中注册类。

 

 在registerBeanDefinitions方法的第一行注册了AOP需要的相关bean,方法中的下面部分是取EnableAspectJAutoProxy注解的信息,根据参数值做相应的处理,这里主要关注方法的首行代码,进入registerAspectJAnnotationAutoProxyCreatorIfNecessary方法。

 

 发现最终注册了AnnotationAwareAspectJAutoProxyCreator。该类是实现AOP的基础,我们对该类进行分析,首先来看继承结构

 

 BeanFactoryAware接口主要用于设置BeanFactory,这里我们主要关注InstantiationAwareBeanPostProcessor与BeanPostProcessor接口,实现这两个接口意味着AnnotationAwareAspectJAutoProxyCreator是一个Spring的后置处理器,后置处理器会在bean的创建过程中起作用,关于后置处理器不熟悉的同学可以去看这篇文章Spring之IOC容器初始化。

 

 InstantiationAwareBeanPostProcessor有一个before与after接口,由接口名可知两个方法分别在bean实例化前后调用,关于Spring中bean的实例化过程不清楚的可以看Spring Bean的实例化分析。我们在子类中找到他们的实现(after方法由于没有特别的处理这里就省略了)

 

 

首先从缓存中获取,然后调用this.isInfrastructureClass(beanClass)判断创建的类是否为Advice、Pointcut等相关类,若是则放入adviseBean集合并返回null,正常的bean经过该方法会返回null,这里主要是用来处理我们的切面类。

 

 bean创建完成后接下来就是另一个接口BeanPostprocess(实例化,调用构造函数)开始起作用了。

 

 他会在InstantiationAwareBeanPostProcessor(初始化,即BeanDefination的初始化)接口方法执行完之后调用,查看其实现(before方法由于没有特别的处理这里就省略了)

 

 最终会调用wrapIfNecessary方法判断该bean是否需要增强。进入方法

 

 正常bean的创建会进入到isInfrastructureClass这个分支,isInfrastructureClass这个方法就是之前分析的判断是否是Aspect等注解的类,如果不是则调用getAdvicesAndAdvisorsForBean方法获取到符合该bean的通知方法(即相应的Advisor)。

 

 最终调用createProxy创建代理对象。

 

 接上图右侧
最终进入代理工厂创建代理对象的方法,根据是否实现接口自动选择创建JDK动态代理(基于接口)或者是Cglib代理(基于子父类)。到这里切面以及要被代理的类就都创建完成了,接下来就是如何运行通知方法了。

执行流程

我们这里假设上一步创建的对象为Cglib对象,了解过Cglib代理的同学都知道实现代理要实现MethodInterceptor接口,在里面的intercept方法中进行方法的拦截。我们找到代理类的intercept方法

 

 首先调用getInterceptorsAndDynamicInterceptionAdvice方法获取所有通知方法的Advisor拦截器链,chain不为空会依次调用对应的Advisor拦截器的proceed方法进行代理调用,在此会按照通知的顺序执行原方法与通知方法。

 

 

大体的执行流程就分析完了,有时间的同学最好简单写个demo然后跟着一步步debug,这样能够更清晰的了解流程。

最后总结一下,容器初始化时将切面等信息放入通知集合中,正常bean在创建时会判断该bean是否需要被增强,若需要增强,创建相应的代理对象。在执行时,代理对象执行相应的invoke方法,在方法中获取到通知集合并抽象成拦截器链,使用拦截器模式按照顺序执行相应的方法。

附两张流程图:

 

 

 参考博客:https://blog.csdn.net/u014735138/article/details/124072540

posted @ 2022-12-11 16:25 湫龙 阅读(796) 评论(0) 推荐(0) 编辑
摘要: 1、ApplicationContext VS BeanFactory l 二者来自的 jar 包不同;BeanFactory 来自 spring.beans.jar;ApplicationnContext 来自 spring.context.jar 下。 l BeanFactory 和 Appli 阅读全文
posted @ 2022-12-11 09:40 湫龙 阅读(21) 评论(0) 推荐(0) 编辑
摘要: BeanFactory介绍 BeanFactory是用于访问Spring Bean容器的根接口,是bean容器的最基本的实现。其子接口(如ListableBeanFactory和ConfigurableListableBeanFactory)是用于特定功能的扩展接口。主要是负责bean的创建,访问等 阅读全文
posted @ 2022-12-05 08:22 湫龙 阅读(188) 评论(0) 推荐(0) 编辑
摘要: 一、SpringBean的生命周期 二、后置处理器postProcessor 一个是针对BeanDefinition的容器级别的后处理器 - BeanFactoryPostProcessor 一个是针对getBean操作获得的对象的后处理器 - BeanPostProcessor 两者的不同: 触发 阅读全文
posted @ 2022-11-27 14:06 湫龙 阅读(213) 评论(0) 推荐(0) 编辑
摘要: 一.快问快答1.为什么需要使用时间这种模式?上面将注册的主要逻辑(用户信息落库)和次要的业务逻辑(发送邮件)通过事件的方式解耦了。次要的业务做成了可插拔的方式,比如不想发送邮件了,只需要将邮件监听器上面的@Component注释就可以了,非常方便扩展。2.spring中实现事件1.面相接口的方式(A 阅读全文
posted @ 2022-11-20 15:22 湫龙 阅读(1989) 评论(0) 推荐(0) 编辑
摘要: 1.整体启动流程 Spring的启动流程可以归纳为三个步骤: 1、初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中 2、将配置类的BeanDefinition注册到容器中 3、调用refresh()方法刷新容器 因为是基于 java-conf 阅读全文
posted @ 2022-11-13 15:39 湫龙 阅读(707) 评论(0) 推荐(0) 编辑
摘要: 阅读全文
posted @ 2022-11-13 14:49 湫龙 阅读(38) 评论(0) 推荐(0) 编辑
摘要: 日志类型 数据类型 1.更小的通常更好能正确存储的最小数据类型,优点是占用磁盘、内存和CPU都少2.简单就好3.尽量避免使用null在数据库中null不等于null对游湖和索引和值的比较都很复杂 MyISAM和InnoDB存储引擎对比 对比项MyISAMInnoDB 主外键 不支持 支持 事务 不支 阅读全文
posted @ 2022-10-23 12:28 湫龙 阅读(20) 评论(0) 推荐(0) 编辑
摘要: 1.Hash 哈希表是键值对的集合,通过键(key)值即可快速的取出对应的值(value),因此hash表查询的速度很快。但是,哈希算法有hash冲突的问题,也就是说多个不同的key最后得到的index相同,虽然hash通过链表的方法解决了hash冲突,但是如果使用hash用来存储数据,mysql可 阅读全文
posted @ 2022-10-23 11:27 湫龙 阅读(141) 评论(0) 推荐(0) 编辑
摘要: MySQL数据结构之最左匹配 MySQL InnoDB B+树,叶子节点直接放置整条数据注意: InnoDB是通过B+Tree结构对主键创建索引,然后叶子节点中存储记录,如果没有主键,那么会选择唯一键,如果没有唯一键,那么会生成一个6字节的row_id来作为主键 如果创建索引的键是其他字段,那么在叶 阅读全文
posted @ 2022-10-10 19:52 湫龙 阅读(48) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示