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. redis的并发set

    1.Redis高并发的问题 Redis缓存的高性能有目共睹,应用的场景也是非常广泛,但是在高并发的场景下,也会出现问题:缓存击穿.缓存雪崩.缓存和数据一致性,以及今天要谈到的缓存并发竞争. 这里的并发 ...

  2. APIView 的请求生命周期

    目录 APIView 的请求生命周期 请求解析模块 响应渲染模块 序列化组件 Django 配置 """ 1)应用是否需要在INSTALLED_APPS中注册 在没有使用 ...

  3. Q12问题

    1.我知道公司对我的工作要求吗? 2.我有做好我的工作所需要的材料和设备吗? 3.在工作中,我每天都有机会做我最擅长做的事吗? 4.在过去的七天里,我因工作出色而受到表扬吗? 5.我觉得我的主管或同事 ...

  4. 前端学习笔记系列一:12 js中获取时间new date()的用法

    获取时间: 1  var myDate = new Date();//获取系统当前时间 获取特定格式的时间: 1 myDate.getYear(); //获取当前年份(2位) 2 myDate.get ...

  5. 说说我对SQL语句执行顺序的理解,以SQL Server为例

    有人说SQL语句难学,其实并不难!只要掌握了基本的语句执行顺序,用程序化的思维分析结构,再难的问题也会迎刃而解! 假设有如下表emp 现在要求 列出员工姓名(ename)中不含A的所有人按照部门编号( ...

  6. Python format语法

    a = {"name" : "alex","age":16} v = "my name is {name}, my age is ...

  7. 【LOJ2127】「HAOI2015」按位或

    题意 刚开始你有一个数字 \(0\),每一秒钟你会随机选择一个 \([0,2^n-1]\) 的数字,与你手上的数字进行或操作.选择数字 \(i\) 的概率是 \(p[i]\) . 问期望多少秒后,你手 ...

  8. Mysql8.0免安装包配置方法

    1. 官网下载mysql_8.0.12免安装包,解压到你存放的地方: https://www.jb51.net/softs/609101.html 2. 配置环境变量(把bin的文件夹弄进系统path ...

  9. python进阶强化学习

    最近学习了慕课的python进阶强化训练,将学习的内容记录到这里,同时也增加了很多相关知识. 主要分为以下九个模块: 基本使用 迭代器和生成器 字符串 文件IO操作 自定义类和类的继承 函数装饰器和类 ...

  10. 1_01_MSSQL课程_基础入门

    0. 课程安排: 课程共7天课,前两天SQL基础,后面三天Ado.Net ,最后两天数据库高级进阶学习. 1.数据库的概念 ->数据库就是数据仓库. ->DBMS:数据库管理系统.SQLS ...