前言
我們都知道Spring有兩個重要的特性,那就是IOC和AOP,而這兩個特性也是我們在求職過程中經常被問到的問題,下面我們就這兩個特性結合執行個體來詳細說明一下。
一、IOC
IOC英文全稱為“Inverse of Control”即控制反轉的意思,它并不是一種技術,而是一種設計思想與理念。便是最初由我們在程式中自己手動new一個對象改變成交給Spring容器來控制并管理。簡單的說,IOC你可以了解為一個Map集合,而Map存放的是各種對象,當我們需要用的時候就直接去擷取這個key。
IOC容器裡面管理着各個對象之間的依賴關系并且完成對象的注入。這樣做就會簡化了我們在應用程式中的開發,進而将應用程式從複雜的依賴中解放出來,最終達到了程式解耦的目的。
從上面的描述中我們知道IOC帶來的改變不僅僅是在程式上的展現,它給我們帶來的最大的改變是從思想上的改變,使得原本是主動的應用程式變成被動的了,被動的去等待IOC容器中生成對象并推給它想要的資源。通俗點說就是“你别過來找我,你等着就行,我會給你的”
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生成一個被代理對象的子類作為代理,如下圖所示:
通過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知識體系學習、分享面試經驗,讓我們結伴而行,共同成長!