# Spring boot AOP & DI example --- ## Aspect-Oriented Programming 將一些有在多個地方使用到的功能或服務,如安全檢查或是紀錄等功能抽取出來,單一撰寫。 ![](https://i.imgur.com/r4OD2r7.png =500x) ---- ### 常用名詞 * Aspect:設計各個獨立可重用的物件,這些物件稱之。 * Joinpoint:Aspect 在應用程式執行時加入流程的時機。 * Pointcut:定義某個 Aspect 在哪些 Joinpoint 時要應用上。 ---- ### AOP Example 以我們的專案來舉例,如果要計算每項 Request 的時間要如何寫呢? ![](https://i.imgur.com/57caW1B.png) ---- 最直覺的方法就是在每個 function 的頭部跟尾部加上紀錄時間: ![](https://i.imgur.com/hUol63S.png) 缺點是維護不易,且程式變得冗雜。 ---- ### Forget it, try AOP 使用 AOP 前要在 pom.xml 設置 dependency ```htmlmixed= <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` ---- ### Log Execution time 再來開新的 class 並且撰寫程式碼如下: ![](https://i.imgur.com/Ap411vG.png) (funciton 的意思是當如果用到 RestController 所標註的 function 時就會被觸發。) ---- * @Aspect: 註解定義此 class 為切面。 * @Around: 在切入點切入內容,且可以控制何時執行切入點自身內容。(使用 ProceedingJoinPoint 控制程式流程。) * @Before * @After * @AfterReturning * ... * ProceedingJoinPoint: 切入點之物件,呼叫 proceed() 可以繼續執行程式碼。 ---- ### Result 顯示出各個 RestController 被呼叫到的 function 以及執行時間。 ![](https://i.imgur.com/2AXtHgT.png =1000x) --- ## Dependency Injection * 相依:例如 Hello World 程式,相依在 System、String 等類別。當類別有更動,相依的部分也要跟著更動。 * 如:macbook 相依於其上游廠商 hard drive、RAM... ---- ## Injection * 當物件被建立的時候,由調控系統內所有物件的外界實體,將其所依賴的物件注入給它。 ![](https://i.imgur.com/y9arAEH.png) ---- ### Why? * 讓程式達到 loosely coupled。 * 測試容易,物件與物件間可分別測試: [mock object](https://zh.wikipedia.org/wiki/%E6%A8%A1%E6%8B%9F%E5%AF%B9%E8%B1%A1)。 * 維護更新也會較為方便。 ---- ### How? 聲明 Bean (以下四種為較常用註解) 當 spring 看到註解會自動將其註冊為 bean。 * @Component:可以作用在任何地方,通常把 pojo 實例化到 spring 容器。 * @Service:業務邏輯使用,更詳細紀錄執行方法的地方。 * @Repository:DAO 層使用 * @Controller:它把用戶請求的數據經過業務處理層處理之後封裝成一個Model ,然後再把該Model返回給對應的View進行展示 注入Bean * @Autowired:Spring 會抓取已存在的 bean,並且在外 new 出新物件,自動注入。 ---- ### Example 以專案的片段程式碼為例,[UserController](https://github.com/mrwenwei/ESUN-Summer-Project/blob/f5da9516e5f4406346ec6f1240ec7f6ca4291b96/esp-back-end/src/main/java/com/esun/espbackend/controller/UserController.java#L19) 使用到 AutoWierd 自動注入 bean 物件 [UserService](https://github.com/mrwenwei/ESUN-Summer-Project/blob/f5da9516e5f4406346ec6f1240ec7f6ca4291b96/esp-back-end/src/main/java/com/esun/espbackend/service/UserService.java#L15) 如此就能直接使用。 ```java= @RestController public class UserController { @Autowired UserService userService; @RequestMapping(value = "/GET/users") public List<UserEntity> getAll() { return userService.getAll(); } } ``` UserService 則使用到 [UserRepository](https://github.com/mrwenwei/ESUN-Summer-Project/blob/master/esp-back-end/src/main/java/com/esun/espbackend/repository/UserRepository.java) 的 bean。 ```java= @Service public class UserService { @Autowired UserRepository userRepo; public List<UserEntity> getAll() { return (List<UserEntity>) userRepo.findAll(); } } ``` --- ## Reference https://openhome.cc/Gossip/Spring/
{"metaMigratedAt":"2023-06-14T23:34:35.877Z","metaMigratedFrom":"YAML","title":"Spring boot AOP & DI example","breaks":true,"contributors":"[{\"id\":\"0ee7ad64-ac2e-4bf1-969d-547d09882099\",\"add\":3948,\"del\":982}]"}
    1324 views