Spring AOP介绍(一)之 Spring AOP 基础介绍

时间:2022-06-19
本文章向大家介绍Spring AOP介绍(一)之 Spring AOP 基础介绍,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

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

欢迎留言进行讨论:) 我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=16n5qvyzybi7j