在看了很多网上的资料和记录之后,我大概捋了下SpringAOP的各种阶段:

  1. 基本的advice编程,利用ProxyFactory拿代理类
  2. 利用spring把ProxyFactory,advice等bean化
  3. 切面编程,在advisor中编写advice和pointcut
  4. SpringAOP实现自动代理,也就是说不用闲式地配置ProxyFactory,和从ProxyFactory中拿代理类了,SpringAOP帮你解决了这些东西。
  5. AspectJ风格的注解式的Aspect编程

先记录一下AOP的几个概念:

AOP:

首先,AOP是Aspect-Originted Programming,即面向切面编程。我觉得可以这样地简单理解,aop就是为了你更清楚的逻辑,让你的业务逻辑代码更清晰,不用去想其他事,像日志啊,权限啊这些和业务逻辑无关的东西。那要怎么用这些又很重要的功能呢?我们不用改变原来的代码,只要在另一个个地方,把这些要附加的功能打包好,然后运行的时候切进你要用这些功能的地方,aop其实大概就是这样。好的那就来看看下面的几个名词:

advice:

翻译成增强、通知,其实就是你要做的东西,你要切到你的代码中的功能。aop框架会把advice模拟成拦截器interceptor。

Join Point:

连接点,就是你可以加入功能,加入advice的地方。Spring只支持在方法或者是抛出异常的地方建立使用通知,也就是说这些地方都可以是joinpoint,像其他aop像aspectJ还可以让你在构造器或属性注入时加入advice。

Pointcut:

刚刚JoinPoint我们说了哪些地方可以用advice,但不是所有地方都要用advice啊,所以就有了这个pointcut,就是加上条件的joincut。在写代码的时候,会用类似正则表达式的方式去选择那些joinpoint来作为pointcut。

Aspect:

切面,这个可是个很重要的概念哦。其实就是advice+pointcut。Spring AOP就是负责实施切面的框架, 它将切面所定义的横切逻辑织入到切面所指定的连接点中.

AOP的工作重心在于如何将增强织入目标对象的连接点上, 这里包含两个工作:

  1. 如何通过 pointcut 和 advice 定位到特定的 joinpoint 上
  2. 如何在 advice 中编写切面代码.

Introduction:

翻译成引入,就是引入允许我们向现有的类添加新方法或属性,从而无需修改这些现有类的情况下,让他们具有新的行为和状态。Spring AOP 允许我们为 目标对象 引入新的接口(和对应的实现). 例如我们可以使用 introduction 来为一个 bean 实现 IsModified 接口, 并以此来简化 caching 的实现.

Target:

目标,要加入新功能,新advice的目标类。就是不知道什么情况然后等等要被我们切入新功能的那个类。

AOP proxy:

一个类被 AOP 织入 advice, 就会产生一个结果类, 它是融合了原类和增强逻辑的代理类. 在 Spring AOP 中, 一个 AOP 代理是一个 JDK 动态代理对象或 CGLIB 代理对象.   可以说,spring aop就是用动态代理来实现的,我理解的,就是我们要在一个target类中加入新功能嘛,就通过一个代理类来实现,代理类是原来目标类+advice的结合,可以想象成变强了的target类的替身。那么要怎样才能成为这个替身呢?要么就实现一样的接口(jdk动态代理的原理),要么就继承target类称为它的子类(CGLIB的原理)。

Weaving:

织入,将aspect和其他对象连接起来,并创建adviced object的过程。(可以把weaving理解成动词,introduction理解成名词)。根据不同的技术,weaving的方式有三种:编译器织入,要求有特制的编译器;类装载期织入,这需要特殊的类装载期器;动态代理织入,在运行期间为target添加advice的方式。

一、先是非常原始的advice实现

这里我们写一个非常原始的,连spring bean都不用的例子来帮助理解aop。写的是advice增强,用的是jdk代理的方式,也就是接口代理。但要先引入Spring aop的相关jar包

思路就是,要加强的类实现一个接口,然后advice作为加强类,要实现SpringAOP提供的Advice相关接口。然后通过ProxyFactory来拿代理类,往代理类中addAdvice来达到加强的效果。

这里我们有个Greeting接口。

package com.stuPayment.aopTest;

public interface Greeting {
public void sayHello(String name);
public int saySth();
}

然后它的实现:

package com.stuPayment.aopTest;

public class GreetingImpl implements Greeting {
@Override
public void sayHello(String name) {
// TODO Auto-generated method stub
System.out.println("hello, " + name);
} @Override
public int saySth() {
// TODO Auto-generated method stub
System.out.println("this is say sth");
return 213;
} public int sayMorning(String name) {
System.out.println("good morning, " + name);
return 123;
} public void sayAfternoon(String name) {
System.out.println("good afternoon, " + name);
}
}

然后是我们的advice增强类,要这里我们用的是MethodBeforeAdvice接口和AfterReturningMethod,表示着advice是加在方法调用前还是方法返回之后。

package com.stuPayment.aopTest.advice;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice; public class GreetingBeforeAndAfterAdvice implements MethodBeforeAdvice, AfterReturningAdvice{
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
// TODO Auto-generated method stub
System.out.println("this is after");
} @Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
// TODO Auto-generated method stub
System.out.println("this is before");
} }

然后测试类:

package com.stuPayment.aopTest;

import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory; import com.stuPayment.aopTest.advice.GreetingAroundAdvice;
import com.stuPayment.aopTest.advice.GreetingBeforeAndAfterAdvice; public class Test1 {
@Test
public void demo1() {
ProxyFactory proxyFactory = new ProxyFactory();//创建代理工厂
proxyFactory.setTarget(new GreetingImpl());//注入目标类对象
proxyFactory.addAdvice(new GreetingBeforeAndAfterAdvice());//添加前置加强和后置加强
//proxyFactory.addAdvice(new GreetingAroundAdvice());//添加前置加强和后置加强
Greeting greeting = (Greeting)proxyFactory.getProxy();//从代理工厂中获取代理
greeting.sayHello("Ben");//调用代理的方法
greeting.saySth();
}
}

结果:

所以大概思路就是,编写一个增强类去实现Spring aop提供的几个advice的接口(其实这些接口就是决定在接入点的哪个位置加入新advice),然用aop给的ProxyFactory,先设定一个target,然后addAdvice来加入你要切入的功能,然后你就可以通过这个代理工厂来获得一个代理类(对应接口的),一个加强后的adviced object,调用它里面方法就会看到advice的效果。

然后SpringAop给了好几种Advice的增强接口:

二、一般,到了后面,我们会把这个Proxy的配置加入Spring的配置文件中

这个greetingAroundAdvice就像我们刚刚那个GreetingBeforeAndAfterAdvice一样是个实现了一个advice接口的增强类。

这里再介绍一下一个Introduction Advice,来看看jdk动态代理和CGLIB类代理的区别。

上面说到,这个引介增强Introduction Advice是一种特殊的增强,之前的连接点都是方法级别的,而这个是类级别的,也就是对类的加强。

引入增强Introduction Advice的概念:一个Java类,没有实现A接口,在不修改Java类的情况下,使其具备A接口的功能。

先定义一个新接口Love:

然后定义授权引入增强类:

这个DelegatingIntroductionInterceptor就是一个引入的advice类,继承它就有这种advice的能力。

然后是Proxy的配置:

proxyTargetClass属性表示是否代理目标类,默认是false,也就是代理接口,上面一个例子的配置就是没有这一项属性所以用JDK动态代理,现在是true即使用CGLib动态代理。

然后看测试方法里面:

首先看到,从代理里面拿这个GreetingImpl的时候,不是像以前一样:Greeting greeting = (Greeting).......

而是直接用实现类GreetingImpl来拿。因为现在是代理目标类而不是接口类。

然后是这里的Love love = (Love)greetingImpl是将目标类强制向上转换成了Love接口,但注意,我们并没有把这个greetingImpl实现这个Love接口哦,这就是引用增强(DelegatingIntroductionInterceptor)的特性——“接口动态实现的”功能。所以display()方法可以由GreetingImpl的对象来调用,只需要强行转换接口就行了。

三、好了,在advice的层次下的编程之后,就到了后面aspect切面的编程了:

所谓切面,其实就是advice+pointcut,我们在切面中一般要做的就是定义要加的功能还有正则表达式确定要拦截的方法。

这里开始内容就很多了,也有点乱,这里稍微捋一下,迟点会通过阅读相关的书籍来理清楚关系。

切面编程一开始,我们可以通过springAOP提供的切面类RegexpMethodPointcutAdvisor来配置切面。一样还是刚刚的实现了Greeting的GreetingImpl作为target,配置文件如下:

这上面的proxy中的配置中的InterceptorNames,不再是之前的advice加强了,而是一个定义好的切面。我们看这个greetingAdvisor的bean的配置,可以看到一个属性是advice,而另一个是pattern,其实就相当于要加强的功能和pointcut。

再往后发展,proxy也不用怎么写配置了,有了个叫aop自动代理的东西,大概就是spring框架自动生成代理:

配置文件:(属性optimize为true,表示,如果target有接口,就用jdk动态代理,若谷target没有接口,就用CGLib动态代理)

还有测试代码:

此时因为是自动代理,getBean()的值不再是原来的代理id(greetingProxy),而是目标类GreetingImpl的bean的id,这同样也是个代理类,只是自动代理,隐藏了代理的工作和代码。

再往后,就到了AspectJ风格的切面编程,用注解就可以完成切面的编程,大大节省了配置的时间。

 

 

先是利用<aop:config>元素声明切面的方法,配置文件类似于下图的xml:

也可以直接使用@Aspect注解,只需要配置文件中简单得配置一下自动代理:

<context:component-scan base-package="demo.spring"/>  <!-- 用@Component自动发布bean,需要配置这个元素。 -->

<aop:aspectj-autoproxy />     <!-- 使用@AspectJ及其它AOP注解需要配置,否则无法使用注解;@AspectJ注解,将@Component自动发布出来的"interceptor" bean转换为一个aspectj切面,而@Pointcut、@Before、@After、@Around等注解,功能与在xml文件中配置是一样的;@Pointcut注解下面的方法内容无意义,只是要求一个相应方法提供注解依附。 -->

注解只能在使用能获得源码的场景,如果不能获取源码,则只能通过xml配置的形式,将指定的对象配置成拦截器,对指定的目标进行拦截;因此,通过xml文件配置,而不是注解,是更加通用的方式。

然后再下一篇博客,会记录如何在Springboot用AspectJ风格的注解来用SpringAOP实现一个日志记录的功能。

参考过的博客:

https://blog.csdn.net/h525483481/article/details/79625718

https://blog.csdn.net/icarus_wang/article/details/51737474 讲增强类型的

https://www.cnblogs.com/jacksonshi/p/5863313.html

梳理一下我理解的aop的更多相关文章

  1. 深入理解Spring AOP之二代理对象生成

    深入理解Spring AOP之二代理对象生成 spring代理对象 上一篇博客中讲到了Spring的一些基本概念和初步讲了实现方法,当中提到了动态代理技术,包含JDK动态代理技术和Cglib动态代理 ...

  2. ctr预估论文梳理和个人理解

    问题描述 ctr的全称是click through rate,就是预估用户的点击率,可以用于推荐系统的ranking阶段.ctr预估可以理解为给用户的特征.item的特征以及context的特征(比如 ...

  3. spring 理解Spring AOP 一个简单的约定游戏

    应该说AOP原理是Spring技术中最难理解的一个部分,而这个约定游戏也许会给你很多的帮助,通过这个约定游戏,就可以理解Spring AOP的含义和实现方法,也能帮助读者更好地运用Spring AOP ...

  4. 正确理解Spring AOP中的Around advice

    Spring AOP中,有Before advice和After advice,这两个advice从字面上就可以很容易理解,但是Around advice就有点麻烦了. 乍一看好像是Before ad ...

  5. Spring 梳理 - filter、interceptor、aop实现与区别 -第二篇

    spring mvc中的Interceptor可以理解为是Spring MVC框架对AOP的一种实现方式.一般简单的功能又是通用的,每个请求都要去处理的,比如判断token是否失效可以使用spring ...

  6. 曹工说Spring Boot源码(21)-- 为了让大家理解Spring Aop利器ProxyFactory,我已经拼了

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  7. 如何简单理解spring aop和事务

    用比喻的方法理解吧: 初学者的理解,仅仅为了个人好记 aop:由三部分组成:工具箱,工人,为工人分配工具 tx事务:由四部分组成:管理者,制度,工人,向工人通知管理制度  为什么这样理解呢?个人觉得好 ...

  8. 理解Spring AOP的实现方式与思想

    Spring AOP简介 如果说IOC是Spring的核心,那么面向切面编程就是Spring最核心的功能之一了,在数据库事务中,面向切面编程被广泛应用. AOP能够将那些与业务无关,却为业务模块所共同 ...

  9. 轻松理解 Spring AOP

    目录 Spring AOP 简介 Spring AOP 的基本概念 面向切面编程 AOP 的目的 AOP 术语和流程 术语 流程 五大通知执行顺序 例子 图例 实际的代码 使用 Spring AOP ...

随机推荐

  1. Codeforces Round #383 (Div. 2) C. Arpa's loud Owf and Mehrdad's evil plan —— DFS找环

    题目链接:http://codeforces.com/contest/742/problem/C C. Arpa's loud Owf and Mehrdad's evil plan time lim ...

  2. Oracle数据查看被锁住的用户

    //lock_date是被锁住时间,如果为空证明这个用户没有被锁住 select username,lock_date from dba_users where username='GFMIS';   ...

  3. 通过dom4j写.xml文件

    步骤: 1.左键选中src,点击红圈2: 2.新建类: 3.开始写代码: package com.bjsxt.xml; import java.io.File; import java.io.File ...

  4. AC自动机-题目集合

    AC自动机-题目集合 模板 如果你想要学习AC自动机,推荐一些学习资料. 学习可以看这篇博客 http://blog.csdn.net/niushuai666/article/details/7002 ...

  5. python 二分法例子及冒泡排序

    #!/usr/bin/env python #-*- coding:utf-8 -*- def binary_search(source_data,find_nu): mid = len(source ...

  6. @PathVariable @RequestParam @RequestHeader @CookieValue POJO Servlet API

  7. SSH框架中hibernate 出现 user is not mapped 问题

    SSH框架中hibernate 出现 user is not mapped 问题      在做SSH框架整合时,在进行DAO操作时.这里就只调用了chekUser()方法.运行时报  user is ...

  8. activeMQ:java消息机制初试(一)

    前言:自打学习编程以来,就知道activeMQ这么个东西,但是仅仅限于只知其名,不闻其详.现在加入到新的项目组,项目中使用了这个.现在想重新去学习和了解.最后整合成一个完成的demo,在网上看的Dem ...

  9. CF-805B

    B. 3-palindrome time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...

  10. js的call()通俗解释

    var x = "我是全局变量"; //定义全局变量x function a(){ //定义函数类结构a this.x = "我是在函数类结构a中声明的哦"; ...