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. java 线程池简单例子

    package com.hra.riskprice; import com.hra.riskprice.SysEnum.Factor_Type; import com.hra.riskprice.po ...

  2. Python(五) 字典

  3. 去掉手机端延迟300ms

    手机端300ms延迟是由于在手机上可以双击可以放大缩小造成的,当初ios苹果的工程师们做了一些约定,应对 iPhone 这种小屏幕浏览桌面端站点的问题.这就是手机端300ms延迟的由来. 解决:我是用 ...

  4. c++WIN32获取syslistview行数

    #include "stdafx.h" #include <windows.h> #include <commctrl.h> #include <io ...

  5. Note | LaTeX

    目录 一.TeX家族 1. TeX - LaTeX 2. pdfTeX - pdfLaTeX 3. XeTeX - XeLaTeX 4. CTeX - MiKTeX - TeX Live 二.入门 1 ...

  6. Hadoop 系列文章(三) 配置部署启动YARN及在YARN上运行MapReduce程序

    这篇文章里我们将用配置 YARN,在 YARN 上运行 MapReduce. 1.修改 yarn-env.sh 环境变量里的 JAVA_HOME 路径 [bamboo@hadoop-senior ha ...

  7. JQuery下载及选择器总结

    JQuery下载 JQuery只是一个JS函数库,要使用其中的方法还是要在JS文件中进行调用. 一般去https://mvnrepository.com/这个网站下载,搜索JQuery就能找到JS文件 ...

  8. Ubuntu 16.04虚拟机调整窗口大小自适应Windows 7

    Windows 7上Ubuntu 16.04虚拟机安装成功后,默认的虚拟机窗口比较小,需要适当调整,才能把虚拟机的屏幕放大, 适合使用,以下介绍调整方法. 安装VMware Tools  启动虚拟机, ...

  9. jQuery应用实例4:下拉列表

    应用场景:左侧是已有商品,右侧是未有商品,选择其中的内容点击箭头即可互换: 点击大箭头则全部内容去另一边,或者双击已有商品的选项也会加入右边: 代码实现: <!DOCTYPE html> ...

  10. Java的组合排列问题

    从4个人中选2个人参加活动,一共有6种选法. 从n个人中选m个人参加活动,一共有多少种选法?C(m/n)=C((m-1)/(n-1))+C(m/(n-1))数学算法 public class Main ...