慕課網_《探祕Spring AOP》學習總結

時間:2017年09月03日星期日
說明:本文部份內容均來自慕課網。@慕課網:http://www.imooc.com
教學源碼:https://github.com/zccodere/s...
學習源碼:https://github.com/zccodere/s...java

第一章:課程介紹

1-1 面向切面

課程章節mysql

概覽
AOP使用
AOP原理
AOP開源運用
課程實戰
課程總結

面向切面編程是一種編程範式git

編程範式概覽github

面向過程編程
面向對象編程
面向函數編程(函數式編程)
事件驅動編程(GUI開發中比較常見)
面向切面編程

AOP是什麼spring

是一種編程範式,不是編程語言
解決特定問題,不能解決全部問題
是OOP的補充,不是替代

AOP的初衷sql

DRY:Don’t Repeat Yourself代碼重複性問題
SOC:Separation of Concerns關注點分離
    -水平分離:展現層->服務層->持久層
    -垂直分離:模塊劃分(訂單、庫存等)
    -切面分離:分離功能性需求與非功能性需求

使用AOP的好處mongodb

集中處理某一關注點/橫切邏輯
能夠很方便地添加/刪除關注點
侵入性少,加強代碼可讀性及可維護性

AOP的應用場景express

權限控制
緩存控制
事務控制
審計日誌
性能監控
分佈式追蹤
異常處理

支持AOP的編程語言apache

Java
.NET
C/C++
Ruby
Python
PHP
…

1-2 簡單案例

案例背景編程

產品管理的服務
產品添加、刪除的操做只能管理員才能進行
普通實現VS AOP實現

建立一個名爲springaopguide的maven項目pom以下

完成後的項目結構以下

clipboard.png

代碼編寫

1.編寫Product類

package com.myimooc.springaopguide.domain;

/**
 * @title 產品領域模型
 * @describe 產品實體對象
 * @author zc
 * @version 1.0 2017-09-03
 */
public class Product {
    
    private Long id;
    
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
}

2.編寫CurrentUserHolder類

package com.myimooc.springaopguide.security;

/**
 * @title 獲取用戶信息
 * @describe 模擬用戶的切換,將用戶信息存入當前線程
 * @author zc
 * @version 1.0 2017-09-03
 */
public class CurrentUserHolder {
    
    private static final ThreadLocal<String> holder = new ThreadLocal<>();

    public static String get(){
        return holder.get() == null ? "unkown" : holder.get();
    }
    
    public static void set(String user){
        holder.set(user);
    }
}

3.編寫AdminOnly類

package com.myimooc.springaopguide.security;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @title 管理員權限註解
 * @describe 被該註解聲明的方法須要管理員權限
 * @author zc
 * @version 1.0 2017-09-03
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AdminOnly {

}

4.編寫SecurityAspect類

package com.myimooc.springaopguide.security;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.myimooc.springaopguide.service.AuthService;

/**
 * @title 權限校驗切面類
 * @describe 
 * @author zc
 * @version 1.0 2017-09-03
 */
// 聲明爲一個切面
@Aspect
@Component
public class SecurityAspect {
    
    @Autowired
    private AuthService authService;
    
    // 使用要攔截標註有AdminOnly的註解進行操做
    @Pointcut("@annotation(AdminOnly)")
    public void adminOnly(){
        
    }
    
    @Before("adminOnly()")
    public void check(){
        authService.checkAccess();
    }
    
}

5.編寫AuthService類

package com.myimooc.springaopguide.service;

import java.util.Objects;

import org.springframework.stereotype.Service;

import com.myimooc.springaopguide.security.CurrentUserHolder;

/**
 * @title 權限校驗類
 * @describe 對用戶權限進行校驗
 * @author zc
 * @version 1.0 2017-09-03
 */
@Service
public class AuthService {
    
    public void checkAccess(){
        String user = CurrentUserHolder.get();
        if(!Objects.equals("admin", user)){
            throw new RuntimeException("operation not allow");
        }
    }
    
}

6.編寫ProductService類

package com.myimooc.springaopguide.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.myimooc.springaopguide.domain.Product;

/**
 * @title 產品服務類
 * @describe 產品相關業務服務-傳統方式實現權限校驗
 * @author zc
 * @version 1.0 2017-09-03
 */
@Service
public class ProductService {
    
    @Autowired
    private AuthService AuthService;
    
    public void insert(Product product){
        AuthService.checkAccess();
        System.out.println("insert product");
    }
    
    public void delete(Long id){
        AuthService.checkAccess();
        System.out.println("delete product");
    }
    
}

7.編寫ProductServiceAop類

package com.myimooc.springaopguide.service;

import org.springframework.stereotype.Service;

import com.myimooc.springaopguide.domain.Product;
import com.myimooc.springaopguide.security.AdminOnly;

/**
 * @title 產品服務類
 * @describe 產品相關業務服務-AOP方式實現權限校驗
 * @author zc
 * @version 1.0 2017-09-03
 */
@Service
public class ProductServiceAop {
    
    @AdminOnly
    public void insert(Product product){
        System.out.println("insert product");
    }
    
    @AdminOnly
    public void delete(Long id){
        System.out.println("delete product");
    }
    
}

8.編寫AopGuideApplicationTests類

package com.myimooc.springaopguide;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.myimooc.springaopguide.security.CurrentUserHolder;
import com.myimooc.springaopguide.service.ProductService;
import com.myimooc.springaopguide.service.ProductServiceAop;

/**
 * @title 單元測試類
 * @describe 測試權限校驗服務是否生效
 * @author zc
 * @version 1.0 2017-09-03
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class AopGuideApplicationTests {
    
    @Autowired
    private ProductService productService;
    
    @Test(expected = Exception.class)
    public void annoInsertTest(){
        CurrentUserHolder.set("tom");
        productService.delete(1L);
    }
    
    @Test
    public void adminInsertTest(){
        CurrentUserHolder.set("admin");
        productService.delete(1L);
    }
    
    @Autowired
    private ProductServiceAop productServiceAop;
    
    @Test(expected = Exception.class)
    public void annoInsertAopTest(){
        CurrentUserHolder.set("tom");
        productServiceAop.delete(1L);
    }
    
    @Test
    public void adminInsertAopTest(){
        CurrentUserHolder.set("admin");
        productServiceAop.delete(1L);
    }
    
}

第二章:使用詳解

2-1 本節內容

Spring AOP使用方式

XML配置+Pointcut expression【不推薦使用方式】
註解方式+ Pointcut expression【推薦使用該方式】

Aspectj註解

@Aspect:用於聲明當前類是一個切面
@Pointcut:用於描述在哪些類、哪些方法上執行切面的代碼
Advice:描述想要在這些方法執行的什麼時機進行攔截

本章內容

Pointcut express:切面表達式
5種Advice:建言的五種細分怎麼使用

2-2 切面表達式

切面表達式

1.designators(指示器)
    execution()
    描述經過什麼樣的方式去匹配哪些類、哪些方法
2.wildcards(通配符)
    * .. +
    使用通配符進行描述
3.operators(運算符)
    && || !
    使用運算符進行多條件的判斷

Designators(指示器)

匹配方法 execution()
匹配註解 @target() @args() @within() @annotation()
匹配包/類型 @within()
匹配對象 this() bean() target()
匹配參數 args()

Wildcards(通配符)

* 匹配任意數量的字符
+ 匹配指定類及其子類
.. 通常用於匹配任意參數的子包或參數

Operators(運算符)

&& 與操做符
|| 或操做符
! 非操做符

2-3 匹配包類

// 匹配 ProductServiceAop 類裏面的全部方法
    @Pointcut("within(com.myimooc.springaopguide.service.ProductServiceAop)")
    public void matchType(){}
    
    // 匹配 com.myimooc.springaopguide.service 包及子包下全部類的方法
    @Pointcut("within(com.myimooc.springaopguide.service..*)")
    public void matchPackage(){}

2-4 匹配對象

// 匹配AOP對象的目標對象爲指定類型的方法,即DemoDao的aop代理對象的方法
    @Pointcut("this(com.myimooc.springaopguide.dao.DemoDao)")
    public void testDemo(){}
    
    // 匹配實現IDao接口的目標對象(而不是aop代理後的對象)的方法,這裏即DemoDao的方法
    @Pointcut("target(com.myimooc.springaopguide.dao.IDao)")
    public void targetDemo(){}
    
    // 匹配全部以Service結尾的bean裏面的方法
    @Pointcut("bean(*Service)")
    public void beanDemo(){}

2-5 匹配參數

// 匹配任何以find開頭並且只有一個Long參數的方法
    @Pointcut("execution(* *..find*(Long))")
    public void argsDemo1(){}
    
    // 匹配任何只有一個Long參數的方法
    @Pointcut("args(Long)")
    public void argsDemo2(){}
    
    // 匹配任何以find開頭並且第一個參數爲Long型的方法
    @Pointcut("execution(* *..find*(Long,..))")
    public void argsDemo3(){}
    
    // 匹配第一個參數爲Long型的方法
    @Pointcut("args(Long,..))")
    public void argsDemo4(){}

2-6 匹配註解

// 匹配方法標註有AdminOnly的註解的方法
    @Pointcut("@annotation(com.myimooc.springaopguide.security.AdminOnly)")
    public void annoDemo(){}
    
    // 匹配標註有Beta的類底下的方法,要求的annotation的RetentionPolicy級別爲CLASS
    @Pointcut("@within(com.google.common.annotations.Beta)")
    public void annoWithDemo(){}
    
    // 匹配標註有Repository的類底下的方法,要求的RetentionPolicy級別爲RUNTIME
    @Pointcut("@target(org.springframework.stereotype.Repository)")
    public void annoTargetDemo(){}
    
    // 匹配傳入的參數類標註有Repository註解的方法
    @Pointcut("@args(org.springframework.stereotype.Repository)")
    public void annoArgsDemo(){}

2-7 匹配方法

execution()格式

execution(
    modifier-pattern? // 修飾符匹配
    ret-type-pattern // 返回值匹配
    declaring-type-pattern? // 描述值包名
    name-pattern(param-pattern) // 方法名匹配(參數匹配)
    throws-pattern?// 拋出異常匹配
)

execution()實例

// 匹配 使用public修飾符 任意返回值 在com.myimooc.springaopguide.service包及子下 
    // 以Service結尾的類 任意方法(任意參數)
    @Pointcut("execution(public * com.myimooc.springaopguide.service..*Service.*(..))")
    public void matchCondition(){}

2-8 建言註解

5中Advice(建言)註解

@Before,前置通知
@After(finally),後置通知,方法執行完以後
@AfterReturning,返回通知,成功執行以後
@AfterThrowing,異常通知,拋出異常以後
@Around,環繞通知

5中Advice(建言)實例

// 定義切點,攔截使用NeedSecured註解修飾的方法
    @Pointcut("@within(com.myimooc.demo.security.NeedSecured)")
    public void annoTargetVsWithinDemo(){}
    
    // 使用NeedSecured註解修飾 且 在com.myimooc包下的方法
    @Before("annoTargetVsWithinDemo() && within(com.myimooc..*)")
    public void beforeDemo(){
        System.out.println("被攔截方法執行以前執行");
    }
    
    @After("annoTargetVsWithinDemo() && within(com.myimooc..*)")
    public void afterDemo(){
        System.out.println("被攔截方法執行以後執行");
    }
    
    @AfterReturning("annoTargetVsWithinDemo() && within(com.myimooc..*)")
    public void afterReturning(){
        System.out.println("代碼成功以後執行");
    }
    
    @AfterThrowing("annoTargetVsWithinDemo() && within(com.myimooc..*)")
    public void afterThrowing(){
        System.out.println("代碼執行拋出異常以後執行");
    }
    
    @Around("annoTargetVsWithinDemo() && within(com.myimooc..*)")
    public Object aroundDemo(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("至關於@Before");
        try{
            Object result = pjp.proceed(pjp.getArgs());
            System.out.println("至關於@AfterReturning");
            return result;
        }catch (Throwable throwable) {
            System.out.println("至關於@AfterThrowing");
            throw throwable;
        }finally {
            System.out.println("至關於@After");
        }
    }

Advice中的參數及結果綁定

@Before("annoTargetVsWithinDemo() && within(com.myimooc..*) && args(userId)")
    public void beforeWithArgs(JoinPoint joinPoint,Long userId){
        System.out.println("被攔截方法執行以前執行,args:"+userId);
    }
    
    @AfterReturning(value="annoTargetVsWithinDemo() && within(com.myimooc..*)",returning="returnValue")
    public void getResult(Object returnValue){
        if(returnValue != null){
            System.out.println("代碼成功以後執行,result:"+returnValue);
        }
    }

第三章:實現原理

3-1 本節內容

上節回顧

Pointcut expression的組成部分
各類designators的區別
5中advice及參數、結果綁定

實現原理

概述
設計:代理模式、責任鏈模式
實現:JDK實現、cglib實現

3-2 原理概述

原理概述:植入的時機

1.編譯期(AspectJ)
2.類加載時(Aspectj 5+)
3.運行時(Spring AOP)【本節課講解內容】

運行時值入

運行時織入是怎麼實現的
從靜態代理到動態代理
基於接口代理與基於繼承代理

3-3 代理模式

代理AOP對象

Caller:調用方
Proxy:AOP代理對象
Target:目標對象

代理模式類圖

clipboard.png

客戶端經過接口來引用目標對象
代理對象把真正的方法委託目標對象來執行,本身執行額外的邏輯

代碼編寫

1.編寫Subject類

package com.myimooc.myproxydemo.pattern;

/**
 * @title 代理對象接口
 * @describe
 * @author zc
 * @version 1.0 2017-09-13
 */
public interface Subject {
    
    void request();
    
}

2.編寫RealSubject類

package com.myimooc.myproxydemo.pattern;

/**
 * @title 目標對象
 * @describe 實現了Subject接口
 * @author zc
 * @version 1.0 2017-09-13
 */
public class RealSubject implements Subject{

    @Override
    public void request() {
        System.out.println("real subject execute request");
    }
    
}

3.編寫Proxy類

package com.myimooc.myproxydemo.pattern;

/**
 * @title 代理對象
 * @describe 一樣也實現了Subject接口
 * @author zc
 * @version 1.0 2017-09-13
 */
public class Proxy implements Subject{
    
    // 須要引用目標對象
    private RealSubject realSubject;

    // 強制必須傳入目標對象
    public Proxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        
        // 在目標對象方法執行以前作一些額外的事情
        System.out.println("before");
        
        try{
        
            // 代理對象不會作真實的業務邏輯,仍是委託給真實的目標對象執行
            realSubject.request();
        }catch (Exception e) {
            System.out.println("ex:"+e.getMessage());
            throw e;
        }finally {
            
            // 在目標對象方法執行以後作一些額外的事情
            System.out.println("after");
        }
    }
}

4.編寫Client類

package com.myimooc.myproxydemo.pattern;

/**
 * @title 客戶端
 * @describe 測試代理模式
 * @author zc
 * @version 1.0 2017-09-13
 */
public class Client {

    public static void main(String[] args) {
        Subject subject = new Proxy(new RealSubject());
        subject.request();
    }

}

3-4 JDK代理

靜態代理與動態代理

靜態代理的缺點:每當須要代理的方法越多的時候,重複的邏輯就越多
動態代理的兩類實現:基於接口代理與基於繼承代理
兩類實現的表明技術:JDK代理與Cglib代理

JDK實現要點

類:java.lang.reflect.Proxy
接口:InvocationHandler
只能基於接口進行動態代理

代碼編寫

1.編寫JdkSubject類

package com.myimooc.myproxydemo.jdkimpl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import com.myimooc.myproxydemo.pattern.RealSubject;

/**
 * @title 動態代理類
 * @describe 至關於AOP的aspect
 * @author zc
 * @version 1.0 2017-09-13
 */
public class JdkSubject implements InvocationHandler{
    
    // 一樣須要引入目標對象
    private RealSubject realSubject;
    
    public JdkSubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        // 在目標對象方法執行以前作一些額外的事情
        System.out.println("before");
        Object result = null;
        try{
            // 代理對象不會作真實的業務邏輯,仍是委託給真實的目標對象執行
            result = method.invoke(realSubject, args);
        }catch (Exception e) {
            System.out.println("ex:"+e.getMessage());
            throw e;
        }finally {
            // 在目標對象方法執行以後作一些額外的事情
            System.out.println("after");
        }
        return result;
    }
}

2.編寫Client類

package com.myimooc.myproxydemo.jdkimpl;

import java.lang.reflect.Proxy;

import com.myimooc.myproxydemo.pattern.RealSubject;
import com.myimooc.myproxydemo.pattern.Subject;

/**
 * @title 動態代理類
 * @describe JDK實現動態代理測試類
 * @author zc
 * @version 1.0 2017-09-13
 */
public class Client {
    
    public static void main(String[] args) {
        Subject subject = (Subject) Proxy.newProxyInstance(Client.class.getClassLoader(),
            new Class[]{Subject.class}, new JdkSubject(new RealSubject()));
        subject.request();
    }
    
}

3-5 JDK解析

JDK代理源碼解析

Proxy.newProxyInstance(首先,調用該方法)
getProxyClass0、ProxyClassFactory、ProxyGenerator(而後,分別調用方法,生成字節碼)
newInstance(最後,利用反射根據字節碼生成實例)

3-6 Cglib代理

代碼編寫

1.編寫DemoMethodInterceptor類

package com.myimooc.myproxydemo.cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * @title 須要植入的代碼類
 * @describe 須要實現MethodInterceptorj接口
 * @author zc
 * @version 1.0 2017-09-13
 */
public class DemoMethodInterceptor implements MethodInterceptor{

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("before in cglib");
        
        Object result = null;
        try{
            // 代理類調用父類的方法
            proxy.invokeSuper(obj, args);
        }catch (Exception e) {
            System.out.println("ex:"+e.getMessage());
            throw e;
        }finally {
            // 在目標對象方法執行以後作一些額外的事情
            System.out.println("after in cglib");
        }
        return result;
    }
}

2.編寫Client類

package com.myimooc.myproxydemo.cglib;

import com.myimooc.myproxydemo.pattern.RealSubject;
import com.myimooc.myproxydemo.pattern.Subject;

import net.sf.cglib.proxy.Enhancer;

/**
 * @title 動態代理類
 * @describe Cglib實現動態代理測試類
 * @author zc
 * @version 1.0 2017-09-13
 */
public class Client {
    
    public static void main(String[] args) {
        // 實例化Enhancer對象
        Enhancer enhancer = new Enhancer();
        // 設置須要代理的對象
        enhancer.setSuperclass(RealSubject.class);
        // 設置須要植入的代碼
        enhancer.setCallback(new DemoMethodInterceptor());
        // 生成代理類
        Subject subject = (Subject)enhancer.create();
        subject.request();
    }
}

JDK與Cglib代理對比

JDK只能針對有接口的類的接口方法進行動態代理
Cglib基於繼承來實現代理,沒法對static、final類進行代理
Cglib基於繼承來實現代理,沒法對private、static方法進行代理

3-7 Spring選擇

Spring建立代理bean時序圖

clipboard.png

SpringAOP對兩種實現的選擇

若是目標對象實現了接口,則默認採用JDK動態代理
若是目標對象沒有實現接口,則採用Cglib進行動態代理
若是目標對象實現了接口,但設置強制cglib代理,則使用cglib代理
在SpringBoot中,經過@EnableAspectJAutoProxy(proxyTargetClass=true)設置

3-8 鏈式調用

當多個AOP做用到同一個目標對象時,採用責任鏈模式

責任鏈模式類圖

clipboard.png

代碼編寫

1.編寫Handler類

package com.myimooc.myproxydemo.chain;

/**
 * @title 責任鏈模式
 * @describe 抽象接口
 * @author zc
 * @version 1.0 2017-09-13
 */
public abstract class Handler {
    
    // 後繼Handler,是否有類進行處理
    private Handler sucessor;
    
    // 對外暴露
    public void execute(){
        handleProcess();
        if(sucessor != null){
            sucessor.execute();
        }
    }
    
    // 由子類實現
    protected abstract void handleProcess();
    
    public Handler getSucessor() {
        return sucessor;
    }

    public void setSucessor(Handler sucessor) {
        this.sucessor = sucessor;
    }
    
}

2.編寫Client類

package com.myimooc.myproxydemo.chain;

/**
 * @title 責任鏈模式
 * @describe 測試類
 * @author zc
 * @version 1.0 2017-09-13
 */
public class Client {
    
    static class HandlerA extends Handler{
        @Override
        protected void handleProcess() {
            System.out.println("handle by a");
        }
    }
    static class HandlerB extends Handler{
        @Override
        protected void handleProcess() {
            System.out.println("handle by b");
        }
    }
    static class HandlerC extends Handler{
        @Override
        protected void handleProcess() {
            System.out.println("handle by c");
        }
    }
    
    public static void main(String[] args) {
        HandlerA handlerA = new HandlerA();
        HandlerB HandlerB = new HandlerB();
        HandlerC HandlerC = new HandlerC();
        // 設置連接關係
        handlerA.setSucessor(HandlerB);
        HandlerB.setSucessor(HandlerC);
        
        handlerA.execute();
    }
}

3.編寫Chain類

package com.myimooc.myproxydemo.chain;

import java.util.List;

/**
 * @title 責任鏈模式
 * @describe 封裝鏈式關係
 * @author zc
 * @version 1.0 2017-09-13
 */
public class Chain {
    
    private List<ChainHandler> handlers;
    
    private int index = 0;
    
    public Chain(List<ChainHandler> handlers){
        this.handlers = handlers;
    }
    
    public void proceed(){
        if(index >= handlers.size()){
            return;
        }
        handlers.get(index++).execute(this);
    }
}

4.編寫ChainHandler類

package com.myimooc.myproxydemo.chain;

/**
 * @title 責任鏈模式
 * @describe 對Handler進行封裝
 * @author zc
 * @version 1.0 2017-09-13
 */
public abstract class ChainHandler {
    
    public void execute(Chain chain){
        handleProcess();
        chain.proceed();
    }
    
    // 由子類實現
    protected abstract void handleProcess();
    
}

5.編寫ChainClient類

package com.myimooc.myproxydemo.chain;

import java.util.Arrays;
import java.util.List;

/**
 * @title 責任鏈模式
 * @describe 有順序的鏈式調用測試類
 * @author zc
 * @version 1.0 2017-09-13
 */
public class ChainClient {
    
    static class ChainHandlerA extends ChainHandler{
        @Override
        protected void handleProcess() {
            System.out.println("handle by a");
        }
    }
    static class ChainHandlerB extends ChainHandler{
        @Override
        protected void handleProcess() {
            System.out.println("handle by b");
        }
    }
    static class ChainHandlerC extends ChainHandler{
        @Override
        protected void handleProcess() {
            System.out.println("handle by c");
        }
    }
    
    public static void main(String[] args) {
        // 聲明鏈式調用順序
        List<ChainHandler> handlers = Arrays.asList(
            new ChainHandlerA(),
            new ChainHandlerB(),
            new ChainHandlerC()
        );
        
        Chain chain = new Chain(handlers);
        chain.proceed();
    }
}

第四章:代碼解讀

4-1 本節內容

上節回顧

靜態代理與動態代理
JDK代理與Cglib代理區別及侷限
代理模式與責任鏈模式

Spring AOP在開源項目裏面的應用:三個例子

事務:@Transactional:Spring如何利用Transaction進行事務控制
安全:@PreAuthorize:Spring Security如何利用PreAuthorize進行安全控制
緩存:@Cacheable:Spring Cache如何利用Cacheable進行緩存控制

經過案例來說解,源碼可到個人github地址查看

第五章:實戰案例

5-1 案例背景

實戰案例背景

商家產品管理系統
記錄產品修改的操做記錄
什麼人在什麼時間修改了哪些產品的哪些字段修改成什麼值

實現思路

利用aspect去攔截增刪改方法
利用反射獲取對象的新舊值
利用@Around的advice去記錄操做記錄

5-2 案例實現

建立名爲mydatalog的maven項目pom以下

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.myimooc</groupId>
  <artifactId>mydatalog</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>mydatalog</name>
  <url>http://maven.apache.org</url>

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
<!--         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency> -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.36</version>
        </dependency>
        
    </dependencies>
    
</project>

完成後的項目結構圖以下

圖片描述

受篇幅限制,源碼請到個人github地址查看

第六章:課程總結

6-1 課程總結

要點清單

AOP的適用範圍及優劣勢
AOP的概念及Spring切面表達式
AOP的實現原理及運用

使用SpringAOP的注意事項

不宜把重要的業務邏輯放到AOP中處理
沒法攔截static、final、private方法
沒法攔截內部方法調用

課程小結

合理利用面向切面編程提升代碼質量
掌握SpringAOP概念及實現原理
瞭解AOP的優缺點及SpringAOP的使用侷限
相關文章
相關標籤/搜索