用通俗易懂的語言談談我對IOC和AOP的理解

前言

  我們都知道Spring有兩個重要的特性,那就是IOC和AOP,而這兩個特性也是我們在求職過程中經常被問到的問題,下面我們就這兩個特性結合實例來詳細說明一下。

一、IOC

  IOC英文全稱爲“Inverse of Control”即控制反轉的意思,它並不是一種技術,而是一種設計思想與理念。便是最初由我們在程序中自己手動new一個對象改變成交給Spring容器來控制並管理。簡單的說,IOC你可以理解爲一個Map集合,而Map存放的是各種對象,當我們需要用的時候就直接去獲取這個key。

  IOC容器裏面管理着各個對象之間的依賴關係並且完成對象的注入。這樣做就會簡化了我們在應用程序中的開發,從而將應用程序從複雜的依賴中解放出來,最終達到了程序解耦的目的。

  從上面的描述中我們知道IOC帶來的改變不僅僅是在程序上的體現,它給我們帶來的最大的改變是從思想上的改變,使得原本是主動的應用程序變成被動的了,被動的去等待IOC容器中生成對象並推給它想要的資源。通俗點說就是“你別過來找我,你等着就行,我會給你的”

用通俗易懂的語言談談我對IOC和AOP的理解

IOC初始化過程

下面我們通過代碼來了解一下

<bean id="contentService" class="com.qxwo.service.impl.ContentServiceImpl"></bean>
<bean id="contentController" class="com.qxwo.service.ContentController" scope="prototype">
		<!-- 注入Service -->
		<property name="contentService" ref="contentService" />
</bean>
// 注入service
private ContentService contentService;
		
public void setContentService(ContentService contentService) {
		this.contentService = contentService;
}

我們從上面的代碼中可以看出,spring通過<property>元素會自動調用contentService的set方法,像這樣在我們的ContentController類中就自動的獲得了contentService的對象,而不需要我們手動去創建這個對象。本文來源於公衆號:【Java學習提升】 專注於Java領域技術分享,Java知識體系學習、分享面試經驗,讓我們結伴而行,共同成長!

二、AOP

  aop的英文全稱爲“Aspect Oriented Programming”,我們不難看出直觀的意思爲面向切面編程。它可以封裝那些和業務沒有關係的但是又給那些業務模塊調用的邏輯封裝起來,如我們常見的事務處理、系統日誌和權限控制等應用場景。這樣有利於減少系統的代碼重複量,降低系統耦合度,對系統將來的可擴展性和可維護性有着很大的好處。

  AOP本身是基於動態代理的,假如要代理某個對象或者現實某個接口,這時AOP將使用JDK Proxy完成代理對象的創建。但是對於一些沒有實現接口的對象,就不能使用JDK Proxy去代理對象的創建了,這種情況下該如何創建呢?這時它會使用Cglib生成一個被代理對象的子類作爲代理,如下圖所示:

用通俗易懂的語言談談我對IOC和AOP的理解

通過Cglib生成一個被代理對象的子類作爲代理

下面我來用用戶操作日誌的場景來距離說明下:

首先maven中引入

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
import cn.hutool.json.JSONUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

@Aspect
@Component
@Order(1)//值越小,優先級越高
public class SaveUserLogDemo {

    private Logger log = LoggerFactory.getLogger(getClass());

    //申明一個切點
    @Pointcut("execution(public * com.qxwo.demo.*(..))")

    private void controllerAspect() {
    }

    //在方法執行前請求
    @Before(value = "controllerAspect()")
    public void methodBefore(JoinPoint joinPoint) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        //打印請求接口的內容
        log.info("請求的接口地址:" + request.getRequestURL().toString());
        log.info("請求的方式:" + request.getMethod());
        log.info("請求的方法參數:" + Arrays.toString(joinPoint.getArgs()));

    }

    //在方法執行後請求
    @AfterReturning(returning = "o", pointcut = "controllerAspect()")
    public void methodAfterReturing(Object o) {
        log.info("Response內容:" + JSONUtil.toJsonPrettyStr(o));
    }
}

這樣我們就可以收集用戶請求接口的相關信息,包括接口的地址、請求方式、請求的參數以及執行時間等信息。

原創聲明:本文爲【Java學習提升】原創博文,轉載請註明出處。

本文來源於公衆號:【Java學習提升】 專注於Java領域技術分享,Java知識體系學習、分享面試經驗,讓我們結伴而行,共同成長!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章