1.【超级干货】为什么spring一定要弄个三级缓存?
2.SpringBoot 玩一玩代码混淆,源码防止反编译代码泄露
3.爆破专栏丨Spring Security系列教程之SpringSecurity中的解读密码加密
4.76 张图,剖析 Spring AOP 源码,源码小白居然也能看懂,解读大神,源码请收下我的解读废品回收 源码膝盖!
5.Spring Boot源码解析(四)ApplicationContext准备阶段
【超级干货】为什么spring一定要弄个三级缓存?
在深入探讨为什么Spring需要实现三级缓存之前,源码我们首先回顾Spring创建bean的解读流程。Spring在获取bean时会经历两到三层缓存的源码检查,这在处理循环依赖问题时尤其关键。解读
具体来说,源码Spring创建bean时,解读如果不存在循环依赖,源码通常只会使用到第一层缓存。解读但当存在循环依赖时,源码第二层和第三层缓存则发挥了重要作用。它们通过缓存对象工厂的返回结果来避免不必要的计算,提高效率。
以一个简单的demo为例,我们假设有两个接口及其实现类相互引用。当创建其中一个实现类时,Spring会先从第一层缓存中查找bean实例。如果没有找到,则可能进入第二或第三层缓存检查。若仍然未找到,Spring会调用对象工厂的`getObject`方法。该方法会先执行`getEarlyBeanReference`,如果返回新对象,则此对象会被缓存以供后续使用。这样,当其他依赖于当前bean的bean需要初始化时,可以避免重复计算,大大提高性能。
现在,让我们回到问题的核心:为什么Spring需要三级缓存?答案在于代理类的引入。代理类可能在bean的初始化过程中被创建,以实现诸如事务管理等功能。Spring通过三级缓存确保了代理类的正确引用,即使在处理循环依赖时也能保持一致。lolsun防封源码这使得在bean实例的创建和初始化之间建立了一层保护,确保了正确的依赖关系。
假设我们仅使用第一层缓存,那么在bean实例创建后,即使需要代理类,也无法确保在循环依赖场景下代理类的正确引用。引入第二层缓存,使得当对象工厂返回新对象时,该对象可以被缓存以供循环依赖的bean引用。第三层缓存则进一步确保了循环依赖场景下,代理类引用的一致性,防止了在初始化完成前代理类引用的混乱。
总的来说,三级缓存的设计并非为了代理类的存在,而是为了处理循环依赖时的复杂性。通过这一设计,Spring能够在提供循环依赖支持的同时,保持高性能和代码的可维护性。
若想进一步深入理解Spring源码,推荐查阅Spring源码深度解析专栏,其中详细解读了Spring的核心机制和源码细节,帮助开发者全面理解Spring框架。
SpringBoot 玩一玩代码混淆,防止反编译代码泄露
编译过程将源代码转换为机器可读的格式,形成 .class 文件。然而,面对反编译工具,如 JD-GUI,开发者可能担心自己的代码会暴露给他人。这时,代码混淆成为了一种有效的防御手段。混淆代码的目标是使反编译变得困难,甚至无法解读原始代码逻辑。
实现混淆的步骤包括:首先,在项目路径下创建一个 proguard.cfg 文件,用于配置哪些类、方法和枚举需要保留,以及哪些不需要混淆。基带芯片源码该文件包含了一系列的规则,以确保代码的结构和逻辑不会被完全破坏。其次,在项目的 pom 文件中添加 ProGuard 混淆插件,以便在构建过程中应用这些规则。在构建配置中,需要指定混淆规则文件的路径。
完成配置后,只需执行正常的构建流程。当构建完成后,生成的 jar 包将包含经过混淆的代码。此时,即便是使用反编译工具,也无法轻易地解读出原始的代码结构和逻辑,从而保护了开发者的知识产权。
总结而言,代码混淆是保护代码不被反编译的一种方法。通过合理配置混淆规则和插件,开发者可以在不改变代码功能的前提下,增加代码的可读性和理解难度,为防止代码泄露提供了额外的安全屏障。
爆破专栏丨Spring Security系列教程之SpringSecurity中的密码加密
前言
本文将带您深入Spring Security密码加密机制的学习。Spring Security作为安全框架,自然包含密码加密内容。本篇将详细解释密码加密原理、Spring Security中的处理方案,特别是BCryptPasswordEncoder的应用。此外,还会指导您如何使用BCryptPasswordEncoder进行加密,以及实现多密码加密方案共存。
一. 密码加密简介
散列加密概述:密码加密常采用的信息摘要算法,包括MD5、SHA系列等,将数据压缩成固定长度的字符串。
散列加密原理:通过压缩和混淆数据生成唯一指纹,确保数据安全。
盐的作用:为增加安全性,密码加密时加入随机盐值,期货ddx指标源码确保即使明文相同,生成的密文也不同。
Spring Security密码处理:支持BCryptPasswordEncoder等方案,确保密码安全。
二. 利用BCryptPasswordEncoder进行加密
编写接口、配置加密算法、测试运行,实现密码加密。
1. 编写register接口
在UserController中添加register接口,对密码进行加密,注入PasswordEncoder对象。
2. 配置密码加密算法
在Security Config类中,配置使用BCryptPasswordEncoder,放行注册接口。
3. 测试运行
启动项目,测试/user/register接口,验证密码加密效果。
4. BCryptPasswordEncoder加解密原理
BCrypt随机生成盐值,确保密码明文相同,密文也不同。比对密码时,先提取盐值,再加密明文,最后对比生成的密文。
三. 利用其他Encoder进行加密实现
1. MessageDigestPasswordEncoder用法
使用MessageDigestPasswordEncoder实现,支持MD5、SHA等算法,配置时需指定算法名称。
2. DelegatingPasswordEncoder用法
利用DelegatingPasswordEncoder实现密码加密方案的动态切换,支持多种加密方式。
四. 源码解析
了解PasswordEncoder接口、默认实现BCryptPasswordEncoder、密码比对原理。
1. PasswordEncoder接口解读
接口定义密码加密和比对方法,实现密码安全。
2. matches()默认执行时机
自动调用matches方法进行密码比对,无需手动编码。
五. 实现多密码加密方案共存
1. 需求背景
项目改造时,精美导航站源码需要更新密码加密方案,但不希望用户重新注册。
2. 实现过程
配置DelegatingPasswordEncoder,定义测试接口,测试共存效果。
3. 多密码方案并存实现原理
Spring Security通过配置不同PasswordEncoder实现密码加密方案的灵活管理。
张图,剖析 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源码的学习,大家还想了解哪些内容,欢迎留言给楼仔。
Spring Boot源码解析(四)ApplicationContext准备阶段
深入解析Spring Boot中ApplicationContext的准备阶段,本文将带你从环境设置、后处理到初始化器的执行,直至广播事件和注册应用参数等关键步骤的全面解读。
环境的设置是准备阶段的起点,主要涉及三个步骤。首先,通过AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner,将包含实际参数的Environment重新配置到这些实例中,以确保ApplicationContext能够准确理解和处理后续的配置信息。
紧接着,对ApplicationContext进行后处理。这包括注册beanNameGenerator、设置resourceLoader和conversionService。对于一般配置的Spring Boot应用,这些部分往往为空,因此主要执行的是设置conversionService,确保数据转换的顺利进行。
处理Initializer阶段,Spring Boot通过遍历META-INF/spring.factories中的initializer加载配置,执行8个预设的Initializer方法,它们负责执行特定的功能,例如增强或定制ApplicationContext行为,尽管具体实现细节未详细展开。
广播ApplicationContextInitialized和BootstrapContextClosed事件,以及注册applicationArguments和printedBanner,是准备阶段的后续操作,确保ApplicationContext能够接收外部参数并展示启动信息,同时为ApplicationContext的后续操作做准备。
在设置不支持循环引用和覆盖后,调整lazy initialization为默认不允许。Spring Boot通过配置确保依赖注入过程的高效性和稳定性,同时提供了开启懒加载的选项,允许在实际使用时加载bean,提高应用启动性能。
最后,处理重排属性的post processor,确保ConfigurationClassPostProcessor加载的property在正确的位置被处理,维护配置加载的逻辑顺序和依赖关系。
资源的加载是准备阶段的最后一步,将PrimarySource与所有其他源整合到allSources中,并返回一个不可修改的集合。这个过程确保了资源的高效访问和管理,为ApplicationContext的后续操作提供基础。
在完成启动类的加载后,Spring Boot通过构建BeanDefinitionLoader并配置相应的组件,将主类Application加载到Context中。这一过程是动态且高效的,确保了应用的快速启动和资源的有效管理。
至此,Spring Boot中ApplicationContext的准备阶段全面解析完成,从环境设置到启动类加载,每一个步骤都为ApplicationContext的高效运行打下了坚实的基础。接下来,我们将探讨ApplicationContext的刷新过程,敬请关注。
2024-11-13 15:01
2024-11-13 14:13
2024-11-13 13:28
2024-11-13 12:47
2024-11-13 12:39
2024-11-13 12:31