Spring的第三天AOP之xml版

ssm框架 spring 

AOP介绍

AOP(Aspect Oriented Programming),面向切面编程。它出来的目的并不是去取代oop,而是对它的完善和补充。在oop中,人们的是去定义纵向的关系,但是会出现一个问题:在程序中,日志代码往往是横向的地散布在各种对象层次中,而在oop的模式设计中,导致了大量重复工作的代码。

可以这样说:oop是面向名词领域,AOP是面向动词领域。AOP适合通用的工作,不适合个性化的工作。

图来自网络,侵删

 

在AOP中,我们将那些与多个类相关的行为放在一起变成一个模块,命名为Aspect【切面】。讲个故事:

村里来了一个通告,以前是到每家每户去通知,假如通告进行了改变,又要重新进行通知,然后村里面的人觉得太麻烦了,就做了一个声音传输管道,每当有通告来的时候,村长就选择要通知的,告诉他们某个时间去做通告里面的东西,然后打开管道进行通知。

  • 通告:通知(Advice)

    就是你想要的东西,比如说日志,事物。

  • 人:PointCut【切入点】

    切入点里面定义了Advice发生的地点,例如某个类或方法的名称,为被切的地方。

  • 时间:Joinpoint【连接点】

    连接点就是告诉程序什么时候去使用通知,例如当方法被调用时,或者是异常抛出时。

  • 村长:Proxy【代理】
    Proxy不能算是AOP的家庭成员,它是一个管理部门,管理AOP如何融入OOP,是AOP的实践者。同时AOP的代理离不开spring的IOC容器。在Spring Framework中,AOP代理是JDK动态代理或CGLIB代理。

那么什么是切面呢?
切面其实就是Advice+PointCut,代表了切面的所有元素,而将切面织入代码中就是依靠Proxy

maven依赖

导入Spring依赖和aop依赖

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.8.RELEASE</version>
<type>pom</type>
</dependency> <dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>

头部文件xmlns文件配置

<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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> </beans>

类的java代码

package com.weno.pojo;

public class User {
public void print(){
System.out.println("我这是在执行一个方法");
throw new RuntimeException("我故意的报错");
} public String msg(){
return "竟然有返回值";
}
}

建议类:

package com.weno.aop;

    public void beforeMethod(){
System.out.println("一千年以前");
} public void afterMethod(){
System.out.println("一千年以后");
} public void returnMethod(Object rvt){
System.out.println("返回值>>>>>>"+rvt);
System.out.println("方法返回");
} public void errorMethod(){
System.out.println("程序竟然报错了");
}
}

xml版本的使用

首先先说一下切入点,切入点分为:

  • 前置通知:在连接点之前运行但无法阻止执行流程进入连接点的建议(除非它引发异常,该异常将中断当前方法链的执行而返回)。

  • 后置通知:在连接点正常完成后运行的建议(例如,如果方法返回而不抛出异常)。

  • 异常通知:如果方法通过抛出异常退出,则执行建议。

  • 后置最终通知:无论连接点退出的方式(正常或异常返回),都要执行建议。

  • 环绕通知:环绕在连接点处的方法所执行的通知,环绕通知可以在方法调用之前和之后自定义任何行为,并且可以决定是否执行连接点处的方法、替换返回值、抛出异常等等。环绕通知还需要负责决定是继续处理join point(调用ProceedingJoinPoint的proceed方法)还是中断执行。

前置通知,后置通知,异常通知,返回通知

<bean class="com.weno.pojo.User" id="user"/>
<bean class="com.weno.aop.Method" id="method"/> <aop:config>
<!--定义一个切面-->
<aop:aspect ref="method"> <!--切点,定义切点的id exexution后面写要切入的地点:在print这个方法进行切-->
<aop:pointcut id="positon" expression="execution(* com.weno.pojo.User.print())"/>
<!-- 切的时间 method表示切的方法 -->
<!-- beforeMethod 在执行方法之前切入 -->
<aop:before method="beforeMethod" pointcut-ref="positon"/>
<!-- 在执行方法之后切入 -->
<aop:after method="afterMethod" pointcut-ref="positon"/>
<!-- 在方法报错的时候切入 -->
<aop:after-throwing method="errorMethod" pointcut-ref="positon"/>
<!-- 在方法有返回值的时候切
同时可以加上returning,将值传给returnMethod()方法
-->
<aop:after-returning method="returnMethod" returning="rvt" pointcut="execution(* com.weno.pojo.User.msg())"/>
</aop:aspect>
</aop:config>

测试代码一:

@Test
public void m01(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/spring-test1.xml");
// 在这里,如果直接通过new实例化User,那么aop功能将失效,因为AOP是要在spring IOC容器里面实现的
User user = ctx.getBean("user",User.class);
user.print();
}

输出结果

一千年以前
我这是在执行一个方法
一千年以后
程序竟然报错了

测试代码二:

@Test
public void m03(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/spring-test1.xml");
User user = ctx.getBean("user",User.class);
user.msg();
}

结果:

返回值>>>>>>竟然有返回值
方法返回

环绕通知

环绕通知是所有通知类型中功能中最为强大的,能够全面地控制连接点,甚至能够控制方法是否执行,同时,他还可以实现before和after的功能。

切面程序的代码

public void aroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

    //允许程序进行执行
proceedingJoinPoint.proceed();
} public void aroundMethod2(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//允许程序进行执行,并将其参数进行改变。
proceedingJoinPoint.proceed(new String[]{"你最帅"});
}

被切的程序

public void msg1(){
System.out.println("这是米有参数的msg");
} public void msg2(String msg){
System.out.println("进行执行方法输出"+msg);
}

xml文件配置

<aop:around method="aroundMethod" pointcut="execution(* com.weno.pojo.User.msg1())"/>
<aop:around method="aroundMethod2" pointcut="execution(* com.weno.pojo.User.msg2(..))"/>

测试文件


@Test
public void m04() { ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/spring-test1.xml");
User user = ctx.getBean("user", User.class); user.msg1();
user.msg2("我好帅");
}

结果

这是米有参数的msg
//在这里面,参数进行了改变,由我好帅变成了你最帅
进行执行方法输出你最帅

JoinPoint的神奇之处

官方文档

这个是官方文档截取过来的

使用上面的那个例子来获得参数:

public void aroundMethod2(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object[] args = proceedingJoinPoint.getArgs();
System.out.println(Arrays.toString(args));
//允许程序进行执行,并将其参数进行改变。
proceedingJoinPoint.proceed(new String[]{"你最帅"});
}

输出结果当然是:

这是米有参数的msg
[我好帅]
进行执行方法输出你最帅

当然,如果你将Object[] args = proceedingJoinPoint.getArgs(); System.out.println(Arrays.toString(args));放在后面,那输出参数当然就变成了[你最帅]。

基本数据类型和包装类对于execution严格区分

首先先简单的介绍一下execution,先定义一个表达式:

execution(* com.weno...(..))

在这里面

标识符 含义
execution 表达式的主体
第一‘*’号 表示返回值的类型,*号代表任意类型
com.weno 代表包,被切的地方
包后面的‘..’ 代表当前包及其子包
第二个‘*’号 代表类,*号代表所有类
第三个‘*’号 代表方法,‘*’代表任意方法
(..) 括号里面表示参数,两个点表示任意参数,也可以不加

在execution表达式中,参数严格区分基本数据类型和包装类。例如:

在com.weno.pojo.User.hasAge()中

public void hasAge(Integer age){
}
<!-- 这样是可以切到的 -->
<aop:before method="beforeAge" pointcut="execution(* com.weno.pojo.User.hasAge(Integer))"/> <!-- 加入将Integer换成int,那么,无法执行切面 -->
<aop:before method="beforeAge" pointcut="execution(* com.weno.pojo.User.hasAge(int))"/>

好了,Spring的第三天就到这里了。明天就星期六了,IG加油(ง •_•)ง

 

在下一篇博客中,我将介绍一下aop注解版的使用

 

Spring的第三天AOP之xml版的更多相关文章

  1. Spring的第四天AOP之注解版

    Spring的第四天AOP之注解版 ssm框架 spring  在上一篇博客中,介绍了Spring的AOP的xml版本的使用,在这篇博客中,我将介绍一下,注解版的使用. 常用注解 注解 通知 @Aft ...

  2. 深入学习Spring框架(三)- AOP面向切面

    1.什么是AOP? AOP为 Aspect Oriented Programming 的缩写,即面向切面编程, 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术..AOP是OOP的延续, ...

  3. Spring入门(三)— AOP注解、jdbc模板、事务

    一.AOP注解开发 导入jar包 aop联盟包. aspectJ实现包 . spring-aop-xxx.jar . spring-aspect-xxx.jar 导入约束 aop约束 托管扩展类和被扩 ...

  4. Spring 学习(三)AOP

    (1)AOP概述 - AOP:面向切面编程,扩展功能不修改源代码实现 - AOP采取横向抽取机制,取代了传统的纵向继承体系重复性代码 (2)AOP底层原理 原始方法------->纵向继承体系 ...

  5. spring源码 — 三、AOP代理生成

    AOP代理生成 AOP就是面向切面编程,主要作用就是抽取公共代码,无侵入的增强现有类的功能.从一个简单的spring AOP配置开始: <?xml version="1.0" ...

  6. Spring框架第三篇之基于XML的DI注入

    一.注入分类 Bean实例在调用无参构造器创建空值对象后,就要对Bean对象的属性进行初始化.初始化是由容器自动完成的,称为注入.根据注入方式的不同,常用的有两类:设值注入.构造注入.实现特定接口注入 ...

  7. Spring入门(三)——AOP

    1. AOP aspect object programming ,简单来说就是把重复的代码抽取出来,然后再需要用到的地方进行切入,这里讲解基于接口的注解实现 2. 了解 关注点:即重复的代码 切面: ...

  8. Spring Boot2 系列教程 (十三) | 整合 MyBatis (XML 版)

    前言 如题,今天介绍 SpringBoot 与 Mybatis 的整合以及 Mybatis 的使用,之前介绍过了 SpringBoot 整合MyBatis 注解版的使用,上一篇介绍过 MyBatis ...

  9. Spring (五):AOP

    本文是按照狂神说的教学视频学习的笔记,强力推荐,教学深入浅出一遍就懂!b站搜索狂神说或点击下面链接 https://space.bilibili.com/95256449?spm_id_from=33 ...

随机推荐

  1. Maven学习 三 Maven与Eclipse结合使用

    一检查是否已经集成了Maven 现在的Eclipse一般都是集成了Maven,如果确定集成开发工具是否集成了Maven, Windows->preferences->Maven,查看是否已 ...

  2. 阿里巴巴Java开发规约插件安装使用指南

    编码规范插件安装使用指南 阿里技术公众号于今年的2月9日首次公布<阿里巴巴Java开发规约>,瞬间引起全民代码规范的热潮,后又发布了PDF的终极版,大家踊跃留言,期待配套的静态扫描工具开放 ...

  3. The current state of generics in Delphi( 转载)

    The current state of generics in Delphi   To avoid duplication of generated code, the compiler build ...

  4. springsecurity 源码解读之 SecurityContext

    在springsecurity 中,我们一般可以通过代码: SecurityContext securityContext = SecurityContextHolder.getContext(); ...

  5. C++ MFC棋牌类小游戏day4

    根据昨天的计划,今天开始做下面的内容. 1.鼠标点击事件 2.点击坐标进行处理.(坐标转换) 3.判断选中的位置是否有效. 4.确定选中的棋子,设置棋子的状态和棋子所在坐标的状态. 5.判断移动是否有 ...

  6. Programming | 中/ 英文词频统计(MATLAB实现)

    一.英文词频统计 英文词频统计很简单,只需借助split断句,再统计即可. 完整MATLAB代码: function wordcount %思路:中文词频统计涉及到对"词语"的判断 ...

  7. leetcode 315. Count of Smaller Numbers After Self 两种思路

    说来惭愧,已经四个月没有切 leetcode 上的题目了. 虽然工作中很少(几乎)没有用到什么高级算法,数据结构,但是我一直坚信 "任何语言都会过时,只有数据结构和算法才能永恒". ...

  8. Android开发之Activity

    活动(Activity) 活动是最容易吸引用户的地方,它是一种可以包含用户界面的组件,主要用于和用户交互. FirstActivity 手动创建活动 新建一个project,不再选择empty act ...

  9. Docker构建文件

    构建文件 创建Dockerfile touch Dockerfile 编辑Dockerfile vim Dockerfile #基于java8版本构建 FROM java:8 #挂载日志目录 VOLU ...

  10. Docker环境安装与配置

    Docker 简介 Docker使用Go语言编写的 安装Docker推荐LInux内核在3.10上 在2.6内核下运行较卡(CentOS 7.X以上内核是3.10) Docker 安装 安装yum-u ...