1.代理模式与静态代理、码讲动态代理的码讲实现(Proxy.newProxyInstance、InvocationHandler)
2.SpringBoot源码学习——SpringBoot自动装配源码解析+Spring如何处理配置类的码讲
3.动态代理(2)-CGLIB核心原理和JDK区别
4.76 张图,剖析 Spring AOP 源码,码讲小白居然也能看懂,码讲大神,码讲妖股公式源码选股请收下我的码讲膝盖!
5.cglib底层源码分析(⼆)
代理模式与静态代理、码讲动态代理的码讲实现(Proxy.newProxyInstance、InvocationHandler)
代理模式在设计模式中被广泛应用,码讲尤其是码讲在Android开发中,如Retrofit利用动态代理实现API接口调用,码讲Dagger使用代码生成和反射机制创建依赖注入代理。码讲本文将详细解释代理模式,码讲并探讨静态代理与动态代理的码讲实现方式。
代理模式的核心思想在于不直接访问目标对象,而是通过访问代理对象来间接操作目标。例如,与明星打交道时,通过经纪人(代理)进行联系而非直接接触明星。这种方式能实现目标对象功能的扩展,增强额外操作。
代理模式实现有静态代理与动态代理。静态代理中代理与目标对象共用接口或继承同一父类。操作流程如下:定义接口或父类、目标对象类、代理对象类、使用代理类。静态代理易于理解,但存在代码冗余和扩展性差的缺点。
动态代理是通过运行时生成代理对象实现的,无需代理与目标对象共用接口。Java中Proxy类提供方法生成代理对象。动态代理在内存中构建代理类,允许在运行时为目标对象添加功能,而无需修改源代码。实现过程包括确定目标接口、源码火炮目标对象、调用newProxyInstance生成代理对象、使用代理对象。
动态代理实现了灵活性与扩展性,是实际开发中更常用的代理模式。但代理对象仍需目标对象实现接口。对于未实现接口的目标对象,可使用cglib或ByteBuddy库进行代理。
cglib库虽能实现非接口目标对象的代理,但已不再维护,新版本Java中可能存在兼容性问题。因此,推荐使用ByteBuddy库。ByteBuddy库在代理非接口目标对象方面提供了更稳定、高效的解决方案。
总结,代理模式提供了一种在不修改目标对象代码的情况下扩展其功能的方法。静态代理简洁直观,但存在扩展性限制;动态代理则在运行时实现代理,提供更多灵活性,但需目标对象实现接口。对于未实现接口的目标对象,可借助cglib或ByteBuddy库实现代理。选择合适的代理模式及库能够有效提升系统设计与实现的灵活性与效率。
SpringBoot源码学习——SpringBoot自动装配源码解析+Spring如何处理配置类的
SpringBoot通过SPI机制,借助外部引用jar包中的META-INF/spring.factories文件,实现引入starter即可激活功能,简化手动配置bean,实现即开即用。
启动SpringBoot服务,通常使用Main方法启动,其中@SpringBootApplication注解包含@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan,自动装配的核心。
深入分析@SpringBootApplication,vixl源码其实质是执行了@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解的功能,简化了配置过程,强调了约定大于配置的思想。
SpringBoot的自动装配原理着重于研究如何初始化ApplicationContext,Spring依赖于ApplicationContext实现其功能,SpringApplication#run方法为初始化ApplicationContext的入口。
分析SpringApplication构造方法,SpringApplication.run(启动类.class, args) 实际调用的是该方法,其关键在于根据项目类型反射生成合适的ApplicationContext。
选择AnnotationConfigServletWebServerApplicationContext,此上下文具备启动Servlet服务器和注册Servlet或过滤器类型bean的能力。
准备刷新ApplicationContext,SpringBoot将主类注册到Spring容器中,以便@ConfigurationClassPostProcessor解析主类注解,发挥@Import、@ComponentScan的作用。
刷新ApplicationContext过程包括一系列前置准备,如将主类信息封装成AnnotatedGenericBeanDefinition,解析注解并调用BeanDefinitionCustomizer自定义处理。
解析配置类中的注解,通过BeanDefinitionRegistryPostProcessor和ConfigurationClassParser实现,筛选、排序候选者,并解析@Import注解实现自动装配。
增强配置类,ConfigurationClassPostProcessor对full模式的配置进行增强,确保@Import正确处理,CGLIB用于增强原配置类,确保生命周期完整,避免真正执行@Bean方法逻辑。
深入解析AutoConfigurationImportSelector实现自动装配,通过spring.boot.enableautoconfiguration设置开启状态,读取spring-autoconfigure-metadata.properties和META-INF/spring.factories文件,筛选并加载自动配置类。kep源码
动态代理(2)-CGLIB核心原理和JDK区别
在先前的文章中,我们探讨了动态代理的应用以及JDK动态代理的核心原理。本文将继续探讨CGLIB的核心原理及其与JDK动态代理的区别。
JDK动态代理存在一个限制,它无法代理那些没有实现接口的对象。这是因为动态代理需要通过实现接口来创建代理类。然而,这种限制在实际应用中可能引起一些不便。例如,当需要代理一个没有接口的第三方类,或者根本不希望编写接口时,这种限制就变得尤为明显。正是在这种背景下,CGLIB应运而生。
CGLIB通过创建一个继承目标类的代理类来实现动态代理。与JDK动态代理不同,CGLIB不通过实现接口来创建代理类,而是通过继承来达到目的。尽管方法的工作逻辑都需要在外部定义,并将其传递给自动生成的代理类,但CGLIB和JDK动态代理在这一方面是相似的。
在代码层面,CGLIB的使用方式与JDK动态代理相似。用户首先提出代理需求,然后Java自动生成代理类。这种模式在CGLIB中同样适用。
CGLIB的核心源码包括创建代理逻辑和生成class对象的方法。在创建代理逻辑时,CGLIB使用缓存机制来提高性能。当需要创建代理类时,如果缓存中不存在对应的类对象,则会将其包装为一个异步任务FutureTask,并将其放置在缓存中。这种设计可以有效地处理多线程环境下类对象的创建。
CGLIB生成的类包括代理对象类和两个FastClass。FastClass是smbclient 源码对代理类和目标类方法的签名hash映射,这使得CGLIB可以直接调用这些方法,避免了反射调用。
总结来说,CGLIB和JDK动态代理在实现方式、性能和适用场景上存在一定的差异。JDK动态代理要求目标类实现接口,而CGLIB可以代理没有接口的类。此外,CGLIB采用继承的方式创建代理类,而JDK动态代理通过实现接口。在性能方面,CGLIB采用FastClass机制,避免了反射调用,从而提高了性能。
张图,剖析 Spring AOP 源码,小白居然也能看懂,大神,请收下我的膝盖!
本文将简要介绍AOP(面向切面编程)的基础知识与使用方法,并深入剖析Spring AOP源码。首先,我们需要理解AOP的基本概念。
1. **基础知识
**1.1 **什么是AOP?
**AOP全称为Aspect Oriented Programming,即面向切面编程。AOP的思想中,周边功能(如性能统计、日志记录、事务管理等)被定义为切面,核心功能与切面功能独立开发,然后将两者“编织”在一起,这就是AOP的核心。
AOP能够将与业务无关、却为业务模块共同调用的逻辑封装,减少系统重复代码,降低模块间的耦合度,有利于系统的可扩展性和可维护性。
1.2 **AOP基础概念
**解释较为官方,以下用“方言”解释:AOP包括五种通知分类。
1.3 **AOP简单示例
**创建`Louzai`类,添加`LouzaiAspect`切面,并在`applicationContext.xml`中配置。程序入口处添加`"睡觉"`方法并添加前置和后置通知。接下来,我们将探讨Spring内部如何实现这一过程。
1.4 **Spring AOP工作流程
**为了便于理解后面的源码,我们将整体介绍源码执行流程。整个Spring AOP源码分为三块,结合示例进行讲解。
第一块是前置处理,创建`Louzai`Bean前,遍历所有切面信息并存储在缓存中。第二块是后置处理,创建`Louzai`Bean时,主要处理两件事。第三块是执行切面,通过“责任链+递归”执行切面。
2. **源码解读
**注意:Spring版本为5.2..RELEASE,否则代码可能不同!这里,我们将从原理部分开始,逐步深入源码。
2.1 **代码入口
**从`getBean()`函数开始,进入创建Bean的逻辑。
2.2 **前置处理
**主要任务是遍历切面信息并存储。
这是重点!请务必注意!获取切面信息流程结束,后续操作都从缓存`advisorsCache`获取。
2.2.1 **判断是否为切面
**执行逻辑为:判断是否包含切面信息。
2.2.2 **获取切面列表
**进入`getAdvice()`,生成切面信息。
2.3 **后置处理
**主要从缓存拿切面,与`Louzai`方法匹配,创建AOP代理对象。
进入`doCreateBean()`,执行后续逻辑。
2.3.1 **获取切面
**首先,查看如何获取`Louzai`的切面列表。
进入`buildAspectJAdvisors()`,方法用于存储切面信息至缓存`advisorsCache`。随后回到`findEligibleAdvisors()`,从缓存获取所有切面信息。
2.3.2 **创建代理对象
**有了`Louzai`的切面列表,开始创建AOP代理对象。
这是重点!请仔细阅读!这里有两种创建AOP代理对象方式,我们选择使用Cglib。
2.4 **切面执行
**通过“责任链+递归”执行切面与方法。
这部分逻辑非常复杂!接下来是“执行切面”最核心的逻辑,简述设计思路。
2.4.1 **第一次递归
**数组第一个对象执行`invoke()`,参数为`CglibMethodInvocation`。
执行完毕后,继续执行`CglibMethodInvocation`的`process()`。
2.4.2 **第二次递归
**数组第二个对象执行`invoke()`。
2.4.3 **第三次递归
**数组第三个对象执行`invoke()`。
执行完毕,退出递归,查看`invokeJoinpoint()`执行逻辑,即执行主方法。回到第三次递归入口,继续执行后续切面。
切面执行逻辑已演示,直接查看执行方法。
流程结束时,依次退出递归。
2.4.4 **设计思路
**这部分代码研究了大半天,因为这里不是纯粹的责任链模式。
纯粹的责任链模式中,对象内部有一个自身的`next`对象,执行当前对象方法后,启动`next`对象执行,直至最后一个`next`对象执行完毕,或中途因条件中断执行,责任链退出。
这里`CglibMethodInvocation`对象内部无`next`对象,通过`interceptorsAndDynamicMethodMatchers`数组控制执行顺序,依次执行数组中的对象,直至最后一个对象执行完毕,责任链退出。
这属于责任链,实现方式不同,后续会详细剖析。下面讨论类之间的关系。
主对象为`CglibMethodInvocation`,继承于`ReflectiveMethodInvocation`,`process()`的核心逻辑在`ReflectiveMethodInvocation`中。
`ReflectiveMethodInvocation`的`process()`控制整个责任链的执行。
`ReflectiveMethodInvocation`的`process()`方法中,包含一个长度为3的数组`interceptorsAndDynamicMethodMatchers`,存储了3个对象,分别为`ExposeInvocationInterceptor`、`MethodBeforeAdviceInterceptor`、`AfterReturningAdviceInterceptor`。
注意!这3个对象都继承了`MethodInterceptor`接口。
每次`invoke()`调用时,都会执行`CglibMethodInvocation`的`process()`。
是否有些困惑?别着急,我将再次帮你梳理。
对象与方法的关系:
可能有同学疑惑,`invoke()`的参数为`MethodInvocation`,没错!但`CglibMethodInvocation`也继承了`MethodInvocation`,可自行查看。
执行逻辑:
设计巧妙之处在于,纯粹的责任链模式中,`next`对象需要保证类型一致。但这里3个对象内部没有`next`成员,不能直接使用责任链模式。怎么办呢?就单独设计了`CglibMethodInvocation.process()`,通过无限递归`process()`实现责任链逻辑。
这就是我们为什么要研究源码,学习优秀的设计思路!
3. **总结
**本文首先介绍了AOP的基本概念与原理,通过示例展示了AOP的应用。之后深入剖析了Spring AOP源码,分为三部分。
本文是Spring源码解析的第三篇,感觉是难度较大的一篇。图解代码花费了6个小时,整个过程都沉浸在代码的解析中。
难度不在于抠图,而是“切面执行”的设计思路,即使流程能走通,将设计思想总结并清晰表达给读者,需要极大的耐心与理解能力。
今天的源码解析到此结束,有关Spring源码的学习,大家还想了解哪些内容,欢迎留言给楼仔。
cglib底层源码分析(⼆)
通过观察cglib生成的代理类,可以推测出其生成原理。代理类通常继承自目标类并实现了Factory接口。这使得代理需要实现Factory接口中的方法。具体而言,newInstance()方法用于生成代理对象,而setCallbacks()和getCallbacks()方法则用于设置或获取增强逻辑。
代理类会为任何方法生成对应的方法,如equals()、toString()、hashCode()和clone()等。这些方法的实现已经在前一篇文章中进行了说明。对于代理类中不熟悉的代码,主要集中在大量针对具体方法的Method对象和MethodProxy对象的属性。在代理类中,有一个代理块调用CGLIB$STATICHOOK1()方法,用于给属性赋值,如构造ThreadLocal对象、获取目标方法的Method对象、创建对应MethodProxy对象等。
值得注意的是,代理类中还有一些方法只生成未调用,其中一个方法是cglib在生成代理对象后主动调用的CGLIB$SET_THREAD_CALLBACKS()方法,用于将设置的Callbacks放入CGLIB$THREAD_CALLBACKS的ThreadLocal中。之后,代理对象执行test()方法时,会从CGLIB$THREAD_CALLBACKS获取设置的Callbacks并调用其intercept()方法。
代理类的生成逻辑包括:首先生成代理类的定义,实现目标类和服务接口;然后根据目标类的方法生成代理类中对应的方法和属性;最后生成辅助的属性和方法。具体源码细节可以自行深入研究。文章至此,未分析MethodProxy对象,下文将继续探讨。
2024-11-27 13:33
2024-11-27 13:20
2024-11-27 12:33
2024-11-27 12:28
2024-11-27 12:20
2024-11-27 12:18