Spring基础20——AOP基础
1、什么是AOP
AOP(Aspect-Oriented Programming)即面向切面编程,是一种新的方法论,是对那个传统OOP面向对象编程的补充。AOP的主要编程对象是切面(aspect),而切面模块化横切关注点,在应用AOP编程时,仍需要定义公共功能但可以明确功能在哪里,以什么方式应用,并且不必修改受影响的类,这样一来横切关注点就模块化到了特殊得对象(切面)里,那么什么是面向切面编程呢?
下面我们通过一个例子来理解:
我们需要实现一个计算器,并且有以下两个需求:
需求1:日志,在程序执行期间追寻正在发生的活动。
需求2:希望计算器只能处理正数的运算。
首先我们来定义一个接口,来描述计算器的功能:
public interface ArithmeticCalculator {
/**
* 加法
* @param i
* @param j
* @return
*/
int add(int i, int j); /**
* 减法
* @param i
* @param j
* @return
*/
int sub(int i, int j); /**
* 乘法
* @param i
* @param j
* @return
*/
int mul(int i, int j); /**
* 除法
* @param i
* @param j
* @return
*/
int div(int i, int j);
}
之后我们实现这个接口并对方法进行实现:
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}
编写Main测试类对功能进行测试:
public class Main {
public static void main(String[] args) {
ArithmeticCalculator calculator = new ArithmeticCalculatorImpl();
System.out.println(calculator.add(1,2));
System.out.println(calculator.sub(2,1));
System.out.println(calculator.div(4,2));
System.out.println(calculator.mul(2,4));
}
}
我们可以观察到输出结果是正常的。
在上面的基础上,修改ArithmeticCalculatorImpl 我们下面来完成上面两个需求:
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
if (i < 0 ||j < 0 ) {
System.out.println("操作数必须为正数");
return -1;
}
System.out.println("The add method begin [ " + i + ", " + j + " ]" );
int result = i + j;
System.out.println("The add method end [ " + result + " ]" );
return result;
}
@Override
public int sub(int i, int j) {
if (i < 0 ||j < 0 ) {
System.out.println("操作数必须为正数");
return -1;
}
System.out.println("The sub method begin [ " + i + ", " + j + " ]" );
int result = i - j;
System.out.println("The sub method end [ " + result + " ]" );
return result;
}
@Override
public int mul(int i, int j) {
if (i < 0 ||j < 0 ) {
System.out.println("操作数必须为正数");
return -1;
}
System.out.println("The mul method begin [ " + i + ", " + j + " ]" );
int result = i * j;
System.out.println("The mul method end [ " + result + " ]" );
return result;
}
@Override
public int div(int i, int j) {
if (i < 0 ||j < 0 ) {
System.out.println("操作数必须为正数");
return -1;
}
System.out.println("The div method begin [ " + i + ", " + j + " ]" );
int result = i / j;
System.out.println("The div method end [ " + result + " ]" );
return result;
}
}
再次运行测试类:
public class Main {
public static void main(String[] args) {
ArithmeticCalculator calculator = new ArithmeticCalculatorImpl();
System.out.println(calculator.add(-1,2));
System.out.println(calculator.sub(2,1));
System.out.println(calculator.div(4,2));
System.out.println(calculator.mul(2,4));
}
}
输出结果:我们看到是实现了之前的需求。
2.使用动态代理对程序进行改进
我们用上面的代码实现了之前的两个需求,但是我们可以观察到,每个方法中都包含大量的重复代码,如果一旦需要修改日志或参数校验的规则,我们每个方法都要去修改,这显然是非常不利于维护的,那么我们可以采用——动态代理的方式来进行改进。代理模式原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象任何原始对象的调用都要通过代理,代理对象决定是否以及何时将方法调用转到原始对象上。
代理类ArithmeticCalculatorLoggingProxy:
public class ArithmeticCalculatorLoggingProxy {
private ArithmeticCalculator calculator; public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator calculator) {
this.calculator = calculator;
} public ArithmeticCalculator getCalculatorProxy() {
InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) {
System.out.println("The method " + method.getName() + " begin with " + Arrays.asList(args));
Object result = null;
try {
//前置通知
result = method.invoke(calculator, args);
//返回通知,可以访问到方法的返回值
} catch (Exception e) {
e.printStackTrace();
//异常通知,可以访问到方法出现的异常
}
//后置通知,方法可能会出异常,所以访问不到方法的返回值
System.out.println("The method add " + method.getName() +" with " + result);
return result;
}
};
return (ArithmeticCalculator) Proxy.newProxyInstance(calculator.getClass().getClassLoader(), calculator.getClass().getInterfaces(), handler);
}
}
将ArithmeticCalculatorImpl类改到最初的版本,重新运行测试类,我们可以得到同样的结果
3.AOP中的一些概念及AOP的好处
AOP中的一些概念:
切面(Aspect):横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象,如上图日志切面和验证切面(在后面还会讲spring aop切面的优先级)。
通知(Advice):切面必须要完成的工作。(切面里的每一个方法,比如前置日志和后置日志)
目标(Target):被通知的对象(被代理对象)
代理(Proxy):向目标对象应用通知之后创建的对象(代理对象)
连接点(JoinPoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示程序执行点;相对点表示的方位。例如ArithmethicCalculator#add()方法执行前的连接点执行点为ArithmethicCalculator#add()方位为该方法执行前位置。
切点(Pointcut):每个类都拥有多个连接点:例如ArithmethicCalculator的所有方法实际上都是连接点,即连接点是程序中客观存在的事物,AOP通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一一对应的关系,一个切点匹配多个连接点,切点通过org.springframework.aop.Pointcut接口进行描述,它使用类和方法作为连接点的查询条件。
AOP的好处:
每个事物逻辑位于一个位置,代码不分散,便于维护和升级
业务模块更加简洁只包含核心业务代码。
Spring基础20——AOP基础的更多相关文章
- Spring笔记:AOP基础
Spring笔记:AOP基础 AOP 引入AOP 面向对象的开发过程中,我们对软件开发进行抽象.分割成各个模块或对象.例如,我们对API抽象成三个模块,Controller.Service.Comma ...
- Spring IOC和AOP 基础
1 spring中注入资源是通过描述来实现的,在 spring 中是通过注解或者 XML 描述.spring 中IOC 注入方式有三种 1)构造方法注入 2)setter 注入 3)接口注入 1.1) ...
- 【AOP】Spring AOP基础 + 实践 完整记录
Spring AOP的基础概念 ============================================================= AOP(Aspect-Oriented Pr ...
- [Spring框架]Spring AOP基础入门总结二:Spring基于AspectJ的AOP的开发.
前言: 在上一篇中: [Spring框架]Spring AOP基础入门总结一. 中 我们已经知道了一个Spring AOP程序是如何开发的, 在这里呢我们将基于AspectJ来进行AOP 的总结和学习 ...
- [Spring框架]Spring AOP基础入门总结一.
前言:前面已经有两篇文章讲了Spring IOC/DI 以及 使用xml和注解两种方法开发的案例, 下面就来梳理一下Spring的另一核心AOP. 一, 什么是AOP 在软件业,AOP为Aspect ...
- CgLib动态代理学习【Spring AOP基础之一】
如果不了解JDK中proxy动态代理机制的可以先查看上篇文章的内容:Java动态代理学习[Spring AOP基础之一] 由于Java动态代理Proxy.newProxyInstance()的时候会发 ...
- Spring基础系列--AOP织入逻辑跟踪
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9619910.html 其实在之前的源码解读里面,关于织入的部分并没有说清楚,那些前置.后 ...
- Spring基础系列-AOP源码分析
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9560803.html 一.概述 Spring的两大特性:IOC和AOP. AOP是面向切 ...
- 15Spring AOP基础
为什么需要AOP? 先来看一段代码: package com.cn.spring.aop.helloworld; //加减乘除的接口类 public interface ArithmeticCalcu ...
随机推荐
- idea maven sync Cannot resolve xxx 的解决方案
经常会出现这种奇葩情况,提示找不到包 其实是因为网络波动或者突然断掉,导致包更新出现问题 直接去maven的仓库目录 找到不能找到的包 删掉相关目录 然后重新更新maven就行了 比如 直接去仓库目录 ...
- VUE生命周期demo
<!DOCTYPE html> <html> <head> <title></title> <script typ ...
- 后盾网lavarel视频项目---vue-axios基本用法
后盾网lavarel视频项目---vue-axios基本用法 一.总结 一句话总结: 都是npm安装,然后import引入vue,然后按手册使用就好了,很简单 二.vue-axios基本用法 转自或参 ...
- Emacs 浏览网页
Emacs 浏览网页非常方便,还可以忽略掉那些烦人的小广告.特别是在看小说 的时候~ 在之前了解如何通过Emacs浏览网页时,大部分人使用的是w3m,折腾了半天,没能成功.后来无意间发现 ,有EWW ...
- Jmeter(十二)响应断言之响应文本和响应信息的差别
在Jmeter的后置处理器中添加响应断言, 要测试的响应字段中有两个很难区分的选项, 响应文本和响应信息. 我做了两个小实验来进行区别. 1. 用Fiddler捕捉了一个POST请求, 其响应是suc ...
- Report List 报表开发
1. Report List的输出定义 * ...NO STANDARD PAGE HEADING: 输出的报表不包含表头: * ...LINE-SIZE col : 输出的报表不包含表头: * .. ...
- Professional JavaScript for Web Developers P226
我是这么理解的: (object.getName = object.getName),这条语句在执行结束后,返回的是右操作数object.getName: 但是关键是这个右操作数现在放在哪里 ? 我 ...
- VBA删除空白行列
'删除空行 Sub DeleteEmptyRows() Dim LastRow As Long, r As Long LastRow = ActiveSheet.UsedRange.Rows.Coun ...
- java:Oracle(级联删除,左右内外交叉自然连接,子查询,all,any,in)
1.级联删除: -- 级联删除:裁员,公司倒闭 -- 级联删除(cascade),设置为null(setnull),放任不管(No action) -- cascade:(以一对多为例)如果删除多的一 ...
- springmvc请求参数获取(自动绑定)的几种方法
1.直接把表单的参数写在Controller相应的方法的形参中,适用于get方式提交,不适用于post方式提交. /** * 1.直接把表单的参数写在Controller相应的方法的形参中 * @pa ...