深入解析Spring AOP核心原理

一 Spring-AOP

1.對SpringAOP理解

????????AOP是OOP的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生泛型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低提高程序的可重用性,同時提高了開發的效率。

AOP(Aspect-Oriented Programming:面向切面編程):將哪些與業務無關,卻為業務模塊所共同調用的邏輯(例如事務處理,日志管理,權限控制)封裝抽成一個可重用的模塊,這個模塊被命名為“切面”,便于減少系統的重復代碼,降低模塊之間的耦合度,并有利于未來的可拓展性和可維護性。

SpringAOP基于動態代理實現:

  • ? ? ? ? 如果被代理的對象,已經實現某個接口,則SpringAOP會使用JDK Proxy(反射),基于接口的方式,創建代理對象(JDK動態代理的核心是InvocationHandler接口和Proxy類);
  • ????????如果被代理的對象,沒有實現某個接口,就無法使用JDK Proxy去處理代理了,這時候Spring會使用Cglib,基于繼承的方式,生成一個被代理類對象的子類來作為代理(Cglib動態代理的核心是MethodInterceptor接口和Enhancer類)。

2.AOP通知

? ? ? ? 概念:AOP將抽取出來的共性功能稱為通知;

????????通知類型:以通知在上下文中的具體位置作為劃分

? ? ? ? 解釋:通知就是需要增強的方法內容以及執行位置的結合。

? ? ? ? 前置通知-before,返回通知-after-returning,異常通知-after-throwing,后置通知-after,環繞通知-around.

<!--    aop配置--><aop:config>
<!--        配置切面--><aop:aspect id="mian" ref="logger">
<!--            配置切點--><aop:pointcut id="cut" expression="execution(public * com.itheima.service.*.*(..))"></aop:pointcut>
<!--            配置通知-->
<!--            前置通知--><aop:before method="beforeLog" pointcut-ref="cut"></aop:before>
<!--            后置通知--><aop:after method="afterLog" pointcut-ref="cut"></aop:after>
<!--            返回通知--><aop:after-returning method="afterReturningLog" pointcut-ref="cut"></aop:after-returning>
<!--            異常通知--><aop:after-throwing method="afterThrowingLog" pointcut-ref="cut"></aop:after-throwing><aop:around method="aroundLog" pointcut-ref="cut"></aop:around></aop:aspect></aop:config>

3.AOP連接點

? ? ? ? AOP將所有的方法都視為連接點,不管是接口里面的抽象方法,還是實現類里面的重寫方法,都是連接點。

? ? ? ? 解釋:具備添加通知能力的方法位置,就是連接點,也就是所有類的所有方法

4.AOP切點

? ? ? ? AOP將可能被抽取共性功能的方法稱為切入點,切入點是連接點的子集。

? ? ? ? 解釋:成功添加了通知方法的位置,就是切點。

<aop:pointcut id="dian" expression="execution(public * com.apesource.service.*.*(..))"/>

5.AOP目標對象

????????就是挖掉功能的方法對應的類生的對象,這種對象是無法直接完成最終工作的

? ? ? ? 解釋:被代理對象,就是目標對象

6.AOP織入

? ? ? ? 就是將挖掉的功能回填的動態過程

? ? ? ? 解釋:將通知添加到切點的過程ing,就是織入。

補充:AOP切面:切點+通知


7.SpringAOP+AspectJ實現

????????1.坐標

        <dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.7</version></dependency>

????????2.配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="accountSErviceImp" class="com.itheima.service.AccountServiceImp"></bean><bean id="logger" class="com.itheima.util.Logger"></bean>
<!--    aop配置--><aop:config>
<!--        配置切面--><aop:aspect id="mian" ref="logger">
<!--            配置切點--><aop:pointcut id="cut" expression="execution(public * com.itheima.service.*.*(..))"></aop:pointcut>
<!--            配置通知-->
<!--            前置通知--><aop:before method="beforeLog" pointcut-ref="cut"></aop:before>
<!--            后置通知--><aop:after method="afterLog" pointcut-ref="cut"></aop:after>
<!--            返回通知--><aop:after-returning method="afterReturningLog" pointcut-ref="cut"></aop:after-returning>
<!--            異常通知--><aop:after-throwing method="afterThrowingLog" pointcut-ref="cut"></aop:after-throwing><aop:around method="aroundLog" pointcut-ref="cut"></aop:around></aop:aspect></aop:config>
</beans>

切點表達式配置語法

? ? ? ? execution(修飾符 返回值 包名稱.類名稱.方法名稱(參數列表))

1.修飾符可以省略代表任意
execution(返回值 包名稱.類名稱.方法名稱(參數列表))
2.返回值可以使用“*”代表任意
execution(* 包名稱.類名稱.方法名稱(參數列表))
3.包名可以使用“*”代表任意名稱
execution(* *.*.*.類名稱.方法名稱(參數列表))
eg:execution(void *.*.*.ServiceImp.findAll())
4.包名可以使用“..”代表任意個數
execution(* *..類名稱.方法名稱(參數列表))
eg:execution(void *..ServiceImp.findAll())
5.類名與方法名可以使用“*”代表任意
execution(* *...*.*(參數列表))
6.參數列表可以使用".."代表任意個數任意類型
execution(* *...*.*(..))

? ? 如果有參數
int======>int
String===>java.lang.String

二 Spring中bean的一生

1.bean實例化的基本流程-底層

? ? ? ? Spring容器在進行初始化時,會將xml配置的信息封裝成一個BeanDefinition對象,所有的BeanDefinition存儲到一個名為beanDefinitionMap的Map集合中去,Spring框架在對該Map進行遍歷,使用反射創建bean實例對象,創建號的Bean對象存儲在一個名為singletonObject的Map集合中,當調用getBean方法時,則最終從該Map集合中取出Bean實例對象返回。

? Bean 實例化的基本流程

加載xml配置文件,解析獲取配置中的每個的信息,封裝成一個個的BeanDe?nition對象;

BeanDe?nition存儲在一個名為beanDe?nitionMap的Map中;

ApplicationContext底層遍歷beanDe?nitionMap,創建Bean實例對象; 創建好的Bean實例對象,被存儲到一個名為singletonObjects的Map中;

當執行applicationContext.getBean(beanName)時,從singletonObjects去匹配Bean實例返回。

2.Spring 還有其他類型的 “后處理器”

后處理器接口作用階段核心功能
BeanFactoryPostProcessorBean 定義加載后,Bean 實例化前修改 BeanDefinition(Bean 的元信息),例如:
- 動態修改 Bean 的屬性值、作用域
- 新增 Bean 定義(如 Spring 的PropertyPlaceholderConfigurer用于解析${}占位符)
BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor 的增強版,更早執行向容器中注冊新的 BeanDefinition(比BeanFactoryPostProcessor有更高的優先級),例如:
- 動態掃描并注冊 Bean(Spring Boot 的 @ComponentScan 底層用到類似機制)
InstantiationAwareBeanPostProcessorBean 實例化前后(比BeanPostProcessor更早)干預 Bean 的實例化過程,例如:
- 阻止默認實例化,返回自定義 Bean 對象
- 處理屬性注入前的邏輯(如 @Autowired 的依賴查找)
DestructionAwareBeanPostProcessorBean 銷毀前處理 Bean 銷毀前的邏輯,例如:
- 資源釋放、狀態清理等

Spring的后處理器是Spring對外開放的重要擴展點,允許我們介入到Bean的整個實例化流程中來,以達到動態注冊BeanDefinition,以及動態修改Bean的作用。

Spring主要有兩種后處理器

  • ? ? ? ? BeanFactoryPostProcessor:Bean工廠后處理器,在BeanDefinitionMap填充完畢,Bean實例話之前執行;
  • BeanPostProcessor:Bean后處理器,一般在Bean實例化之后,填充到單例池singletonObjects之前執行;

3.Bean工廠后處理器 – BeanFactoryPostProcessor

BeanFactoryPostProcessor是一個接口規范,實現了該接口的類只要交由Spring容器管理的話,那么 Spring就會 回調該接口的方法,用于對BeanDe?nition注冊和修改的功能。

修改

????????1. 創建BeanFactoryPostProcessor實現類并重寫方法

????????2. 注入實現類

注冊

????????1. 創建BeanFactoryPostProcessor實現類并重寫方法

????????2. 注入實現類

Spring 提供了一個BeanFactoryPostProcessor的子接口BeanDe?nitionRegistryPostProcessor專門用 于注冊BeanDe?nition操作

public class MyBeanFactoryPostProcessor2 implements 
BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory 
configurableListableBeanFactory) throws BeansException {}@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry 
beanDefinitionRegistry) throws BeansException {BeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.apesource.pojo.Student");beanDefinitionRegistry.registerBeanDefinition("stu",beanDefinition);}
}

4.Bean后處理器-BeanPostProcessor

? ? ? ? Bean被實例化后,到最終緩存到名為singletonObjects單例池之前,中間會經過Bean的初始化過程。

public class MyBeanPostProcessor implements BeanPostProcessor{public Object postProcessBeforeInitialization(Object bean, String beanName){System.out.println("初始化之前執行");return bean;}public Object postProcessAfterInitialization(Object bean, String beanName){System.out.println("初始化之后執行");return bean;}

5.spring-bean的生命周期

? ? ? ? 從Bean實例化之后,及通過反射創建出對象之后,到Bean成為一個完整對象最終存儲到單例池中,這個過程被成為SPringBean的生命周期。

大致分為三個階段

  • Bean的實例化階段:spring框架會取出BeanDefinition的信息進行判斷當前bean的范圍是否是singleton的,是否不是延遲加載的,是否不是FactoryBean等,最終將一個普通的singleton的Bean通過反射進行實例化。
  • Bean的初始化階段:Bean創建之后還僅僅是個”半成品“,還需要對Bean的實例進行填充,執行一些aware接口方法,執行BeanPostProcessor方法,執行InitializingBean接口的初始化方法。執行自定義初始化init方法等。該階段是Spring最具技術含量和復雜度的階段。
  • Bean的完成階段:經過初始化階段,Bean就成為了一個完整的Spring Bean,被存儲到單例池sinletonObjects去了,及完成了SPringBean的整個生命周期。

6.Spring Bean的初始化過程涉及如下幾個過程:

  • Bean實例的屬性填充

  • Aware接口屬性注入

  • BeanPostProcessorbefore()方法回調

  • InitializingBean接口的初始化方法回調 自定義初始化方法init回調

  • BeanPostProcessorafter()方法回調

8.常用的Aware接口

????????Aware接口是一種框架輔助屬性注入的一種思想,其他框架中也可以看到類似的接口。框架具備高度封裝性,我們接 觸到的一般都是業務代碼,一個底層功能API不能輕易的獲取到,但是這不意味著永遠用不到這些對象,如果用到了 ,就可以使用框架提供的類似Aware的接口,讓框架給我們注入該對象。

三 循環依賴-解決

? ? ? 1.? Spring在進行屬性注入時,會分為如下幾種情況:

????????????????注入普通屬性,String、int或存儲基本類型的集合時,直接通過set方法的反射設置進去;

????????????????注入單向對象引用屬性時,從容器中getBean獲取后通過set方法反射設置進去,如果容器中沒有,則先創建被注入對象Bean實例(完成整個生命周期)后,在進行注入操作;

????????????????注入雙向對象引用屬性時,就比較復雜了,涉及了循環引用(循環依賴)。

循環依賴

????????含義:多個實體之間相互依賴并形成閉環的情況就叫做"循環依賴",也叫做"循環引用"。

????????Spring提供了 三級緩存 存儲完整Bean實例半成品Bean實例,用于解決循環引用問題

????????在DefaultListableBeanFactory的上四級父類DefaultSingletonBeanRegistry中提供如下三個Map

public class DefaultSingletonBeanRegistry ... {//1、最終存儲單例Bean成品的容器,即實例化和初始化都完成的Bean,稱之為"一級緩存"    Map<String, Object> singletonObjects = new ConcurrentHashMap(256);//2、早期Bean單例池,緩存半成品對象,且當前對象已經被其他對象引用了,稱之為"二級緩存"    Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);//3、單例Bean的工廠池,緩存半成品對象,對象未被引用,使用時在通過工廠創建Bean,稱之為"三級緩存"    
Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}

注:將對象保存至三級緩存的時候,會包裝成ObjectFactory對象錄入,未來通過此接口對應的get方法再次提取對象.

UserService和UserDao循環依賴的過程結合上述三級緩存描述一下

  1. UserService 實例化對象,但尚未初始化,將UserService存儲到三級緩存
  2. UserService 屬性注入,需要UserDao,從緩存中獲取,沒有UserDao
  3. UserDao實例化對象,但尚未初始化,將UserDao存儲到到三級緩存;
  4. UserDao屬性注入,需要UserService,從三級緩存獲取UserService,UserService三級緩存移入二級緩存
  5. UserDao執行其他生命周期過程,最終成為一個完成Bean,存儲到一級緩存,刪除二三級緩存; UserService 注入UserDao;
  6. UserService執行其他生命周期過程,最終成為一個完成Bean,存儲到一級緩存,刪除二三級緩存。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/96616.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96616.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/96616.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

大數據與AI:一場“數據盛宴”與“智能大腦”的奇妙邂逅

在當今這個信息爆炸的時代&#xff0c;大數據和AI&#xff08;人工智能&#xff09;就像一對熱戀中的情侶&#xff0c;天天黏在一起&#xff0c;形影不離。它們的結合&#xff0c;不僅改變了我們的生活方式&#xff0c;還讓這個世界變得更加有趣和奇妙。今天&#xff0c;就讓我…

解決window下共享資源報“不允許一個用戶使用一個以上用戶名與服務器或共享資源的多重連接“問題

問題現象&#xff1a; 使用不同samba共享賬號登錄同一服務器ip共享文件夾資源時會報錯誤提示解決辦法&#xff1a; 1.使用net use命令查看已保存的網絡連接 C:\Users\Administrator>net use 會記錄新的網絡連接。狀態 本地 遠程 網絡----…

SciKit-Learn 全面分析分類任務 wine 葡萄酒數據集

背景 wine 葡萄酒數據集&#xff0c;提供了對三種不同品種的意大利葡萄酒的化學分析結果 主要特點&#xff1a; 數據集規模&#xff1a;總共有 178 個樣本特征數量&#xff1a;每個樣本有 13 個化學特征&#xff0c;包括酒精、蘋果酸、灰分、鎂等類別數量&#xff1a;總共有 3 …

【論文閱讀】Far3D: Expanding the Horizon for Surround-view 3D Object Detection

標題&#xff1a; Far3D: Expanding the Horizon for Surround-view 3D Object Detection motivation 作者覺得市面上的方法對遠處的long-range 的3d-od檢測沒有深入研究&#xff0c;于是作者提出FAR3D. 基于環視圖像的3D物體檢測取得了顯著進展&#xff0c;且其部署成本較低。…

Redis分布式鎖的try-with-resources實現

Redis分布式鎖的try-with-resources實現 在Java中&#xff0c;try-with-resources是一種自動資源管理機制&#xff0c;適用于實現了AutoCloseable接口的類。通過結合Redis分布式鎖和try-with-resources&#xff0c;可以確保鎖的自動釋放&#xff0c;避免因異常或忘記釋放鎖導致…

上傳文件接口設計,SpringBoot + MinIO/S3 文件服務實現:FileService 接口與 FileServiceImpl 詳解

在企業項目中&#xff0c;文件上傳和管理是非常常見的需求。本文基于 芋道源碼 的實現&#xff0c;介紹如何封裝一個通用的 文件服務 FileService&#xff0c;支持&#xff1a;文件上傳&#xff08;保存數據庫記錄 存儲文件到 S3/MinIO 等對象存儲&#xff09;文件下載與刪除文…

MVC 依賴注入(DI)與服務全解析(附避坑實戰)

依賴注入的核心概念 依賴注入&#xff08;DI&#xff09;是一種設計模式&#xff0c;通過將對象的依賴關系從內部創建轉移到外部傳遞&#xff0c;實現解耦。在 MVC 框架中&#xff0c;DI 容器負責管理對象的生命周期和依賴關系&#xff0c;開發者只需聲明依賴&#xff0c;容器…

【實證分析】上市公司經營風險數據集-含代碼(2000-2022年)

數據簡介&#xff1a;上市公司經營風險涉及多維度、多層次的復雜因素&#xff0c;本文章參考王竹泉-經營風險與營運資金融資決策對上市公司經驗風險進行測算&#xff0c;經營風險是該公司息稅折舊攤銷前利潤率的標準差&#xff0c;經營風險是該公司息稅折舊攤銷前利潤率的標準差…

領碼方案|Windows 下 PLT → PDF 轉換服務超級完整版:異步、權限、進度

摘要 面向 Windows 平臺&#xff0c;使用 ASP.NET Core Web API 結合 Ghostscript.NET 庫&#xff0c;實現 PLT&#xff08;HPGL&#xff09;→PDF 的純庫調用轉換&#xff0c;無需外部進程。支持同步與異步模式&#xff0c;采用 JWTRBAC 進行權限治理&#xff0c;任務狀態存儲…

瀏覽器兼容性問題全解:CSS 前綴、Grid/Flex 布局兼容方案與跨瀏覽器調試技巧

1. 瀏覽器兼容性與前綴問題 不同瀏覽器&#xff08;尤其是老版本 IE、Edge、Safari&#xff09;對新特性&#xff08;比如 CSS 變量、Grid、Flex 等&#xff09;的支持程度不一&#xff0c;需要使用廠商前綴&#xff08;-webkit-、-moz- 等&#xff09;或降級方案。新手往往忽…

【Android View】事件分發機制

參考文獻 https://juejin.cn/post/6844904041487532045https://juejin.cn/post/6844903894103883789#heading-12https://www.jianshu.com/p/dea72779a6b7 文章目錄

【大數據相關】ClickHouse命令行與SQL語法詳解

ClickHouse命令行與SQL語法詳解一、ClickHouse命令行與SQL語法詳解第一部分&#xff1a;ClickHouse SQL 命令行客戶端 (clickhouse-client)1. 基礎連接2. 核心命令行參數3. 數據導入與導出實戰第二部分&#xff1a;ClickHouse SQL 語法詳解1. DDL (數據定義語言)2. DML (數據操…

學習日記-CSS-day53-9.11

1.CSS介紹知識點核心內容重點CSS定義層疊樣式表&#xff0c;用于內容修飾和樣式展現英文全稱cascading style sheetsCSS作用實現HTML內容與樣式分離&#xff0c;提高開發效率對比傳統HTML元素單獨設置樣式的低效方式學習建議掌握常用功能即可&#xff0c;重點在打通前后端數據通…

Maven中optional的作用

目的&#xff1a; 控制依賴傳遞 &#xff1a;將依賴標記為可選&#xff0c;這樣當其他模塊依賴common-component時&#xff0c;不會自動繼承Elasticsearch依賴。這遵循了"依賴最小化"原則&#xff0c;避免不必要的庫被引入到不需要它們的模塊中。模塊化設計 &#xf…

藍橋杯算法之基礎知識(7)---排序題的快排和歸并排序

一、快排》快排方法&#xff0c;就三步1.隨便選一個值作為基準值x2.拿選中的這個x值劃分隊列為左右兩個區間&#xff08;左邊的都小于x&#xff0c;右邊的都大于x&#xff09;3.然后遞歸左區間和右區間就行》代碼舉例&#xff1a;#qs排序#1 6 7 8 6 5 4 #先找比較點&#xff0c…

緩存未命中

緩存未命中&#xff08;Cache Miss&#xff09; 發生在 CPU 訪問某塊內存時&#xff0c;該地址不在當前緩存&#xff08;L1/L2/L3&#xff09;中&#xff0c;導致程序被迫從更慢的內存&#xff08;RAM&#xff09;讀取數據&#xff0c;嚴重拖慢程序執行速度。 &#x1f4cd; 一…

AR眼鏡:化工安全生產的技術革命

在石化企業的壓縮機組巡檢中&#xff0c;佩戴AR眼鏡的巡檢員眼前實時顯示著設備溫度場分布和振動頻譜曲線&#xff0c;單臺設備巡檢時間從45分鐘縮短至18分鐘。這不僅是效率的提升&#xff0c;更是化工安全生產的一場智能革命。一、行業痛點&#xff1a;傳統化工巡檢的困境與挑…

消息中間件RabbitMQ(從入門到精通)

RabbitMQ概念_MQ 消息隊列 MQ全稱Message Queue(消息隊列),是在消息的傳輸過程中保存消息的容器。多用于系統之間的異步通信。 同步通信相當于兩個人當面對話,你一言我一語。必須及時回復 異步通信相當于通過第三方轉述對話,可能有消息的延遲,但不需要二人時刻保持聯系。…

前端學習之后端java小白(五)之多表查詢/事務

一、多表查詢概念二、概述 1. 內連接隱式內連接 SELECT 字段列表 FROM 表1&#xff0c;表2... WHERE 條件顯示內連接SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 條件2. 外連接 左外連接SELECT 列名 FROM 左表 LEFT [OUTER] JOIN 右表 ON 連接條件;右外連接SELECT 列名…

Java全棧學習筆記34

# JDBCjava database connection Java 數據庫連接技術## JDBC 驅動程序如果需要通過jdbc技術連接關系型數據庫&#xff0c;就需要為jdbc提供一個該數據庫的驅動。驅動程序由對應的數據庫廠商提供。mysql提供了針對于各種語言的驅動程序。去官網下載和java相關的驅動即可## JDB…