师爷,翻译翻译什么叫AOP
张麻子:汤师爷,翻译翻译,什么叫AOP?
汤师爷:这还用翻译。
张麻子:我让你翻译给我听,什么叫AOP?
汤师爷:不用翻译,切面编程就是AOP啊。
黄四郎:难道你听不懂什么叫AOP?
张麻子:我就想让你翻译翻译,什么叫AOP!
汤师爷:AOP嘛。
张麻子:翻译出来给我听,什么他妈的叫AOP!什么他妈的叫他妈的AOP!
汤师爷:什么他妈的叫AOP啊?
黄四郎:AOP就是Aspect Oriented Programming,面向切面编程!明白了吗?
汤师爷:这就是AOP啊。
张麻子:翻译翻译。
汤师爷:...
汤师爷:AOP就是Aspect Oriented Programming!面向切面编程!面向!切面!横着切!切面!
张麻子:哈,大哥这是他妈的AOP啊,小弟我马上给个三连。
下面我们好好翻译一下AOP切面编程。
老规矩,在学习切面面编程之前要有前置知识:
目标
• 动态代理搞明白,AOP就明白了
• 学会在开发中使用Spring的AOP技术
概念
AOP 是 Aspect Oriented Programming,和OOP(Object Oriented Programming)一词之差,OOP强调万物皆是对象,那AOP呢?
要真正理解 AOP 就要理解 AOP 的核心:Aspect。
WTF is Aspect?
我们把aspect翻译成切面,但是切面这个词对应中文语义其实很难理解到位。
我们换种解释,aspect我们理解为事物的某个方面、某个视角。
与面向对象思想相对,对象强调一个整体,一个人站在你面前,我们称之为对象。
而aspect强调功能化、模块化、关注点分离。
天气变冷了,人要多穿衣服,上帝控制这么多人的对象,总不能一件一件穿吧?
所以AOP思想就是把天气变冷穿衣服这件事抽离出来,模块化,单独进行关注,然后经过编码实现后,上帝就可以进行一键穿衣,节省了大量工作。
放在实际开发中,我们以最常见的日志打印为例。
我们系统中有200个Controller,都要打印请求日志,那没有AOP思想的实践的话,我们只能一个一个在Controller里编写一遍又一遍的重复代码,有了AOP思想,就可以考虑把日志打印这件事抽离出来做成单独的业务,实现一劳永逸。
那怎么实现呢?
那就要靠我们的动态代理了。
什么?你还没看动态代理?
上帝在吗?把这个人的棉衣扒了。
Spring实现AOP
我们知道框架的存在意义是用来简化开发的。
这里Spring简化了什么呢?
自然是我们在动态代理部分编写的一大堆要么看不懂,看懂了又不想写的代码。
AOP作为Spring的左膀右臂之一,自然对这部分加以简化。
但Spring那一大堆xml也是够够的。
所以SpringBoot才是我们永远的家。
废话不多说直接上代码示例,在AOP代码的编写中提出问题,解决问题,那么最后就算是学会了。
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--aop-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
编写代码
编写这部分代码的逻辑也是非常符合我们的认知逻辑的。
我们前边已经说清楚AOP是做什么的了。
那我们编写代码就要做3件事:
• 抽离出功能模块——定义切面
• 确认功能代码加在哪——定义切点
• 确认功能代码什么时候执行——选择通知类型
我们先把controller给出来:
@RestController
public class AopController {
@RequestMapping("/hello")
public String sayHello(){
System.out.println("hello");
return "hello";
}
}
定义一个切面
也就是抽离出功能模块。
先随便写个类。
然后就直接一个@Aspect就行了,那这个类就是一个切面类。
还要再加一个@Component将该类纳入Ioc容器。
就这么简单,狗来了都会写。
@Aspect
@Component
public class AopAdvice {
}
定义一个切点
也就是确认功能代码加在哪。
先随便写一个方法。
然后就直接一个@Pointcut就行了,那这个方法就是一个切点。
还要再加上表达式,让系统知道代码加到什么位置。
@Aspect
@Component
public class AopAdvice {
@Pointcut("execution (* com.example.aop.controller.*.*(..))")
public void test() {
}
}
这时候有同学问:
啊这个execution是什么?
里面那又是一坨什么?
根本看不懂。
举报了。
这个我只能说,这是固定的表达式,是规定。
规定什么?
看规定之前先记住:表达式一定从右往左匹配。
看规定之前先记住:表达式一定从右往左匹配。
看规定之前先记住:表达式一定从右往左匹配。
execution(访问修饰符(可省略) 方法返回值 包名.类名.方法名(参数))
参数:..代表任何参数
方法: *代表任何方法
类名: *代表所有类
包名: *代表所有包 ..代表子孙包
返回值: *代表所有类型返回值
具体的写法实际五花八门,而且除了execution还有一大堆,为了不让大脑过度疲劳,我们一次只有一个目标:
会用,但不精通。
选择通知类型
也就是确认功能代码什么时候执行。
下面就是通知类型5种,前3种比较常用:
前置通知(@Before):在目标方法调用之前调用通知
后置通知(@After):在目标方法完成之后调用通知
环绕通知(@Around):在被通知的方法调用之前和调用之后执行自定义的方法
返回通知(@AfterReturning):在目标方法成功执行之后调用通知
异常通知(@AfterThrowing):在目标方法抛出异常之后调用通知
代码如下:
@Aspect
@Component
public class AopAdvice {
@Pointcut("execution (* com.example.aop.controller.*.*(..))")
public void test() {
}
@Before("test()")
public void beforeAdvice() {
System.out.println("beforeAdvice...");
}
@After("test()")
public void afterAdvice() {
System.out.println("afterAdvice...");
}
@Around("test()")
public void aroundAdvice(ProceedingJoinPoint joinPoint) {
System.out.println("before");
try {
joinPoint.proceed();
} catch (Throwable t) {
t.printStackTrace();
}
System.out.println("after");
}
}
从以上代码中可以看出,@Before和@After都已经简单到不能再简单了。
我们需要说一下这个@Around 环绕通知。
joinPoint.proceed()这行代码我们就理解为我们需要增强的那个方法的替身就行了。
这也不是想说的,这里我们主要讲一下 ProceedingJoinPoint joinPoint 这个参数。
ProceedingJoinPoint 是一个接口,也就是说这里实际是使用了多态,这不重要。
ProceedingJoinPoint 继承了 JoinPoint 这个接口。
这个JoinPoint有2个方法是我们需要说的。
Object getTarget();
Signature getSignature();
getTarget() 方法返回的是目标对象,即那个被增强方法所属的对象实例。
getSignature() 方法返回的是连接点的签名,即关于被调用的方法(或访问的字段等)的静态信息,如方法名、返回类型、参数类型等。
那么通过这2个方法,就能获取到所有的对象信息和方法信息,那么能做的事就太多了。
但是我们这里不展示更复杂的案例。
依然坚持我们本篇的策略:
懂点,但不多。
会用,但不精。
测试
启动项目,浏览器访问:
http://localhost:8080/hello
运行结果:
before
beforeAdvice...
hello
afterAdvice...
after
往期推荐:
● 0.o?让我看看怎么个事儿之SpringBoot自动配置
● 学会@ConfigurationProperties月薪过三千
师爷,翻译翻译什么叫AOP的更多相关文章
- (翻译) 使用Unity进行AOP对象拦截
Unity 是一款知名的依赖注入容器( dependency injection container) ,其支持通过自定义扩展来扩充功能. 在Unity软件包内 默认包含了一个对象拦截(Interce ...
- R语言包翻译——翻译
Shiny-cheatsheet ...
- Python函数:使用谷歌翻译翻译英语字符串
代码是同事写的,我把它单独抠出来,可以作为工具函数使用.当然,性能还是个问题,有待解决. import random import cookielib import urllib import url ...
- C# 调用百度翻译Api
这是简单的界面.用的是wpf,winform也可以 具体的操作类 public partial class MainWindow : Window { string url = "" ...
- 四大高质量且实用的chrome翻译插件推荐
Google英译汉的质量怎么样?日常生活用语翻译还可以,但是一到专业性术语就歇菜了,翻译出来的东西简直就是惨不忍睹,惨绝人寰..对于酷爱英语学习又有强迫症的患者来说,一款既实用又方便,无疑就是雪中送炭 ...
- 干货|人人都是翻译项目的Master
在平时的工作中,我们都会经常查阅一些英文文档来解决平时遇到的问题和拓宽视野.看到好的文章或者书籍有没有想要和小伙伴分享的冲动,那么我们一起来翻译吧- 翻译主张 "信 达 雅" .& ...
- IDEA Translation插件中有道智云(有道翻译)应用ID,密钥申请教程
登录链接 该登录登录,该注册注册(信息随意填写) 自然语言翻译=>翻译实例=>创建实例(信息随意填写) QQ截图20170701231552.png 应用管理=>我的应用=>创 ...
- 完善chrome翻译插件ChaZD,支持有道智云api
首先放上该项目的github地址:https://github.com/codethereforam/ChaZD 之前想找一个chrome支持划词翻译的插件,最终在知乎上看到了这个回答,推荐的是Cha ...
- selenium批量翻译
Python爬虫视频教程零基础小白到scrapy爬虫高手-轻松入门 https://item.taobao.com/item.htm?spm=a1z38n.10677092.0.0.482434a6E ...
- 论文翻译——Rapid 2D-to-3D conversion——快速2D到3D转换
https://blog.csdn.net/qq_33445835/article/details/80143598 目前想做一个关于2D转3D的项目,由于国内资料比较少而且大部分都是基于国外的研究 ...
随机推荐
- Centos8.4自定义离线安装Nginx
一.简介 Nginx是一个web服务器也可以用来做负载均衡及反向代理使用. 目前使用最多的就是负载均衡,这篇文章主要介绍了centos8 安装 nginx. Nginx是一种开源的高性能HTTP和反向 ...
- SpringBoot Seata 死锁问题排查
现象描述:Spring Boot项目,启动的时候卡住了,一直卡在那里不动,没有报错,也没有日志输出 但是,奇怪的是,本地可以正常启动 好吧,姑且先不深究为什么本地可以启动而部署到服务器上就无法启动的问 ...
- 在arm架构的银河麒麟系统部署Redis
以下是在arm架构的银河麒麟系统上部署Redis的详细步骤: 1. 创建文件夹 首先,在合适的位置创建必要的文件夹.在本例中,我们将创建/opt/redis和/usr/src/redis两个文件夹. ...
- NetSuite 开发日记 —— 事务处理行限制
一.创建行限制 在 NetSuite 中处理事务时,一次可访问的记录.事务处理或数据行数限制为 10,000.除非另有说明,此限制适用于所有交易类型.超过 1,000 行可能会对 Netsuite 的 ...
- Spring源码学习之Web数据绑定器WebDataBinder
WebDataBinder 1.描述 特殊的数据绑定器用于从web请求参数到JavaBean对象的数据绑定.专为web环境,但不依赖于Servlet API;作为更具体的DataBinder变体的基类 ...
- 从零玩转第三方登录之WeChat公众号扫码关注登陆 -wechatgzh
title: 从零玩转第三方登录之WeChat公众号扫码关注登陆 date: 2022-09-27 22:46:53.362 updated: 2023-03-30 13:28:41.359 url: ...
- C#/.NET/.NET Core优秀项目和框架2023年12月简报
前言 公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(公众号每周至少推荐两个优秀的项目和框架当然节假日除外),公众号推文有项目和框架的介绍.功能特点以及部分功能截图等(打不 ...
- 部署堡垒机3——编译安装redis-6.2.1以上版本
一.环境准备 Redis官网:https://redis.io/download/ 历史版本:http://download.redis.io/releases/ 1.安装依赖 yum -y in ...
- Java 新技术:虚拟线程使用指南(二)
虚拟线程是在 Java 21 版本中实现的一种轻量级线程.它由 JVM 进行创建以及管理.虚拟线程和传统线程(我们称之为平台线程)之间的主要区别在于,我们可以轻松地在一个 Java 程序中运行大量.甚 ...
- python -m http.server在本地启动简单HTTP服务器的命令
1.python -m http.server 命令 python -m http.server 是一个用于在本地启动简单 HTTP 服务器的命令.这个命令会在当前工作目录启动一个基本的 HTTP ...