Spring AOP源码分析(七)ProxyFactoryBean介绍
2023-09-14 08:59:44 时间
这篇文章里面就要说说Spring自己的AOP,搞清楚哪种方式是Spring自己实现的AOP,哪种方式是Spring引入aspectj的AOP。
Spring自己的AOP实现在于ProxyFactoryBean。先看下使用案例(仍和之前的案例是一样的):接口AService、实现类AServiceImpl、通知MyBeforeAdvice
?
No qualifying bean of type [com.lg.aop.service.AService] is defined: expected single matching bean but found 2: aServiceImpl,org.springframework.aop.framework.ProxyFactoryBean#0
原因就是对于接口AService,有两个实现类aServiceImpl和ProxyFactoryBean所生产的代理类。所以我们不能使用@Autowired(它是按类型注入),所以要使用按名称注入,我们怎么获取ProxyFactoryBean所产生的代理类的名称呢?其实就是ProxyFactoryBean配置的名称。因为ProxyFactoryBean实现了FactoryBean接口,对于这种接口从容器中获取该bean,不是获取的本身而是获取他的getObject方法所返回的值,看FactoryBean的文档:
?
所以通过beanName找到了ProxyFactoryBean,然而不是返回该对象,而是返回他的getObject方法的返回值,所以我们通过ProxyFactoryBean的id就可以获取到它所产生的代理对象,所以更改如下:
?
然后我们就要源码分析下这一过程,先看下是如何产生代理对象的,在ProxyFactoryBean的getObject方法中:
?
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the targetName property.");
重点1:就是根据我们配置的interceptorNames来获取对应的bean,并却转化成Advisor。如下:
?
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
// Globals cant be last unless we specified a targetSource using the property...
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX)
this.targetName == null this.targetSource == EMPTY_TARGET_SOURCE) {
"Can only use global advisors or interceptors with a ListableBeanFactory");
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
// Its a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
this.advisorChainInitialized:标示是否已进行过初始化,若以初始化则不再进行初始化。然后就是将interceptorNames转化成Advisor。根据interceptorNames所包含的字符串到容器中进行查找,如果含有*则,则表示进行一定的匹配,符合的都会纳入。如官方文档中说的:
?
这个包裹过程已经见过很多遍了,采用了适配器的模式。
之后又是和其他的AOP方式接轨了,设置一些列要实现的接口和参数,使用DefaultAopProxyFactory先创建出AopProxy,要么是JdkDynamicAopProxy,要么是CglibAopProxy,然后就可以调用AopProxy的getProxy方法来获取代理对象了。这个过程详见上一篇博客http://lgbolgger.iteye.com/blog/2119810。
这种方式实现的AOP还是比较麻烦的,同时配置一个ProxyFactoryBean仅能实现对一个目标对象的拦截,要想拦截多个目标对象,需要配置多个ProxyFactoryBean。所以大部分还是使用Spring引进的aspectj的AOP方式来进行AOP编程。
Spring 源码阅读 62:基于 JDK 的 AOP 代理对特殊方法调用的处理 本文深入分析了 JdkDynamicAopProxy 的invoke方法的第一部分逻辑,也就是,对于哪些方法的调用,不对其进行增强,而是执行对应的特定逻辑,从中可以了解,Spring AOP 对哪些方法是默认不进行增强的。
Spring 源码阅读 61:基于 JDK 动态代理的 AOP 代理回调方法 invoke 分析 本文分析了 JdkDynamicAopProxy 的invoke方法,invoke方法是基于 JDK 动态代理创建的 AOP 代理对象的方法处理回调逻辑,也是 Spring AOP 增强目标方法的关键逻辑。
阿里特邀专家徐雷Java Spring Boot开发实战系列课程(第18讲):制作Java Docker镜像与推送到DockerHub和阿里云Docker仓库 立即下载
Spring自己的AOP实现在于ProxyFactoryBean。先看下使用案例(仍和之前的案例是一样的):接口AService、实现类AServiceImpl、通知MyBeforeAdvice
?
No qualifying bean of type [com.lg.aop.service.AService] is defined: expected single matching bean but found 2: aServiceImpl,org.springframework.aop.framework.ProxyFactoryBean#0
原因就是对于接口AService,有两个实现类aServiceImpl和ProxyFactoryBean所生产的代理类。所以我们不能使用@Autowired(它是按类型注入),所以要使用按名称注入,我们怎么获取ProxyFactoryBean所产生的代理类的名称呢?其实就是ProxyFactoryBean配置的名称。因为ProxyFactoryBean实现了FactoryBean接口,对于这种接口从容器中获取该bean,不是获取的本身而是获取他的getObject方法所返回的值,看FactoryBean的文档:
?
所以通过beanName找到了ProxyFactoryBean,然而不是返回该对象,而是返回他的getObject方法的返回值,所以我们通过ProxyFactoryBean的id就可以获取到它所产生的代理对象,所以更改如下:
?
然后我们就要源码分析下这一过程,先看下是如何产生代理对象的,在ProxyFactoryBean的getObject方法中:
?
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the targetName property.");
重点1:就是根据我们配置的interceptorNames来获取对应的bean,并却转化成Advisor。如下:
?
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
// Globals cant be last unless we specified a targetSource using the property...
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX)
this.targetName == null this.targetSource == EMPTY_TARGET_SOURCE) {
"Can only use global advisors or interceptors with a ListableBeanFactory");
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
// Its a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
this.advisorChainInitialized:标示是否已进行过初始化,若以初始化则不再进行初始化。然后就是将interceptorNames转化成Advisor。根据interceptorNames所包含的字符串到容器中进行查找,如果含有*则,则表示进行一定的匹配,符合的都会纳入。如官方文档中说的:
?
这个包裹过程已经见过很多遍了,采用了适配器的模式。
之后又是和其他的AOP方式接轨了,设置一些列要实现的接口和参数,使用DefaultAopProxyFactory先创建出AopProxy,要么是JdkDynamicAopProxy,要么是CglibAopProxy,然后就可以调用AopProxy的getProxy方法来获取代理对象了。这个过程详见上一篇博客http://lgbolgger.iteye.com/blog/2119810。
这种方式实现的AOP还是比较麻烦的,同时配置一个ProxyFactoryBean仅能实现对一个目标对象的拦截,要想拦截多个目标对象,需要配置多个ProxyFactoryBean。所以大部分还是使用Spring引进的aspectj的AOP方式来进行AOP编程。
Spring 源码阅读 62:基于 JDK 的 AOP 代理对特殊方法调用的处理 本文深入分析了 JdkDynamicAopProxy 的invoke方法的第一部分逻辑,也就是,对于哪些方法的调用,不对其进行增强,而是执行对应的特定逻辑,从中可以了解,Spring AOP 对哪些方法是默认不进行增强的。
Spring 源码阅读 61:基于 JDK 动态代理的 AOP 代理回调方法 invoke 分析 本文分析了 JdkDynamicAopProxy 的invoke方法,invoke方法是基于 JDK 动态代理创建的 AOP 代理对象的方法处理回调逻辑,也是 Spring AOP 增强目标方法的关键逻辑。
阿里特邀专家徐雷Java Spring Boot开发实战系列课程(第18讲):制作Java Docker镜像与推送到DockerHub和阿里云Docker仓库 立即下载
相关文章
- Spring学习笔记(十八)——spring日志框架的配置和使用
- 简单介绍一下spring bean的生命周期_Spring bean的生命周期
- Spring Cloud OpenFeign调用流程
- 服务容错的必要性与Spring Cloud Alibaba Sentinel 限流配置实战
- Spring MVC注解Controller源码流程解析--映射建立
- 【06】Spring源码-分析篇-ApplicationContext
- Spring IoC/AOP/Transaction/MVC 归纳小结
- 【10】Spring源码-分析篇-AOP源码分析
- mybatis3源码解析--spring下mapper注册详解
- Spring循环依赖-spring源码详解(四)
- 使用GraalVM 构建 Spring Boot 3.0 原生可执行文件
- 消息总线(Spring Cloud Bus)
- 记一次Spring中HttpMessageConverter的源码分析
- 【Spring源码】- 07 扩展点之自定义标签
- 【Spring源码】- 08 扩展点之mybatis集成
- 【Spring源码】- 10 Spring AOP核心API
- Spring Boot 源码解读与原理剖析|文末赠书
- 用Spring Boot复刻一款天猫商城,你可以做到!
- Spring Cloud Gateway负载均衡-随机策略
- Spring Cloud Bus使用自定义的消息转换器(三)
- 【愚公系列】2023年04月 Java教学课程 136-Spring MVC框架的Request请求详解
- spring的AOP(四)—-Spring AOP 编程(Advisor)详解编程语言
- Spring IOC/BeanFactory/ApplicationContext的工作流程/实现原理/初始化/依赖注入源码详解编程语言
- 关于org.mybatis.spring.MyBatisSystemException:Parameter ‘userId’ not found. 错误调试详解编程语言
- Spring Boot 2 (六):使用 Docker 部署 Spring Boot 开源软件云收藏详解编程语言
- php转java 系列2 Spring boo 链接数据库jdbc详解编程语言
- Spring框架下整合Redis的实现(spring整合redis)