1.spring aop代理对象创建以及调用invoke源码
2.å¦ä½å®ä¹ä¸ä¸ªaopç»ä»¶
3.Spring Aop 常见注解和执行顺序
4.Spring注解驱动开发二狗子让我给他讲讲@EnableAspectJAutoProxy注解
5.Spring-AOP 及 AOP获取request各项参数操作
6.使springAOP生效不一定要加@EnableAspectJAutoProxy注解
spring aop代理对象创建以及调用invoke源码
深入解析Spring AOP代理对象创建及调用invoke源码
一、代理对象创建与invoke源码概览
1.1 代理对象创建源码概览
Spring AOP代理对象的看a看注创建时机主要在实例化后或初始化后。具体流程涉及BeanPostProcessor.postProcessAfterInitialization()方法。注解正常情况下,源码源码代理对象创建与单例池内的何查代理对象一致,确保方法调用实际指向代理对象。看a看注-10101源码
1.2 invoke执行目标方法源码概览
目标对象方法调用后,注解因为代理对象存储于单例池,源码源码实际调用的何查是代理对象的增强方法。这种方式实现了方法调用的看a看注动态代理。
1.3 exposeProxy = true使用说明
1.3.1 不使用(exposeProxy = true)
不使用配置时,注解目标方法内部调用被拦截增强的源码源码方法,不会再次触发AOP。何查
1.3.2 使用(exposeProxy = true)
启用此配置后,看a看注执行目标方法时,注解AOP增强将再次激活,从而触发重复执行。
1.3.3 cglib与JDK代理区别
cglib通过继承实现代理,方法调用指向代理对象,因此内嵌方法会重复调用增强逻辑;
JDK代理通过反射,方法调用直接指向目标对象,内嵌方法不会重复调用。
关于Spring中cglib不会重复调用的解释:测试表明,使用Spring5.版本,强制使用cglib配置时,案例中方法调用与代理对象方法调用之间并无重复,原因是Spring调用的是目标方法而非代理对象的方法。
二、代理对象创建及invoke源码分析图
代理创建流程始于@EnableAspectJAutoProxy注解注册的AspectJAutoProxyRegistrar,此注册器在解析import注解时执行registerBeanDefinitions方法。linux perl设置源码该方法注册了在bean实例化前调用的InstantiationAwareBeanPostProcessor类型的bean后置处理器,此处理器在实例化前解析AOP,非循环依赖在初始化后调用postProcessAfterInitialization()创建动态代理。
匹配Advisor集合:首先筛选Advisor列表,匹配规则涉及类级别和方法级别的筛选,通过Aspect匹配实现。同时,Advisor排序确保调用顺序遵循通知类型。创建代理对象遵循ProxyTargetClass参数与目标类接口的配置,选择JDK或cglib动态代理。
代理方法调用:由于存储的是代理对象,方法调用实际指向代理。exposeProxy = true配置下,代理对象暴露到线程变量中。代理对象执行方法调用遵循责任链模式,按顺序执行前置、目标方法、后置等通知。
å¦ä½å®ä¹ä¸ä¸ªaopç»ä»¶
åé¢è¯´è¿äºspringçSchemaæ©å±æ¯æï¼å¯ä»¥çè¿é3.1Springæºç 解æââèªå®ä¹æ ç¾ç使ç¨,è¿éå°±ä¸å¨è¿è¡å¤ä½çå¤è¿°äºãåé¢è®²è¿ï¼Springæ¯æèªå®ä¹çæ©å±ç»ä»¶ï¼ä½æ¯å¿ 须以ä¸ä¸¤ç¹
èªå®ä¹ç±»å¹¶å®ç°SpringçBeanDefinitionParserç±»æ¥è§£æXSDæ件ä¸çå®ä¹åç»ä»¶å®ä¹ï¼
èªå®ä¹ç±»å¹¶å®ç°SpringçNamespaceHandlerSupportç®çæ¯å°ç»å»ºæ³¨åå°Spring容å¨
对åºçæ件ç解æç±»å¯ä»¥å¨META-INFæ件夹çSpring.handlersä¸å¯ä»¥æ¾å°
å¨ä»£ç ä¸å¯¹å®ä¹çAspectç注解è¿è¡è§£æç类为AopNamespaceHandlerï¼
public void init() {// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
å¨è§£æé ç½®æ件çæ¶åï¼ä¸æ¦éå°aspectj-autoproxy注解æ¶å°±ä¼ä½¿ç¨è§£æå¨AspectJAutoProxyBeanDefinitionParserè¿è¡è§£æãä¸ä¸ç¯SpringçAOPç解æââAnnotationAwareAspectJAutoProxyCreator
Spring Aop 常见注解和执行顺序
Spring Aop 常见注解与执行顺序详解
回顾 Spring Aop 中常用注解:Spring Aop 重点在于通知顺序与配置细节,Spring Boot 或 Spring Boot 2 的执行顺序遵循其配置与依赖管理原则。开发者需关注通知的顺序,以及 Spring Boot 版本对 Aop 执行的影响。
常见问题与答案:了解 Aop 全部通知顺序,需理解其执行机制与 Spring Boot 版本特性。在 AOP 开发中,常见坑点涉及配置错误、依赖冲突与通知顺序问题。
示例代码与配置文件:构建 Spring Aop 示例程序,使用 Spring Boot 快速搭建项目。疯狂猜歌源码配置文件中需注意正确引用依赖,避免冲突。
接口与实现类:定义接口并实现除法操作,模拟正常与异常情况。JDK 默认代理实现细节可查阅相关文档。
aop 拦截器与配置:声明拦截器需加 @Aspect 和 @Component 注解,避免仅使用 @Aspect 错误。测试类中应配置 @EnableAspectJAutoProxy 注解以启用 Aop 支持。
执行步骤与Spring Aop 使用步骤包括定义、配置与测试。结论显示环绕通知在 Spring 4 中执行位置,不同版本下执行顺序有所差异。
多切面与优先级:多个切面情况下通过 @Order 指定顺序,优先级由数字大小决定。正确配置切面顺序以优化程序执行。
代理失效场景:在调用方法内部直接调用其他方法导致代理失效,需避免此类操作,以确保 Aop 的正确执行。
Spring注解驱动开发二狗子让我给他讲讲@EnableAspectJAutoProxy注解
在配置类上添加@EnableAspectJAutoProxy注解,能够开启注解版的AOP功能。这意味着,如果在AOP中要启用注解版的AOP功能,就需要在配置类上添加@EnableAspectJAutoProxy注解。让我们来看看@EnableAspectJAutoProxy注解的源码,如下所示。
从源码可以看出,@EnableAspectJAutoProxy注解使用@Import注解引入了AspectJAutoProxyRegister.class对象。那么,AspectJAutoProxyRegistrar是电话小程序源码做什么的呢?我们点击到AspectJAutoProxyRegistrar类的源码中,如下所示。
可以看到AspectJAutoProxyRegistrar类实现了ImportBeanDefinitionRegistrar接口。我们回顾ImportBeanDefinitionRegistrar接口的定义,如下所示。
通过ImportBeanDefinitionRegistrar接口,我们可以实现将自定义的组件添加到IOC容器中。也就是说,@EnableAspectJAutoProxy注解使用AspectJAutoProxyRegistrar对象自定义组件,并将相应的组件添加到IOC容器中。
在AspectJAutoProxyRegistrar类的registerBeanDefinitions()方法中设置断点,我们以debug的方法来运行AopTest类的testAop()方法。当程序运行到断点位置时,我们可以看到程序已经暂停,IDEA的左下角显示了方法的调用栈。
在registerBeanDefinitions()方法中,首先调用AopConfigUtils类的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法来注册registry。在registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中,直接调用了重载的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法。在重载的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中,传入了AnnotationAwareAspectJAutoProxyCreator.class对象。
在registerOrEscalateApcAsRequired()方法中,接收到的Class对象的类型为:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator。然后,我们继续跟进代码。
在registerOrEscalateApcAsRequired()方法中,首先判断registry是否包含org.springframework.aop.config.internalAutoProxyCreator类型的bean。接下来,我们继续看代码。
最终,实体卡系统源码AopConfigUtils类的registerOrEscalateApcAsRequired()方法中,会通过registry调用registerBeanDefinition()方法注册组件,并注册的bean的名称为org.springframework.aop.config.internalAutoProxyCreator。
接下来,我们继续看AspectJAutoProxyRegistrar类的registerBeanDefinitions()源码。我们通过AnnotationConfigUtils类的attributesFor方法来获取@EnableAspectJAutoProxy注解的信息。接下来,我们继续判断proxyTargetClass属性的值是否为true,如果为true则调用AopConfigUtils类的forceAutoProxyCreatorToUseClassProxying()方法;继续判断exposeProxy属性的值是否为true,如果为true则调用AopConfigUtils类的forceAutoProxyCreatorToExposeProxy()方法。
综上所述,向Spring的配置类上添加@EnableAspectJAutoProxy注解后,会向IOC容器中注册AnnotationAwareAspectJAutoProxyCreator。
了解了这些之后,我们就可以关注「冰河技术」微信公众号,后台回复不同的关键字获取相应的PDF文档。这些文档都是由冰河原创并整理的超硬核教程,包括《深入浅出Java 种设计模式》、《Java8新特性教程》和《亿级流量下的分布式限流解决方案》,都是面试必备的资料。
最后,如果你觉得这篇文章对你有帮助,别忘了点个赞,给个在看和转发,让更多的人看到,一起学习,一起进步!
Spring-AOP 及 AOP获取request各项参数操作
AOP称为面向切面编程,主要用于解决系统层面的问题,如日志、事务、权限等。 在Spring框架中,AOP代理依赖于Spring的IoC容器,代理的生成、管理和依赖关系均由容器负责。Spring默认使用JDK动态代理,对于需要代理类而非代理接口的情况,则自动切换为CGLIB代理。尽管项目多采用面向接口编程,JDK动态代理使用依然广泛。 Spring AOP支持基于注解的配置方式: 启用@AspectJ支持:在Spring配置中添加相应的配置,或直接使用注解。 通知类型包括: Before:在目标方法调用前执行增强逻辑,只需指定切入点表达式。 AfterReturning:目标方法正常执行后执行增强逻辑,可指定返回值形参名以获取返回值。 AfterThrowing:处理目标方法中未处理的异常,可指定抛出的异常对象。 After:无论目标方法是否成功执行后执行增强逻辑,指定切入点表达式即可。 Around:环绕通知,在目标方法执行前后均可执行增强逻辑,是最重要的通知类型。 通知执行的优先级:进入目标方法时,先织入Around,再织入Before;退出目标方法时,先织入Around,再织入AfterReturning,最后才织入After。请注意,Spring AOP的环绕通知可能会影响到AfterThrowing通知的运行,通常无需同时使用。 切入点的定义和表达式是AOP的核心,Spring AOP支持执行方法连接点的匹配: execution:匹配执行方法的连接点,定义包括匹配任意方法返回值、服务包及其子包、所有类、所有方法,以及任意参数个数。 within:限定匹配服务包下的任意连接点。 this:限定AOP代理必须是特定类型的实例。 bean:指定IOC容器中的bean名称。 以下是一个使用AOP获取统计计算方法执行时间及请求参数的日志方法示例: 今天实现了一个AOP管理日志功能,遇到了一些麻烦。 接下来贴出相关代码,注意忽略注释部分,以避免强迫症。 在实现AOP功能时,除了AOP包,还需要引入一些额外的包,具体可通过搜索引擎查询。 若想将AOP应用于controllers,请在MVC配置中添加相应的代码。在纠结了一上午后,发现原因在于控制器类中只有request和response两个参数。 在AOP中实现request参数获取,可以使用以下代码: 代码示例:获取从页面上传过来的所有参数以及参数名。 通过`request.getParameter(a)`可获取参数值,参数名使用`a`表示。 在AOP中实测此方法正常工作,但在拦截器中应用时,偶尔返回`date`类型值,对于GET请求可能偶尔正常,而POST请求则始终异常。在AOP环境中,此方法无问题。使springAOP生效不一定要加@EnableAspectJAutoProxy注解
在上篇文章《springAOP和AspectJ有关系吗?如何使用springAOP面向切面编程》中,我们留有一个问题:在使用springboot进行开发时,是否需要在启动类上添加@EnableAspectJAutoProxy注解来启用springAOP?
接下来,我们通过一个示例来解析这个问题。业务类、切面类、测试的controller以及sprinboot的启动类都已经设定好,测试结果显示,即使未添加@EnableAspectJAutoProxy注解,AOP也依然生效。这是为什么?难道网络上的普遍说法有误?
答案在依赖配置中。在pom.xml文件中,存在spring-boot-starter-web依赖,该依赖会引入spring-boot-autoconfigure。此自动配置依赖在spring.factories文件中进行配置,其中包含了AopAutoConfiguration类。该类的作用等同于@EnableAspectJAutoProxy注解。
详细解析AopAutoConfiguration类时,我们会发现其注释表明了该类的设置与@EnableAspectJAutoProxy注解相同。重点在于@ConditionalOnProperty注解,它表示如果配置文件中存在“spring.aop.auto”配置项且值为true,则该类生效。在当前配置文件中未配置此属性。
于是,我们尝试在配置文件中增加“spring.aop.auto”配置项,并设置值为false。重启服务后,测试结果表明,此时AOP功能并未启动。然后,我们为启动类添加@EnableAspectJAutoProxy注解,再次进行测试,结果显示AOP功能恢复正常。
综上所述,在springboot环境下,由于默认引入了自动配置依赖,此依赖内含的AopAutoConfiguration类作用与@EnableAspectJAutoProxy相同,所以不添加@EnableAspectJAutoProxy注解时,AOP依然能正常工作。但为了确保功能的可靠启用,推荐在启动类上添加@EnableAspectJAutoProxy注解。
Springboot整合AOP和注解,实现丰富的切面功能
在之前的文章《Spring AOP与AspectJ的应用详解》中,我们已经探讨了AOP的基本使用。本文将深入讲解如何结合注解,进一步提升AOP的灵活性。我们以实现一个简单的计时功能为例,来展示这一过程。
首先,我们创建一个自定义注解,为后续的切面处理做准备:
<!-- 注解定义 -->
然后,在一个Service类中,我们应用这个注解到需要计时的方法:
<!-- Service中的方法 -->
这个方法会被控制器调用,进而触发我们的AOP处理:
<!-- 控制器调用 -->
关键在于实现切面,利用Spring的@Around注解来识别带有我们自定义注解的方法。表达式如下,务必确保其准确性,以避免识别错误和潜在的多次调用问题(更多细节可参考Stackoverflow):
<!-- 切面实现 -->
@Around("@annotation(com.pkslow.springboot.aop.PkslowLogTime) && execution(* *(..))")
这里借助Spring的StopWatch来记录方法执行时间。
接下来,我们进行测试。通过Maven构建项目:
<!-- 测试阶段 -->
在日志中,你会看到切面织入的痕迹:
<!-- 日志输出 -->
启动应用并访问相关接口,你会看到计时信息的实时记录:
总的来说,通过注解与AOP的结合,我们可以轻松实现各种功能,并且通过注解的参数化和组合,进一步增强了灵活性。如果你对这个例子感兴趣,可以在GitHub上查看详细代码:<a href="github.com/LarryDpk/pks...">github.com/LarryDpk/pks...