摘要: 本文结合《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. HTML5 number类型文本框step属性的验证机制——张鑫旭

    我在下一盘很大的棋,本文只是其中的一个棋子. 需要提前知道的: 目前而言,对step雄起的浏览器为IE10+, Chrome以及Opera浏览器. 需要预先知道number类型input的一些基本知识 ...

  2. 导航栏布局时遇到的问题以及解决办法 css选择器优先级

    得到的导航栏效果 添加#menu ul li{width:30px;} 效果如图 将会使列表项和分隔区域的宽度同时改变因为id选择器的优先级高于类选择器,此时应该为列表项添加内联样式如图 才能得到如下 ...

  3. Eclipse 导入 Android studio Exception Ljava/lang/UnsatisfiedLinkEror

    android studio compile fileTree(dir: 'libs', include: ['*.jar']) 没有加载so文件 main 下加入 jniLibs---so文件即可 ...

  4. 【node】node的核心模块---http模块,http的服务器和客户端

    nodejs事件机制 ##### http服务器和客户端 node.js标准库提供了http模块,其中封装了一个高效的http服务器和一个简易的http客户端 HTTP服务器 1. http.crea ...

  5. xcrun: error: invalid active developer path (/Applications/Xcode.app/Contents/Developer)解决办法

    背景 mac下卸载了xcode,使用git等命令时就提示错误.invalid active path(Applications/Xcode.app/Contents/Developer),这种情况可以 ...

  6. linux 用户管理修改用户信息、密码状态、删除用户、退出登陆、切换用户

    修改用户信息usermoduseradd支持的选项usermod都支持passwd有两个选项-l(在密码串前面加了两个叹号),-u,usermod有两个选项:-L 临时锁定用户(Lock)(在密码串前 ...

  7. idea插件Lombok

    在spring boot 中,我们可以使用@Data标签,这样就不需要手动添加getter/setter方法了,但Idea会报错. 此时,我们需要安装Lombok插件,安装好插件后便可以解决这个问题. ...

  8. sql 中的注释

    1.单行注释 “-- ”  即:两个中滑线加一个空格 2.多行注释 "/* ... */" 示例: -- 单行注释 /* 多行注释*/ create table test(id i ...

  9. Django之模型注册

    接着上一篇:Django之创建项目 目的:一个空项目创建好了,我们在models.py中新增3张表并在admin界面中显示,并能操作它们. 示例models 编辑models.py # -*- cod ...

  10. UNIX高级环境编程(9)进程控制(Process Control)- fork,vfork,僵尸进程,wait和waitpid

    本章包含内容有: 创建新进程 程序执行(program execution) 进程终止(process termination) 进程的各种ID   1 进程标识符(Process Identifie ...