Spring AOP介紹(一)之 Spring AOP 基礎介紹

spring.png

Spring AOP介紹(一)之 Spring AOP 基礎介紹

AOP是什麼?

AOP(Aspect Oriented Programming),即面向切面編程,可以說是OOP(Object Oriented Programming,面向對象編程)的補充和完善。與OOP對比,AOP面向切面,傳統的OOP開發中,代碼邏輯是自上而下的,在這些自上而下的過程中,會產生一些橫切性的問題,這些橫切性的問題和我們的主業務邏輯關係不大,會散落在代碼的各個地方,造成難以維護,AOP的變成思想就是把業務邏輯和橫切的問題進行分離,從而達到解耦的目的,提到代碼的可重用性與開發效率。

可以看下這個圖:

spring aop場景.png

AOP的應用場景有哪些?

如上圖中顯示的:

  • 日誌記錄
  • 權限驗證
  • 事務管理
  • 等等
Spring對於AOP是怎樣實現的呢?
  • JDK動態代理(接口實現)

JDK原生動態代理是Java原生支持的,不需要任何外部依賴,但是它只能基於接口進行代理

  • CGLIB代理(繼承)

CGLIB(Code Generation Library)是一個基於ASM的字節碼生成庫,
它允許我們在運行時對字節碼進行修改和動態生成。CGLIB通過繼承方式實現代理。

編譯時期的織入還是運行時期的織入?

兩者都是在運行時期織入(後面有源碼介紹)

初始化時期織入還是獲取對象時期織入?

通過源碼分析,可以知道是在初始化時期織入(後面有源碼介紹)

Spring AOP和AspectJ的關係是什麼?

對於Spring AOP來說,AOP是實現的目標,AspectJ是實現的手段,類似的還有IOC(Inversion of Control 控制反轉)是目標,實現的手段是DI(Dependency Injection 依賴注入)。

Spring AOP提供兩種編程風格

  • @AspectJ support (利用aspectj的註解)
  • Schema-based AOP support (xml aop:config 命名空間)
Spring AOP應用

讓我們首先了解一些AOP概念和術語。

概念 描述
Join point(連接點) 目標對象中的方法,類似數據庫表中的一條記錄
PointCut(切點) 表示連接點的集合,類似數據庫中的表
Advice(通知) 通知指的就是指攔截到連接點之後要執行的代碼,通知分爲前置、後置、異常、最終、環繞通知五類
Aspect(切面) 切點、連接點、通知等的載體,它們加起來就是一個切面
Target object(目標對象) 包含連接點的對象,也被稱作被通知或被代理對象
AOP proxy(AOP 代理對象) AOP創建的對象,包含通知
Weaving(織入) 把代理邏輯加入到目標對象的過程,叫做織入
Before advice(前置通知) 前置通知
After returning advice(後置通知) 後置通知
Around advice(環繞通知) 前後都有,最常用的一種通知
簡單代碼演示

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<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.demo.spring</groupId>
  <artifactId>spring-aop</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>spring-aop Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>5.1.5.RELEASE</version>
      </dependency>

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


      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
      </dependency>
  </dependencies>
</project>

com.demo.spring.dao.TestDao

package com.demo.spring.dao;

import org.springframework.stereotype.Component;

/**
 * PACKAGE_NAME
 *
 * @author Zyy
 * @date 2019/3/4 23:03
 */
@Component
public class TestDao {

    public void query(){
        System.out.println("dao-query ...");
    }
}

com.demo.spring.config.AppConfig

package com.demo.spring.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * com.demo.spring.config
 *
 * @author Zyy
 * @date 2019/3/4 23:05
 */
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.demo.spring")
public class AppConfig {
}

com.demo.spring.config.AspectJTest

package com.demo.spring.config;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * com.demo.spring.config
 *
 * @author Zyy
 * @date 2019/3/4 23:36
 */
@Aspect
@Component
public class AspectJTest {

    @Pointcut("execution(* com.demo.spring.dao.*.*(..))")
    public void pointCut(){
        System.out.println("point cut");
    }

    @After("com.demo.spring.config.AspectJTest.pointCut()")
    public void after(){
        System.out.println("after advice");
    }

    @Before("com.demo.spring.config.AspectJTest.pointCut()")
    public void before(){
        System.out.println("before advice");
    }
}

com.demo.spring.test.AopTest

package com.demo.spring.test;

import com.demo.spring.config.AppConfig;
import com.demo.spring.dao.TestDao;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * com.demo.spring.test
 *
 * @author Zyy
 * @date 2019/3/4 23:07
 */
public class AopTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        TestDao dao = context.getBean(TestDao.class);
        dao.query();
    }
}

運行結果:

before advice
dao-query ...
after advice

歡迎留言進行討論:)

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