摘要: 本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。

我们知道,使用面向对象编程(OOP)有一些弊端,当需要为多个不具有继承关系的对象引人同一个公共行为时,例如日志、安全检测等,我们只有在每个对象里引用公共行为,这样程序中就产生了大量的重复代码,程序就不便于维护了,所以就有了一个对面向对象编程的补充,即面向方面编程(AOP),AOP所关注的方向是横向的,不同于OOP的纵向。

Spring中提供了AOP的实现,但是在低版本Spring中定义一个切面是比较麻烦的,需要实现特定的接口,并进行一些较为复杂的配置。低版本Spring AOP的配置是被批评最多的地方。Spring听取了这方面的批评声音,并下决心彻底改变这一现状。在Spring2.0中,SpringAOP已经焕然一新,你可以使用@AspectJ注解非常容易地定义一个切面,不需要实现任何的接口。

Spring 2.0采用@AspectJ注解对POJO进行标注,从而定义一个包含切点信息和增强横切逻辑的切面。Spring 2.0可以将这个切面织人到匹配的目标Bean中。@AspectJ注解使用AspectJ切点表达式语法进行切点定义,可以通过切点函数、运算符、通配符等高级功能进行切点定义,拥有强大的连接点描述能力。我们先来直观地浏览一下Spring中的AOP实现。

接下来一起看看@AspectJ注解是如何使用的。

目录

一、创建用于拦截的bean

二、创建Advisor

三、创建配置文件

四、测试

在开始前,先配置Aspect。

<!-- aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>

一、创建用于拦截的bean

在实际工作中,此bean可能是满足业务需要的核心逻辑,例如test方法中可能会封装着某个核心业务,但是,如果我们想在test前后加人口志来跟踪调试,如果直接修改源码并不符合面向对象的设计方法,而且随意改动原有代码也会造成一定的风险,还好接下来的Spring帮我们做到了这一点。

public class Audience {

    private String name = "audience";

    public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public void watch() {
System.out.println("Watch movie");
}
}

二、创建Advisor

Spring中摒弃了最原始的繁杂配置方式而采用@AspectJ注解对POJO进行标注,使AOP 的的工作大大简化,例如,在AspectJAudience类中,我们要做的就是在所有类的watch方法执行前在控制台中打印silenceCellPhone和takeSeat,而在所有类的watch方法执行后打印applause,同时又使用环绕的方式在所有类的watch方法执行前后再次分别打印Silencing cell phone和CLAP CLAP CLAP。

@Aspect
public class AspectJAudience {
/**
* 定义一个公共的切点
*/
@Pointcut("execution(* *.watch(..))")
public void watch() { } /**
* 目标方法执行之前调用
*/
@Before("watch()")
public void silenceCellPhone() {
System.out.println("Silencing cell phone");
} /**
* 目标方法执行之前调用
*/
@Before("watch()")
public void takeSeat() {
System.out.println("Taking seat");
} /**
* 目标方法执行完后调用
*/
@AfterReturning("watch()")
public void applause() {
System.out.println("CLAP CLAP CLAP");
} /**
* 目标方法发生异常时调用
*/
@AfterThrowing("watch()")
public void demandRefund() {
System.out.println("Demanding a refund");
} /**
* 环绕通知
* @param p 通过它调用目标方法
*/
@Around("watch()")
public Object aroundWatch(ProceedingJoinPoint p) {
Object o = null;
try {
System.out.println("Silencing cell phone");
o = p.proceed();
System.out.println("CLAP CLAP CLAP!!!");
} catch (Throwable e) {
System.out.println("Demanding a refund");
}
return o;
}
}

三、创建配置文件

XML是Spring的基础。尽管Spring—再简化配置,并且大有使用注解取代XML配置之势,但是无论如何,至少现在XML还是Spring的基础。要在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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <aop:aspectj-autoproxy/> <bean id="audience" class="org.cellphone.uc.aop.Audience"/>
<bean id="aspectJAudience" class="org.cellphone.uc.aop.AspectJAudience"/>
</beans>

四、测试

经过以上步骤后,便可以验证Spring的AOP为我们提供的神奇效果了。

public class AspectJMain {

    public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring/aop-test.xml");
Audience audience = (Audience) context.getBean("audience");
audience.watch();
}
}

不出意外,我们会看到控制台中打印了如下代码:

Silencing cell phone
Silencing cell phone
Taking seat
Watch movie
CLAP CLAP CLAP!!!
CLAP CLAP CLAP

Spring实现了对所有类的watch方法进行增强,使辅助功能可以独立于核心业务之外,方便 与程序的扩展和解耦。

那么,Spring究竞是如何实现AOP的呢?首先我们知道,Spring是否支持注解的AOP是由一个配置文件控制的,也就是<aop:aspectj-autoproxy/>,当在配置文件中声明了这句配置的时候,Spring就会支持注解的AOP,那么我们的分析就从这句注解开始。

Spring AOP源码分析(一)使用示例的更多相关文章

  1. spring AOP源码分析(三)

    在上一篇文章 spring AOP源码分析(二)中,我们已经知道如何生成一个代理对象了,那么当代理对象调用代理方法时,增强行为也就是拦截器是如何发挥作用的呢?接下来我们将介绍JDK动态代理和cglib ...

  2. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  3. Spring AOP 源码分析 - 创建代理对象

    1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...

  4. Spring AOP 源码分析 - 筛选合适的通知器

    1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析.本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出 ...

  5. Spring AOP 源码分析系列文章导读

    1. 简介 前一段时间,我学习了 Spring IOC 容器方面的源码,并写了数篇文章对此进行讲解.在写完 Spring IOC 容器源码分析系列文章中的最后一篇后,没敢懈怠,趁热打铁,花了3天时间阅 ...

  6. Spring AOP源码分析(三):基于JDK动态代理和CGLIB创建代理对象的实现原理

    AOP代理对象的创建 AOP相关的代理对象的创建主要在applyBeanPostProcessorsBeforeInstantiation方法实现: protected Object applyBea ...

  7. 5.2 Spring5源码--Spring AOP源码分析二

    目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...

  8. 5.2 spring5源码--spring AOP源码分析二--切面的配置方式

    目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...

  9. spring aop 源码分析(三) @Scope注解创建代理对象

    一.源码环境的搭建: @Component @Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON,proxyMode = ScopedP ...

  10. 最简 Spring AOP 源码分析!

    前言 最近在研究 Spring 源码,Spring 最核心的功能就是 IOC 容器和 AOP.本文定位是以最简的方式,分析 Spring AOP 源码. 基本概念 上面的思维导图能够概括了 Sprin ...

随机推荐

  1. sql判断某个字段是否为空

    判断sql某个字段是否为NULL public function dataNull($id){ $sql = 'SELECT * FROM `vvt_company_funcs_user` WHERE ...

  2. .net开发环境搭建

    本地开发环境下载网址:https://msdn.itellyou.cn/,选择个人免费版本 下载工具 下载安装win7系统选择asp.net 和web开发,右侧可选全部选择,大约11GB左右

  3. Vue 实现复制到粘贴板功能

    vue 实现复制到粘贴板功能需要依赖到 clipboard.js 1. 首先需要安装依赖  * 出现错误的话,可以试试 cnpm npm install --save vue-clipboard2 2 ...

  4. $.extend 的相关用法

    1.1 $.extend(result,item1,item2…..) 将所有的参数项都合并result中,返回result,会破坏result的结构. 1.2 $.extend({},item1,i ...

  5. Java实验案例(接口)

    实验任务 任务一:设计实现发声接口 任务二:动物乐园 实验内容 任务一:设计实现发声接口 任务目的: 理解并掌握如何定义接口 掌握接口的实现方式 任务描述: 设计和实现一个Soundable接口,该接 ...

  6. maven 生命周期、生命周期阶段、插件、目标

    生命周期maven的生命周期是抽象的,它本身不做任何实际的工作.实际的工作都由插件来完成.生命周期好比接口,插件好比实现类.maven 有三个独立的生命周期,clean.default.site. 生 ...

  7. 前端构建工具 Gulp.js 上手实例

    在软件开发中使用自动化构建工具的好处是显而易见的.通过工具自动化运行大量单调乏味.重复性的任务,比如图像压缩.文件合并.代码压缩.单元测试等等,可以为开发者节约大量的时间,使我们能够专注于真正重要的. ...

  8. nginx 的socket 选项处理--TCP_DEFER_ACCEPT

    在nginx listen配置项的说明中有一个选项: deferred -- indicates to use that postponed accept(2) on Linux with. the ...

  9. Git使用本地仓库之基本操作

    1.Git是什么? 一个分布式版本控制系统,和SVN类似,但远比SVN强大的一个版本控制系统 ①Git可以方便的在本地进行版本管理,如同你本地有一个版本管理服务器一样我们可以选择在合适的时间将本地版本 ...

  10. phpcas 整合 ecms的问题

    如果有ecms整合phpCAS经验的小伙伴可以给我留言,有偿付费 需求是:ecms登录自动跳转到CAS认证(已完成),认证后直接跳转到帝国cms系统中,并保持帝国cms系统权限等都和以前一样 正常使用 ...