本文为 SSM 框架系列之 Spring 第五部分:面向切面编程
其它内容的链接如下:
    1. HelloSpring
    2. 控制反转
    3. 依赖注入与装配机制
    4. 代理模式
    5. 面向切面编程
    6. 声明式事务

目录:

  • 1 AOP 的定义
  • 2 Spring 中的 AOP
  • 3 使用 Spring 实现 AOP
    • 3.1 通过使用 Spring API 接口实现
    • 3.2 通过自定义类来实现
    • 3.3 使用注解来实现

1 AOP 的定义

AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

面向切面编程是面向对象编程的补充,它将面向对象编程产生的各个业务模块所共同调用的部分封装起来,达到与主业务逻辑解耦的目的。同时,AOP 可以在不改变原来的代码的情况下,实现对原有功能的增强。(代理模式,开闭原则)


2 Spring 中的 AOP

AOP 是 Spring 的特性之一,它可以让我们通过少量的代码就可以完成面向切面编程的目的。

Spring AOP 就是基于动态代理的,Spring 中的 AOP 目前支持 JDK 动态代理和 Cglib 代理。

Spring 中的 AOP 定义如下:


其中的核心术语的含义如下:

  • 横切关注点:我们需要关注的部分,就是横切关注点;
  • 切面:横切关注点被模块化的特殊对象。是一个类;
  • 通知:切面需要完成的工作。是类中的一个方法;
  • 切入点:用来匹配特定接入点的表达式,通过切入点表达式匹配接入点是 AOP 的核心,Spring 默认使用AspectJ的切点表达式;
  • 织入:将一个或多个切面与类或对象链接在一起创建一个被增强对象;
  • 接入点:程序执行期的一个点,例如方法执行、类初始化、异常处理。

Spring AOP 中常用的四种 Advice 方式:

通知类型 连接点
前置通知 方法执行前
后置通知 方法放回后
环绕通知 方法前后
异常抛出通知 方法抛出异常时

下面感受一下同一 aspect,不同 advice 的执行顺序:

更多形式的通知的执行流程请看这位大神的博客:【传送门】


3 使用 Spring 实现 AOP

3.1 通过使用 Spring API 接口实现

1 导入 AOP 所需要的依赖包

    <!-- 经过实践证明,这段代码确实是必须要写的 --><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.encoding>UTF-8</maven.compiler.encoding><java.version>11</java.version><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.9.RELEASE</version></dependency><!-- AOP 所需要的依赖包 --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency></dependencies><!-- 静态资源导出 --><build><resources><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources></build>

2 编写原来的业务接口和实现类

package sharm.service;public interface Rent {public void rent();
}
package sharm.service;public class Host implements Rent {@Overridepublic void rent() {System.out.println("我是房东,我想要出租房子。");}
}

3 书写两个增强类,一个是前置增强,一个是后置增强。即我们需要织入的切面

3.1 前置增强

package sharm.log;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;public class BeforeLog implements MethodBeforeAdvice {//method : 要执行的目标对象的方法//args : 被调用的方法的参数//target : 目标对象@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println(target.getClass().getName() + "的" + method.getName() + "方法被执行了");// 额外加上的领域业务seeHouse();}//看房public void seeHouse(){System.out.println("带房客看房");}
}

3.2 后置增强

package sharm.log;import org.springframework.aop.AfterReturningAdvice;import java.lang.reflect.Method;public class AfterLog implements AfterReturningAdvice {//returnValue:返回值//method:被调用的方法//args:被调用的方法的对象的参数//target:被调用的目标对象@Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println("执行了" + target.getClass().getName()+"的"+method.getName()+"方法,"+"返回值:"+returnValue);// 额外加上的领域业务fare();}// 收中介费public void fare(){System.out.println("收中介费");}
}

4 配置 Spring 的配置文件,并且实现 AOP 切入

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!--注册bean--><bean id="host" class="sharm.service.Host"/><bean id="beforeLog" class="sharm.log.BeforeLog"/><bean id="afterLog" class="sharm.log.AfterLog"/><!--aop的配置--><aop:config><!--切入点 expression:表达式匹配要执行的方法--><aop:pointcut id="pointcut" expression="execution(* sharm.service.*.*(..))"/><!--执行通知。advice-ref:执行方法,pointcut-ref切入点--><aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/><aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/></aop:config></beans>

在切入点表达式execution(* sharm.service.*.*(..))中,各参数的含义如下:

  • execution() 表示表达式主体;

  • 第一个 * 表示返回类型为所有的类型;

  • sharm.service.表示包名。尾部的一个点表示当前包,两个点表示当前包下的所有子包;

  • 第二个 * 表示类名为所有的类;

  • *(..)中的星号表示所有的方法,后面的括号表示方法的参数,两个句点表示任何参数。

5 编写测试类

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import sharm.service.Rent;public class AopTest {@Testpublic void myTest(){ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// Bean 中用的是实现类,而返回值采用的是接口Rent hostService = (Rent)context.getBean("host");hostService.rent();}
}

6 控制面板输出

3.2 通过自定义类来实现

1 导入 AOP 所需要的依赖包

2 编写原来的业务接口和实现类

3 自定义切入类来实现 AOP

package sharm.log;public class CustomAspect {//看房public void seeHouse(){System.out.println("带房客看房");}// 收中介费public void fare(){System.out.println("收中介费");}
}

4 配置 Spring,非常关键

    <!--注册bean--><bean id="host" class="sharm.service.Host"/><bean id="customAspect" class="sharm.log.CustomAspect"/><!--aop的配置--><aop:config><!--第二种方式:使用AOP的标签实现--><aop:aspect ref="customAspect"><aop:pointcut id="customPointCut" expression="execution(* sharm.service.*.*(..))"/><aop:before pointcut-ref="customPointCut" method="seeHouse"/><aop:after pointcut-ref="customPointCut" method="fare"/></aop:aspect></aop:config>

6 编写测试类

7 控制面板输出

3.3 使用注解来实现

1 导入 AOP 所需要的依赖包

2 编写原来的业务接口和实现类

3 编写一个注解实现的增强类

package sharm.log;import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;@Aspect
public class AnnotationAspect {//看房@Before("execution(* sharm.service.*.*(..))")public void seeHouse(){System.out.println("带房客看房");}@After("execution(* sharm.service.*.*(..))")// 收中介费public void fare(){System.out.println("收中介费");}
}

4 在 Spring 配置文件中注册 bean,并增加支持注解的配置

    <!--注册bean--><bean id="host" class="sharm.service.Host"/><!--第三种方式:注解实现--><bean id="annotationPointcut" class="sharm.log.AnnotationAspect"/><aop:aspectj-autoproxy/>

通过aop命名空间的<aop:aspectj-autoproxy />声明自动为 spring 容器中那些配置@aspectJ切面的bean创建代理,织入切面。当然,spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了

<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用 jdk 动态代理织入增强,当配为<aop:aspectj-autoproxy poxy-target-class="true"/>时,表示使用 CGLib 动态代理技术织入增强。不过即使proxy-target-class设置为 false,如果目标类没有声明接口,则 spring 将自动使用 CGLib 动态代理。

5 编写测试类

6 控制面板输出

Spring05:面向切面编程相关推荐

  1. Spring-05 -AOP [面向切面编程] -Schema-based 实现aop的步骤

    一.AOP [知识点详解] AOP:中文名称面向切面编程 英文名称:(Aspect Oriented Programming) 正常程序执行流程都是纵向执行流程 3.1 又叫面向切面编程,在原有纵向执 ...

  2. 【Spring】面向切面编程AOP

    AOP基础 什么是AOP [废话解释]在软件业,AOP全称Aspect Oriented Programming 即:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AO ...

  3. 【spring】初识aop(面向切面编程) 使用jdk动态代理

    BankServiceIImple.java 代码实现: package com.zzxtit.aop;import java.math.BigDecimal;public interface Ban ...

  4. Spring 面向切面编程

    AOP,也就是面向方面编程或者说面向面编程,是一种很重要的思想.在企业级系统中经常需要打印日志.事务管理这样针对某一方面的需求,但是传统的面向对象编程无法很好的满足这些需求.因此催生了面向切面编程这样 ...

  5. Spring核心AOP(面向切面编程)

    AOP(面向切面编程) 原理 相关术语 系统日志增强 异常抛出增强 最终增强 环绕增强 使用注解实现AOP AspectJ 转载于:https://www.cnblogs.com/xhddbky/p/ ...

  6. Spring AOP 面向切面编程相关注解

    Aspect Oriented Programming 面向切面编程 在Spring中使用这些面向切面相关的注解可以结合使用aspectJ,aspectJ是专门搞动态代理技术的,所以比较专业. 需要在 ...

  7. java aop面向切面编程

    最近一直在学java的spring boot,一直没有弄明白aop面向切面编程是什么意思.看到一篇文章写得很清楚,终于弄明白了,原来跟python的装饰器一样的效果.http://www.cnblog ...

  8. Spring in Action 入门之面向切面编程AOP

    注明:这篇文章一是当成学习笔记,二是给大家提供另一个快速理解学习Spring的参考.欢迎留言讨论,持续更新中~ (该部分是Spring的面向切面编程AOP) 第四章 通知Bean 在软件编程中,散布于 ...

  9. 【AOP 面向切面编程】Android Studio 使用 AspectJ 监控方法运行原理分析

    文章目录 一.查看使用 AspectJ 后生成的 Class 字节码类 二.AspectJ 的本质 一.查看使用 AspectJ 后生成的 Class 字节码类 在 Android Studio 中查 ...

最新文章

  1. 这本 Kubernetes 图书,你一定不要错过!
  2. shaderlab学习一
  3. Android 超高仿微信图片选择器 图片该这么加载
  4. PHP 5.3-5.5 新特性
  5. JS中代表结束的三个关键字 break,continue,return
  6. java简易日历程序报告_简单的日历小程序(java编写)
  7. 毕业后想成为一名软件开发工程师,应该如何学习,大牛给出建议!
  8. 数据结构关键路径_2021年厦门大学考研丨能源学院845数据结构参考书目推荐
  9. GO语言学习之路23
  10. docunment对象
  11. Mac 苹果OS X小技巧:如何更改文件的默认打开方式
  12. as3实现(可以操纵的)真正的由惯性导致的漂移
  13. 勤哲Excel服务器2017
  14. 如何分辨usb压枪芯片是无后座压枪还是键鼠模拟压枪
  15. 推销员基础解法c++
  16. linux 配置局域网内部www服务器,局域网内部邮件服务器搭建方法
  17. 杀死一只知更鸟——派克的经典作品
  18. 95%的人都会答错的类加载的问题
  19. github官网访问太慢
  20. 原装苹果手机_苹果手机换个屏水这么深!嘉兴警方揭开“原装屏”真相

热门文章

  1. 又一国产开源项目走向世界,百度RPC框架Apache bRPC正式成为ASF顶级项目
  2. 数据仓库之ODS层设计概要
  3. latex 公式 (正式,非正式。编号,不编号)
  4. (P5)模型运行及结果可视化(netCDF)
  5. odoo12 数据文件翻译
  6. 什么是整洁代码?大咖程序员们这样说
  7. 微信音响服务器断是信号不好吗,HIFIDIY论坛-有人在微信上转发的一篇文章- 音响发烧大多并不是因为喜欢音乐 - Powered by Discuz!...
  8. Android基础篇 屏幕横竖屏切换(layout-land)下篇
  9. 机器学习模型部署PMML
  10. spark-ml和jpmml-sparkml生成pmml模型过程种遇到的问题