Spring AOP

面向切面(儿)编程(横切编程)

  1. Spring 核心功能之一

    • Spring 利用AspectJ 实现.
  2. 底层是利用 反射的动态代理机制实现的
  3. 其好处: 在不改变原有功能情况下, 为软件扩展(织入)横切功能

生活中的横切功能事例:

软件中的横切编程需求:

AOP其原理如下:

切面组件

是封装横切功能的Bean组件, 用于封装扩展功能方法.

AOP配置步骤

1.引入aspectj包

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>

2.创建切面组件对象:

@Component //将当前类纳入容器管理
@Aspect //Aspect 切面(儿), 声明当前的bean是
// 一个切面(儿)组件!
public class DemoAspect implements Serializable{
//@Before 在方法执行之前执行
//userService 的所有方法
@Before("bean(userService)")
public void test(){
System.out.println("Hello World!");
} }

3.配置AOP功能 resource/conf/spring-aop.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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">
<!-- 开启组件扫描 -->
<context:component-scan
base-package="cn.tedu.cloudnote.aop"/>
<!-- 开启aop, 底层使用aspectj -->
<aop:aspectj-autoproxy/> </beans>

spring-aop.xml

  1. 测试: 在登录功能执行期间, 登录功能被扩展了 Hello World!

注意: spring-aop.xml 的文件名必须符合 spring-*.xml 否则无法被加载 注意: Spring AOP 是利用 Aspectj AOP实现的, 在使用Spring AOP时候必须引入 Aspectj 的jar包.

如上代码的工作原理:

通知

是指: 切面方法的执行时机, 用于声明切面方法在被拦截方法之前或者之后执行

常用的有5个:

  1. @Before

    • 在被拦截方法之前执行
  2. @AfterReturning
    • 在方法正常执行以后执行
  3. @AfterThrowing
    • 在方法出现异常以后执行
  4. @After
    • 无论方法是否有异常都会执行
  5. @Around
    • 环绕方法执行

注意: 通知只表示执行时机, 不保证执行次序, @After经常在@AfterThrowing 之前出现.

通知原理:

案例:

@Component
@Aspect
public class TestAspect implements Serializable{
@Before("bean(userService)")
public void before() {
System.out.println("before()");
}
@AfterReturning("bean(userService)")
public void afterReturning(){
System.out.println("afterReturning");
}
@AfterThrowing("bean(userService)")
public void afterThrowing(){
System.out.println("afterThrowing");
}
@After("bean(userService)")
public void after(){
System.out.println("after");
} }

TestAspect.java

@Around 是环绕通知, 是万能的通知

Around 工作原理类似于 Servlet Filter 工作过程

原理:

案例:

@Component
@Aspect
public class AroundAspect
implements Serializable{
//环绕通知, test 方法将代理业务方法
//Object 返回代表业务方法的返回值
//Throwable 是业务方法执行期间的异常
@Around("bean(userService)")
public Object test(
ProceedingJoinPoint joinPoint)
throws Throwable{
System.out.println("执行业务之前!");
//调用业务方法
try{
//@Before
Object obj=joinPoint.proceed();
System.out.println("抓到:"+obj);
//@ArterReturning
return obj;
}catch(Throwable e){
//@AfterThrowing
throw e;
}finally{
System.out.println("执行业务之后!");
//@Arfter
}
}
}

AroundAspect.java

测试...

审计业务层方法的性能案例:

//性能审计 AOP
@Component
@Aspect
public class ProcAspect
implements Serializable{ @Around("execution(* cn.tedu.cloudnote.service.*Service.*(..))")
public Object test(
ProceedingJoinPoint joinPoint)
throws Throwable{
long t1 = System.nanoTime();
//调用业务方法
Object obj=joinPoint.proceed();
Signature s=joinPoint.getSignature();
//Signature 签名: 这里是方法签名(方法名+参数类型列表)
long t2 = System.nanoTime();
System.out.println(s+"执行时间:"+(t2-t1));
return obj;
}
}

ProcAspect.java

Signature 签名: 这里是方法签名(方法名+参数类型列表)

切入点

是指 切面组件的切入位置: 哪个类, 哪个对象, 哪个方法

  1. Bean组件切入点

    • 语法: bean(bean组件ID)
    • bean(userService)
    • bean(userService) || bean(bookService)
    • bean(*Service)
  2. within 类切入点:
    • 语法: within(类的全名)
    • within(cn.tedu.cloudnote.service.*Impl)
    • within(cn.tedu.cloudnote.service.UserServiceImpl)
    • within(cn.tedu.cloudnote..Impl)
  3. execution方法切入点 execution(执行)
    • 语法: execution(修饰词 方法全名(参数列表))
    • execution(* cn.tedu.cloudnote.service.UserService.login(..))
    • execution(* cn.tedu.cloudnote.service.UserService.*(..))
    • execution(* cn.tedu.cloudnote..Service.(..))

建议: 切入点位置有接口! 如果切入位置有接口 AspectJ 会利用JDK动态代理实现织入, 如果没有接口, 则使用CGLIB动态代理织入.

AOP ServletFilter 拦截器 区别

都是横切编程

  1. ServletFilter 是Servlet的标准, 适合于Web请求拦截
  2. 拦截器是SpringMVC提供的组件, 适合拦截处理SpringMVC请求流程
  3. AOP 是Spring 容器提供的功能, 适合拦截Spring容器中管理的Bean

根据拦截位置不同选择不同的拦截器编程方式.

事务编程

回顾编程式事务处理:

try{
打开连接
开始事务 事务操作1
事务操作2
事务操作3 提交事务
}catch(Exception e){
回滚事务
}fianlly{
回收资源,关闭连接
}

使用编程式事务处理, 代码冗长繁琐.

Spring利用AOP机制实现了声明式事务处理, 在业务代码中使用事务注解即可以处理事务, 不需要写复杂的事务处理代码!

声明式事务处理使用步骤:

1. 配置事务管理器 spring-mybatis.xml:

<!-- 配置事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dbcp"/>
</bean> <!-- 用于支持 @Transactional 注解 必须配置事务管理器属性, 其值是一个Bean的ID-->
<tx:annotation-driven transaction-manager="txManager"/>

2.在业务方法上使用 事务注解 UserServiceImpl.java:

@Transactional
public User login(String name, String password)
throws NameException, PasswordException {
//参数格式校验
if(name==null || name.trim().isEmpty()){
throw new NameException("用户名不能为空");
}
if(password==null || password.trim().isEmpty()){
throw new PasswordException("密码不能为空");
}
//密码检验
User user
=userDao.findUserByName(name);
if(user==null){
throw new NameException("用户名错误");
} //Thread t = Thread.currentThread();
//System.out.println(t); //String s = null;
//s.length(); String md5Password=NoteUtil.md5(password);
if(user.getPassword().equals(md5Password)){
return user;
}else{
throw new PasswordException("密码错误");
}
}

UserServiceImpl.java

注意: MySQL的MyISAM数据库引擎,不支持ACID(不能回滚), InnoDB 支持ACID

事务处理案例, 批量删除笔记:

原理:

步骤:

1.声明数据层方法 NoteDao.java:

int deleteNoteById2(String id);

2.添加SQL语句 NoteMapper.xml:

<delete id="deleteNoteById2"
parameterType="string">
delete from cn_note
where cn_note_id = #{id}
</delete>

3.添加业务层接口 NoteService.java:

int deleteNotes(String... ids);

4.实现业务层方法 NoteServiceImpl.java:

@Transactional
public int deleteNotes(String... ids) {
int n = 0;
for (String id : ids) {
int i=noteDao.deleteNoteById2(id);
if(i==0){
throw new RuntimeException(
"id是错误的"+id);
}
n+=i;
}
return n;
}

在业务方法出现异常时候, 会引起事务回滚.

5.测试 TesrNoteService.java:

@Test
public void testDeleteNotes(){
// 84b2d98b-af39-4655-8aa8-d8869d043cca
// c347f832-e2b2-4cb7-af6f-6710241bcdf6
// 07305c91-d9fa-420d-af09-c3ff209608ff
// 5565bda4-ddee-4f87-844e-2ba83aa4925f
String id1="84b2d98b-af39-4655-8aa8-d8869d043cca";
String id2="c347f832-e2b2-4cb7-af6f-6710241bcdf6";
String id3="07305c91-d9fa-420d-af09-c3ff209608ff";
String id4="5565bda4-ddee-4f87-844e-2ba83aa4925f";
noteService.deleteNotes(id1,id2,id3,id4);
}

测试结果: 发生异常时候回滚初始状态.

Filter图片 - 01:

Filter图片 - 02:


测试:

  1. 利用AOP实现性能测试功能, 输出每个业务层方法的执行耗费时间
  2. 为云笔记软件业务层添加事务, 并且测试出现异常时候是否发生回滚操作

02 - Unit011:Spring AOP的更多相关文章

  1. 转:Spring AOP中的动态代理

    原文链接:Spring AOP中的动态代理 0  前言 1  动态代理 1.1 JDK动态代理 1.2 CGLIB动态代理 1.2.1 CGLIB的代理用法 1.2.2 CGLIB的过滤功能 2  S ...

  2. spring AOP 之一:spring AOP功能介绍

    一.AOP简介 AOP:是一种面向切面的编程范式,是一种编程思想,旨在通过分离横切关注点,提高模块化,可以跨越对象关注点.Aop的典型应用即spring的事务机制,日志记录.利用AOP可以对业务逻辑的 ...

  3. Spring(二十):Spring AOP(四):基于配置文件的方式来配置 AOP

    基于配置文件的方式来配置 AOP 前边三个章节<Spring(十七):Spring AOP(一):简介>.<Spring(十八):Spring AOP(二):通知(前置.后置.返回. ...

  4. Spring(十九):Spring AOP(三):切面的优先级、重复使用切入点表达式

    背景: 1)指定切面优先级示例:有的时候需要对一个方法指定多个切面,而这多个切面有时又需要按照不同顺序执行,因此,切面执行优先级别指定功能就变得很实用. 2)重复使用切入点表达式:上一篇文章中,定义前 ...

  5. 转:Spring AOP详解

    转:Spring AOP详解 一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址: ...

  6. Spring入门(十):Spring AOP使用讲解

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

  7. Spring Boot 2.X(八):Spring AOP 实现简单的日志切面

    AOP 1.什么是 AOP ? AOP 的全称为 Aspect Oriented Programming,译为面向切面编程,是通过预编译方式和运行期动态代理实现核心业务逻辑之外的横切行为的统一维护的一 ...

  8. 转载:Spring AOP (下)

    昨天记录了Spring AOP学习的一部分(http://www.cnblogs.com/yanbincn/archive/2012/08/13/2635413.html),本来是想一口气梳理完的.但 ...

  9. 转载:Spring AOP (上)

    工 作忙,时间紧,不过事情再多,学习是必须的.记得以前的部门老大说过:“开发人员不可能一天到晚只有工作,肯定是需要自我学习.第一:为了更充实自己,保 持进步状态.第二:为了提升技术,提高开发能力.第三 ...

随机推荐

  1. FromBottomToTop第十二周项目博客

    FromBottomToTop第十二周项目博客 本周项目计划 设计整体架构,收集素材,制作出静态界面部分 项目进展 已完成游戏整体架构设计 已完成游戏界面.背景音乐等素材的收集 正在进行静态界面部分的 ...

  2. 基于ARM、linux的MF RC522射频读卡器

    摘要:本设计将ARM.linux的嵌入式技术与RFID技术相结合,对于实现移动支付终端的低功耗.便携式和网络化具有特别的意义.首先是采用MF RC522芯片设计与制作读写器,实现对Mifare卡的读写 ...

  3. ajax post data 获取不到数据,注意 content-type的设置 、post/get

    ajax post  data  获取不到数据,注意 content-type的设置 .post/get 关于 jQuery data 传递数据.网上各种获取不到数据,乱码之类的. 好吧今天我也遇到了 ...

  4. HDU 5934 Bomb(tarjan/SCC缩点)题解

    思路:建一个有向图,指向能引爆对象,把强连通分量缩成一点,只要点燃图中入度为0的点即可.因为入度为0没人能引爆,不为0可以由别人引爆. 思路很简单,但是早上写的一直错,改了半天了,推倒重来才过了... ...

  5. python应用-matplotlib绘图

    详细内容参看:官网 测试数据: # 传入的参数 x=[1,2,3,4,5] squares=[1,4,9,16,25] 简单的绘图 import matplotlib.pyplot as plt de ...

  6. http cookie的domain使用

    问题描述 最近遇到了一个因cookie domain设置不正确导致公司自研的分布式session组件无法生效的问题. 公司自研的这套分布式session组件依赖于设置在cookie中的sessionI ...

  7. mysql explain extended 查看 执行计划

    本文以转移至本人的个人博客,请多多关注! 本文以转移至本人的个人博客,请多多关注! 本文以转移至本人的个人博客,请多多关注! 本文以转移至本人的个人博客,请多多关注! 1. explain 可以查看 ...

  8. nodejs路由中:冒号

    路由必看的博客博客,也是学习node必看的博客:http://www.open-open.com/lib/view/open1409929982338.html 下面是一些路由例子,以及与之相匹配的关 ...

  9. jq对象和DOM对象的互换

    var oJq;  //JQ对象 var oDom; //dom对象 oDom = oJq[index];  // JQ对象转化为oDom对象 oJq  = $(oDom);      //DOM对象 ...

  10. hihocoder1513

    https://hihocoder.com/problemset/problem/1513 五维偏序问题,直接bitset压位,复杂度O(n^2/32) (本来想写三维偏序,但是cdq不会只好写写五维 ...