Spring 系列教程


面向切面编程(Aspect Oriented Programming/AOP)是Spring框架核心技术之一。

面向切面编程的主要作用是,在不修改源代码的情况下,可以给目标类打补丁,让其执行补丁中的代码。

例如,用户类中有个登录方法,现在需要加用户登录日志。使用AOP就不需要修改用户登录方法,只需把日志代码注入到用户登录方法前后,让其执行。日志代码就是“切面”,插入代码的地方(用户类的登录方法)就是“连接点”。

面向切面编程概念

先介绍一些AOP的概念

  • 切面(Aspect) - 一些横跨多个类的公共模块,如日志、安全、事务等。简单地说,日志模块就是一个切面。
  • 连接点(Joint Point) - 目标类中插入代码的地方。连接点可以是方法、异常、字段,连接点处的切面代码会在方法执行、异常抛出、字段修改时触发执行。
  • 建议(Advice) - 在连接点插入的实际代码(即切面的方法),有5种不同类型(后面介绍)。
  • 切点(Pointcut) - 定义了连接点的条件,一般通过正则表达式。例如,可以定义所有以loadUser开头的方法作为连接点,插入日志代码。

建议类型

  • before - 在方法之前运行建议(插入的代码)
  • after - 不管方法是否成功执行,在方法之后运行插入建议(插入的代码)
  • after-returning - 当方法执行成功,在方法之后运行建议(插入的代码)
  • after-throwing - 仅在方法抛出异常后运行建议(插入的代码)
  • around - 在方法被调用之前和之后运行建议(插入的代码)

实现

与Bean配置一样,切面也需要配置,然后由Spring容器加载。切面配置可以使用XML,或者使用“AspectJ”语法,“AspectJ”语法使用Java代码实现切面配置。

为更深理解AOP,下面实现一个日志切面的例子,例子使用XML配置。

User类

一个简单的用户类,是日志切面插入的目标类。用户类实现了几个不同的方法,这些方法会作为连接点。

User.java

public class User {
private Integer id;
private String name; public void setId(Integer id) {
this.id = id;
} public Integer getId() {
System.out.println("Id: " + id);
return id;
} public void setName(String name) {
this.name = name;
} public String getName() {
System.out.println("Name: " + name );
return name;
} public void printThrowException(){
System.out.println("Exception raised");
throw new IllegalArgumentException();
}
}

切面 - Logging

日志切面类,定义了要插入目标类执行的方法。

Logging.java

public class Logging {
public void beforeAdvice(){
System.out.println("Before Advice");
} public void afterAdvice(){
System.out.println("After Advice");
} public void afterReturningAdvice(Object retVal){
System.out.println("After Advice Executed Successfully ... Returning: " + retVal.toString() );
} public void AfterThrowingAdvice(IllegalArgumentException ex){
System.out.println("There has been an exception when executing the advice: " + ex.toString());
}
}

retVal是目标类连接点(方法)返回的值。例如,如果连接点是User类的getName()方法,该方法返回用户名称,那么retVal将被赋值用户名称。

配置

本例使用XML配置切面。

首先定义切面类的Bean,然后切面定义中引用该Bean。

切面定义中,会指明切点、插入的代码(建议),以及插入的代码怎么执行(建议类型)。

下面的示例定义了一个名为UserAllMethod的切点,使用expression="execution(* User.*(..))"匹配User类中的所有方法作为连接点。

如果想指定特定方法作为连接点,可使用execution(* User.getName(..))

**示例:beans.xml **

<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <aop:config>
<!-- Aspect -->
<aop:aspect id="loggingAspect" ref="logging"> <!-- Pointcut -->
<aop:pointcut id="UserAllMethods" expression="execution(* User.*(..))"/> <!-- Advice(s) -->
<aop:before pointcut-ref="UserAllMethods" method="beforeAdvice"/>
<aop:after pointcut-ref="UserAllMethods" method="afterAdvice"/>
<aop:after-returning pointcut-ref="UserAllMethods" returning="retVal" method="afterReturningAdvice"/>
<aop:after-throwing pointcut-ref="UserAllMethods" throwing="ex" method="AfterThrowingAdvice"/>
</aop:aspect>
</aop:config> <!-- The user bean -->
<bean id="user" class="User">
<property name="name" value="隔壁老王" />
<property name="id" value="99"/>
</bean> <!-- logging 切面定义 -->
<bean id="logging" class="Logging"/>
</beans>

确保已经添加了依赖的JAR包,我们使用Maven,pom.xml中添加依赖:

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>

测试切面

在main类中调用用户类的方法,查看切面是否被执行:

Test.java

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); User user = (User) context.getBean("user");
user.getName();
user.printThrowException();
}
}

Spring 面向切面编程(AOP)的更多相关文章

  1. Spring面向切面编程(AOP)

    1 spring容器中bean特性 Spring容器的javabean对象默认是单例的. 通过在xml文件中,配置可以使用某些对象为多列. Spring容器中的javabean对象默认是立即加载(立即 ...

  2. Spring面向切面编程(AOP,Aspect Oriented Programming)

    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程(也叫面向方面),可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. ...

  3. Spring面向切面编程(AOP)方式二

    使用注解进行实现:减少xml文件的配置. 1 建立切面类 不需要实现任何特定接口,按照需要自己定义通知. package org.guangsoft.utils; import java.util.D ...

  4. Spring面向切面编程AOP(around)实战

    spring aop的环绕通知around功能强大,我们这里就不细说,直接上代码,看着注释就能明白 需要的可以点击下载源码 1.如果使用注解的方式则需要先创建个注解类 package com.mb.a ...

  5. Spring学习手札(二)面向切面编程AOP

    AOP理解 Aspect Oriented Program面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. 但是,这种说法有些片面,因为在软件工程中,AOP的价值体现的并 ...

  6. Spring学习笔记:面向切面编程AOP(Aspect Oriented Programming)

    一.面向切面编程AOP 目标:让我们可以“专心做事”,避免繁杂重复的功能编码 原理:将复杂的需求分解出不同方面,将公共功能集中解决 *****所谓面向切面编程,是一种通过预编译方式和运行期动态代理实现 ...

  7. Spring框架学习笔记(2)——面向切面编程AOP

    介绍 概念 面向切面编程AOP与面向对象编程OOP有所不同,AOP不是对OOP的替换,而是对OOP的一种补充,AOP增强了OOP. 假设我们有几个业务代码,都调用了某个方法,按照OOP的思想,我们就会 ...

  8. Spring之控制反转——IoC、面向切面编程——AOP

      控制反转——IoC 提出IoC的目的 为了解决对象之间的耦合度过高的问题,提出了IoC理论,用来实现对象之间的解耦. 什么是IoC IoC是Inversion of Control的缩写,译为控制 ...

  9. 04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI&&08.面向切面编程 AOP&&10.Spring中事务控制

    spring共四天 第一天:spring框架的概述以及spring中基于XML的IOC配置 第二天:spring中基于注解的IOC和ioc的案例 第三天:spring中的aop和基于XML以及注解的A ...

随机推荐

  1. Springboot 项目启动设置

    //配置默认访问路径 并且自动打开浏览器  需要创建独立文件 @Controller public class HomeController {     @RequestMapping("/ ...

  2. Spark调优(三) JVM调优

    调节Executor堆外内存 概述: Spark底层shuffle的传输方式是使用netty传输,netty在进行网络传输的过程会申请堆外 内存(netty是零拷贝),所以使用了堆外内存. 什么时候需 ...

  3. C# Show()与ShowDialog()的区别-----转载

    A.WinForm中窗体显示  显示窗体可以有以下2种方法:  Form.ShowDialog方法 (窗体显示为模式窗体)  Form.Show方法 (窗体显示为无模式窗体) 两者具体区别如下:  1 ...

  4. ajax 'Content-Type': 'multipart/form-data' ->文件上传

    'Content-Type': 'multipart/form-data' :指定传输数据为二进制数据,例如图片.mp3.文件

  5. LeetCode刷题--基础知识篇--KMP算法

    KMP算法 关于字符串匹配的算法,最知名的莫过于KMP算法了,尽管我们日常搬砖几乎不可能去亲手实现一个KMP算法,但作为一种算法学习的锻炼也是很好的,所以记录一下. KMP算法是根据三位作者(D.E. ...

  6. java web开发缓存方案,ehcache和redis哪个更好

    Ehcache在java项目广泛的使用.它是一个开源的.设计于提高在数据从RDBMS中取出来的高花费.高延迟采取的一种缓存方案.正因为Ehcache具有健壮性(基于java开发).被认证(具有apac ...

  7. 使用Vue 和 内网穿透:返回 invalid host header

    原因:新版的webpack-dev-server出于安全考虑,默认检查hostname,如果它不是配置内的,将会中断访问. -------------------------------------- ...

  8. python 中常见的异常类型汇总

    异常名称 描述 BaseException 所有异常的基类 SystemExit 解释器请求退出 KeyboardInterrupt 用户中断执行(通常是输入^C) Exception 常规错误的基类 ...

  9. MQTT 协议学习: QoS等级 与 会话

    背景 QoS 等级 与 通信的流程有关,直接影响了整个通信.而且篇幅比较长,所以我觉得应该单独拎出来讲一下. 概念 QoS 代表了 服务质量等级. 设置上,由2 位 的二进制控制,且值不允许为 3(0 ...

  10. 设备树DTS 学习:3-常用的DTS 函数

    Linux内核中目前DTS相关的函数都是以of_前缀开头的,它们的实现位于内核源码的drivers/of下面 void __iomem*of_iomap(struct device_node *nod ...