一、AOP的配置(注解)

步骤一、导入jar包:

处理那5个jar包之外,还需要导入:

  • aopalliance
  • aspectjweaver
  • spring-aop
  • spring-aspects

步骤二、在配置文件中加入aop、context的命名空间

步骤三分为基于注解方式配置AOP和xml方式配置aop;

基于注解方式(本篇)

①在配置文件中加入如下配置;

1 <!-- 使AspjectJ注释起作用,自动匹配的类生成代理对象 -->
2 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

②把横切关注点的代码都加入到切面的类中,

③切面首先是一个IOC中的bean,即加@Conponent注释

④切面需要加入@Aspect注释

⑤在类中声明各种通知:

  • @Before:前置通知,在方法执行前执行;
  • @After:后置通知,在方法执行后执行
  • @AfterRunning:返回通知,在方法返回结果后执行

  • @Afterthrowing:异常通知之后

  • @Around:环绕通知

二、AOP常用通知:

  • @Before:前置通知,在方法执行前执行;
    @Before("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(int, int) )") // 作用于接口中的所有方法
public void beforeMethod(JoinPoint joinPoint) {
String method = joinPoint.getSignature().getName();// 方法的签名
List<Object> args = Arrays.asList(joinPoint.getArgs());// 方法的参数
System.out.println("the method " + method + " begins with" + args);
}
  • @After:后置通知,在方法执行后执行,在后置通知中,不能访问目标方法执行的结果,如果有异常也执行,通知在异常之前;
1     @After("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(int, int) )")
2 public void afterMethod(JoinPoint joinPoint) {
3 String method = joinPoint.getSignature().getName();
4 List<Object> args = Arrays.asList(joinPoint.getArgs());
5 System.out.println("the method " + method + " is end to " + args);
6 }
  • @AfterRunning:返回通知,在方法返回结果后执行,可以访问到返回值;

1     @AfterReturning(value = "execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.add(int, int) )", returning = "result")
2 public void afterReturn(JoinPoint joinPoint, Object result) {
3 String method = joinPoint.getSignature().getName();
4 System.out.println("the method " + method + " is end with " + result);
5 }
  • @Afterthrowing:异常通知之后,可以访问到异常,并且可以指定异常类型,只有符合该异常类型时才被执行

1     @AfterThrowing(value = "execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.add(int, int) )", throwing = "ex")
2 public void afterThrowing(JoinPoint joinPoint, Object ex) {
3 String method = joinPoint.getSignature().getName();
4 System.out.println("the method " + method + " occured exception: " + ex);
5 }
  • @Around:环绕通知;

    环绕通知类似动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行日志方法 且必须有返回值,返回值是目标方法的返回值

 1     @Around("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.add(int, int) )")
2 public Object aroundMethod(ProceedingJoinPoint point) {
3 Object result = null;
4 String method = point.getSignature().getName();
5 // 执行目标方法
6 try {
7 // 前置通知
8 System.out.println("the method " + method + " is begin with " + Arrays.asList(point.getArgs()));
9 result = point.proceed();
10 // 返回通知
11 System.out.println("the method " + method + " is end to " + result);
12 } catch (Throwable e) {
13 // TODO Auto-generated catch block
14 System.out.println("the method " + method + " occured exception: " + e);
15 throw new RuntimeException(e);
16 }
17 System.out.println("the method " + method + " ends");
18
19 return 100;
20 }

三、切点表达式

表达式

1 execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)

这里问号表示当前项可以有也可以没有,其中各项的语义如下:

  • modifiers-pattern:方法的可见性,如public,protected;
  • ret-type-pattern:方法的返回值类型,如int,void等;
  • declaring-type-pattern:方法所在类的全路径名,如com.spring.Aspect;
  • name-pattern:方法名类型,如buisinessService();
  • param-pattern:方法的参数类型,如java.lang.String;
  • throws-pattern:方法抛出的异常类型,如java.lang.Exception;

举例说明:

//    @Before("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.add(int, int) )")// 作用于接口中的add方法
// @Before("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(int, int) )") // 作用于接口中的所有方法 (所有方法是指public int类型的)
// @Before("execution(* ixiuming.spring.aop.impl.ArithmeticCaculator.*(int, int) )") // 第一个* 表示:任意修饰符和任意返回值,第二个*代码任意参数为(int,int)方法
// @Before("execution( public * ixiuming.spring.aop.impl.ArithmeticCaculator.*(..) )") // 第二个*代表任意方法;..代表任意个数的参数,即所有公有方法
// @Before("execution( public double ixiuming.spring.aop.impl.ArithmeticCaculator.*(double.) )") // 返回所有double的第一个参数为double的public的方法

@Pointcut

使用@Pointcut 来声明切入点表达式,后面的其他通知直接使用方法名来引用当前的切入点表达式;如下代码,前置通知使用了方法名为declareJoinPointExpress来引用切点表达式;

这样做的好处是,可以统一管理切点表达式;

 1     @Pointcut("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(..))")
2 public void declareJoinPointExpress() {
3
4 }
5
6 //声明该方法是一个前置通知:在目标方法之前执行
7 @Before("declareJoinPointExpress()")
8 public void beforeMethod(JoinPoint joinPoint) {
9 String method = joinPoint.getSignature().getName();
10 List<Object> args = Arrays.asList(joinPoint.getArgs());
11 System.out.println("the method " + method + " begins with" + args);
12 }

四、实例说明AOP配置:

以实现三(一)中的 为ArithmeticCaculator添加 各方法 执行前 和计算结果后的日志的AOP方案为实例;

步骤一、为ArithmeticCaculatorImpl类添加@Component 注解 来表示 该组件需要被sping容器管理

 1 package lixiuming.spring.aop.impl;
2
3 import org.springframework.stereotype.Component;
4
5 @Component
6 public class ArithmeticCaculatorImpl2 implements ArithmeticCaculator {
7
8 @Override
9 public int add(int i, int j) {
10 int result = i+j;
11 return result;
12 }
13
14 @Override
15 public int sub(int i, int j) {
16 int result = i-j;
17 return result;
18 }
19
20 @Override
21 public int mul(int i, int j) {
22 int result = i*j;
23 return result;
24 }
25
26 @Override
27 public int div(int i, int j) {
28 int result = i/j;
29 return result;
30 }
31
32 }

步骤二、需要添加一个切面:

关于切面声明的说明:

  • 切面需要放置在spring 容器中;所以首先需要一个@Component注解
  • 声明一个切面用注解 @Aspect;

为实现上述实例,需要添加一个前置通知和后置通知;前置通知即,在目标方法执行之前执行;后置通知,即在目标方法执行后执行,无论是否发生异常。

 1 package lixiuming.spring.aop.impl;
2
3 import java.util.Arrays;
4 import java.util.List;
5
6 import org.aspectj.lang.JoinPoint;
7 import org.aspectj.lang.annotation.After;
8 import org.aspectj.lang.annotation.Aspect;
9 import org.aspectj.lang.annotation.Before;
10 import org.springframework.stereotype.Component;
11
12 //把这个类声明为一个切面,需要把该类放入到IOC容器中,再声明为一个切面
13 @Aspect
14 @Component
15 public class LoggingAspect {
16 // 声明该方法是一个前置通知:在目标方法之前执行
18 @Before("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(int, int) )") // 作用于接口中的所有方法
22 public void beforeMethod(JoinPoint joinPoint) {
23 String method = joinPoint.getSignature().getName();// 方法的签名
24 List<Object> args = Arrays.asList(joinPoint.getArgs());// 方法的参数
25 System.out.println("the method " + method + " begins with" + args);
26 }
27
28 // 声明后置通知:在目标方法执行后(无论是否发生异常)执行的通知
29 // 在后置通知中,不能访问目标方法执行的结果,需要在返回通知里面访问
30 @After("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(int, int) )")
31 public void afterMethod(JoinPoint joinPoint) {
32 String method = joinPoint.getSignature().getName();
33 List<Object> args = Arrays.asList(joinPoint.getArgs());
34 System.out.println("the method " + method + " is end to " + args);
35 }
36
37 }

步骤三、配置文件:引入了context和aop的命名空间

 1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:aop="http://www.springframework.org/schema/aop"
5 xmlns:context="http://www.springframework.org/schema/context"
6 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
7 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
8 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
9
10 <context:component-scan base-package="lixiuming.spring.aop.impl"/>
11 <!-- 使AspjectJ注释起作用,自动匹配的类生成代理对象 -->
12 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
13 </beans>

使用main方法测试:

 1 public static void main(String[] args) {
2 ApplicationContext cxt = new ClassPathXmlApplicationContext("ApplicationContext.xml");
3 ArithmeticCaculator arithmeticCaculator = cxt.getBean(ArithmeticCaculator.class);
4
5 int result = arithmeticCaculator.add(1, 2);
6 System.out.println("-->" + result);
7
8 int result1 = arithmeticCaculator.div(4, 2);
9 System.out.println("-->" + result1);
10
11 int result2 = arithmeticCaculator.mul(4, 2);
12 System.out.println("-->" + result2);
13
14 int result3 = arithmeticCaculator.sub(4, 2);
15 System.out.println("-->" + result3);
16
17 }

测试运行结果:

the method add begins with[1, 2]

the method add is end to [1, 2]

-->3

the method div begins with[4, 2]

the method div is end to [4, 2]

-->2

the method mul begins with[4, 2]

the method mul is end to [4, 2]

-->8

the method sub begins with[4, 2]

the method sub is end to [4, 2]

-->2

步骤二中除了使用前置和后置通知,还可以使用环绕通知来实现上述功能;

代码如下:

 1 package lixiuming.spring.aop.impl;
2
3 import java.util.Arrays;
4
5 import org.aspectj.lang.ProceedingJoinPoint;
6 import org.aspectj.lang.annotation.Around;
7 import org.aspectj.lang.annotation.Aspect;
8 import org.aspectj.lang.annotation.Pointcut;
9 import org.springframework.stereotype.Component;
10
11 //把这个类声明为一个切面,需要把该类放入到IOC容器中
12 @Aspect
13 @Component
14 public class LoggingAspect {
15
16 // 定义一个方法,用于声明切入点表达式,一般该方法中不需要其他的代码
17 // 使用@Pointcut 来声明切入点表达式,
18 // 后面的其他通知直接使用方法名来引用当前的切入点表达式
19 @Pointcut("execution(public int lixiuming.spring.aop.impl.ArithmeticCaculator.*(..))")
20 public void declareJoinPointExpress() {
21
22 }
23
24 /**
25 * 环绕通知需要携带ProceedingJoinPoint类型的参数
26 * 环绕通知类似动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行日志方法 且必须有返回值,返回值是目标方法的返回值
27 */
28 @Around("declareJoinPointExpress()")
29 public Object aroundMethod(ProceedingJoinPoint point) {
30 Object result = null;
31 String method = point.getSignature().getName();
32 // 执行目标方法
33 try {
34 // 前置通知
35 System.out.println("the method " + method + " is begin with " + Arrays.asList(point.getArgs()));
36 result = point.proceed();
37 // 后置通知
38 System.out.println("the method " + method + " is end to " + Arrays.asList(point.getArgs()));
39 } catch (Throwable e) {
40 // TODO Auto-generated catch block
41 System.out.println("the method " + method + " occured exception: " + e);
42 throw new RuntimeException(e);
43 }
44
45 return result;
46 }
47 }

五、切面的优先级

使用@Order(index)指定执行顺序的优先级,index为数字,index越小,优先级越高;@Order位置为放置在@Aspect前面;代码如下:

@Order(1)//执行顺序的优先级
@Aspect
@Component
//验证通知
public class VlidationAspect {
@Before("LoggingAspect.declareJoinPointExpress()")
public void validationArgs(JoinPoint jointPoint){
System.out.println("-->validation:"+Arrays.asList(jointPoint.getArgs()));
} }

六、xml方式配置AOP

ArithmeticCaculator 不变;ArithmeticCaculatorImpl移除@Component;

LoggingAspect:

 1 package lixiuming.spring.aop.impl2;
2
3 import java.util.Arrays;
4 import java.util.List;
5
6 import org.aspectj.lang.JoinPoint;
7 import org.aspectj.lang.ProceedingJoinPoint;
8 import org.aspectj.lang.annotation.After;
9 import org.aspectj.lang.annotation.AfterReturning;
10 import org.aspectj.lang.annotation.AfterThrowing;
11 import org.aspectj.lang.annotation.Around;
12 import org.aspectj.lang.annotation.Aspect;
13 import org.aspectj.lang.annotation.Before;
14 import org.aspectj.lang.annotation.Pointcut;
15 import org.springframework.stereotype.Component;
16
17 public class LoggingAspect {
18
19 public void beforeMethod(JoinPoint joinPoint){
20 String method = joinPoint.getSignature().getName();
21 List<Object> args = Arrays.asList(joinPoint.getArgs());
22 System.out.println("the method "+method+" begins with"+args);
23 }
24
25 public void afterMethod(JoinPoint joinPoint){
26 String method = joinPoint.getSignature().getName();
27 List<Object> args = Arrays.asList(joinPoint.getArgs());
28 System.out.println("the method "+method+" is end to "+args);
29 }
30
31 /**
32 *在方法正常结束后执行的代码
33 *返回通知是可以访问到方法的返回值
34 */
35 public void afterReturn(JoinPoint joinPoint,Object result){
36 String method = joinPoint.getSignature().getName();
37 System.out.println("the method "+method+" is end with " +result);
38 }
39
40 public void afterThrowing(JoinPoint joinPoint,Object ex){
41 String method = joinPoint.getSignature().getName();
42 System.out.println("the method "+method+" occured exception: " + ex);
43 }
44
45 public Object aroundMethod(ProceedingJoinPoint point){
46 Object result = null;
47 String method = point.getSignature().getName();
48 //执行目标方法
49 try {
50 //前置通知
51 System.out.println("the method "+method+" is begin with "+Arrays.asList(point.getArgs()));
52 result = point.proceed();
53 //返回通知
54 System.out.println("the method "+method+" is end to "+ result);
55 } catch (Throwable e) {
56 // TODO Auto-generated catch block
57 System.out.println("the method "+method+" occured exception: " + e);
58 throw new RuntimeException(e);
59 }
60 System.out.println("the method "+method+" ends");
61
62 return 100;
63 }
64 }
VlidationAspect:
 1 package lixiuming.spring.aop.impl2;
2
3 import java.util.Arrays;
4
5 import org.aspectj.lang.JoinPoint;
6 import org.aspectj.lang.annotation.Aspect;
7 import org.aspectj.lang.annotation.Before;
8 import org.springframework.core.annotation.Order;
9 import org.springframework.stereotype.Component;
10 //验证通知
11 public class VlidationAspect {
12 public void validationArgs(JoinPoint jointPoint){
13 System.out.println("-->validation:"+Arrays.asList(jointPoint.getArgs()));
14 }
15
16
17 }

配置文件:

 1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:aop="http://www.springframework.org/schema/aop"
5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
6 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
7
8 <!-- 配置bean -->
9 <bean id="aop" class="lixiuming.spring.aop.impl2.ArithmeticCaculatorImpl2"></bean>
10 <!-- 配置切面的bean -->
11 <bean id="LoggingAspect" class="lixiuming.spring.aop.impl2.LoggingAspect"></bean>
12 <bean id="VlidationAspect" class="lixiuming.spring.aop.impl2.VlidationAspect"></bean>
13
14 <!-- 配置AOP -->
15 <aop:config>
16 <!-- 配置切面表达式 -->
17 <aop:pointcut expression="execution(* lixiuming.spring.aop.impl2.ArithmeticCaculator.*(int,int))" id="pointcut"/>
18 <!-- 配置切面及通知 -->
19 <aop:aspect ref="LoggingAspect" order="2">
20 <aop:before method="beforeMethod" pointcut-ref="pointcut"/>
21 <aop:after method="afterMethod" pointcut-ref="pointcut"/>
22 <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="ex"/>
23 <aop:after-returning method="afterReturn" pointcut-ref="pointcut" returning="result"/>
24 <aop:around method="aroundMethod" pointcut-ref="pointcut"/>
25 </aop:aspect>
26
27 <aop:aspect ref="VlidationAspect" order="1">
28 <aop:before method="validationArgs" pointcut-ref="pointcut"/>
29 </aop:aspect>
30 </aop:config>
31 </beans>

三(二)、AOP配置的更多相关文章

  1. Spring AOP编程(二)-AOP实现的三种方式

    AOP的实现有三种方式: l         aop底层将采用代理机制进行实现. l         接口 + 实现类 :spring采用 jdk 的动态代理Proxy. l         实现类: ...

  2. Linux的VMWare下Centos7的三种网络配置过程(网络二)

    Linux之VMWare下Centos7的三种网络配置过程 环境:虚拟软件:VMWare 14.0客户机:windows 10虚拟机:centos 7 VMware三种网络连接方式 Bridge(桥接 ...

  3. 框架源码系列九:依赖注入DI、三种Bean配置方式的注册和实例化过程

    一.依赖注入DI 学习目标1)搞清楚构造参数依赖注入的过程及类2)搞清楚注解方式的属性依赖注入在哪里完成的.学习思路1)思考我们手写时是如何做的2)读 spring 源码对比看它的实现3)Spring ...

  4. Spring的第三天AOP之xml版

    Spring的第三天AOP之xml版 ssm框架 spring  AOP介绍 AOP(Aspect Oriented Programming),面向切面编程.它出来的目的并不是去取代oop,而是对它的 ...

  5. Spring第三天——AOP注解实现与事务管理

    大致内容: aspectJ的aop操作(基于注解,对比day02配置操作)(会用) *jdbcTemplate操作(实现CRUD) *spring配置连接池 *spring事务管理 一.AspectJ ...

  6. Spring的AOP配置

    Spring的AOP配置 1.先写一个普通类: package com.spring.aop; public class Common {  public void execute(String us ...

  7. 从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn)

    从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://w ...

  8. ThinkPHP 3.2.3(二)配置

    一.配置格式 1.PHP数组定义 默认所有配置文件的定义格式均采用返回PHP数组的方式,配置参数不区分大小写. 如果使用二维数组来配置更多的信息,则二级参数配置区分大小写.格式为: //项目配置文件r ...

  9. Maven提高篇系列之(二)——配置Plugin到某个Phase(以Selenium集成测试为例)

    这是一个Maven提高篇的系列,包含有以下文章: Maven提高篇系列之(一)——多模块 vs 继承 Maven提高篇系列之(二)——配置Plugin到某个Phase(以Selenium集成测试为例) ...

随机推荐

  1. Linux服务器通用安全加固指南

    一.基本系统安全 1.保护引导过程(以Grub引导为例) 在 /etc/inittab 中添加 sp:S:respawn:/sbin/sulogin,以确保当切换到单用户模式时 运行级的配置要求输入  ...

  2. 《如何进行接口mock测试》

    前言: Mock通常是指:在测试一个对象时,我们构造一些假的对象来模拟与其交互.而这些Mock对象的行为是我们事先设定且符合预期.通过这些Mock对象来测试对象在正常逻辑,异常逻辑或压力情况下工作是否 ...

  3. python学习笔记(七)-函数

    函数 方法 功能说白了,函数就是把一堆代码组合到一起,变成一个整体.函数不调用不会被执行.作用在于提高代码的复用性.定义函数 def greet_user(): """关 ...

  4. 一文彻底掌握Apache Hudi异步Clustering部署

    1. 摘要 在之前的一篇博客中,我们介绍了Clustering(聚簇)的表服务来重新组织数据来提供更好的查询性能,而不用降低摄取速度,并且我们已经知道如何部署同步Clustering,本篇博客中,我们 ...

  5. kubeadm 命令简介

    kubeadm 命令 kubeadm init 启动一个kubernetes主节点 kubeadm join 启动一个kubernetes工作节点并加入到集群中 kubeadm upgrade 更新一 ...

  6. JSP页面属性

    一.JSP指令 <%@指令名属性名=属性值 %> page指令: 定义页面是如何解析 include指令: 静态包含 taglib指令: 在页面引入标签呢库. 1.page指令属性 imp ...

  7. 华为Awareness kit,您旅途路上的超智能管家

    前言 前段时间看了一部纪录片<中国游客在巴黎>,讲述了外国人眼中"中国式旅游":热衷景点打卡,沉迷拍照留念,无暇仔细欣赏:留足时间,买买买,不能枉此行.网友总结中国式旅 ...

  8. THUSC & 中考 & NOI 拉跨记

    THUSC 的拉胯记 时代比较久远了,可能有些事情记不清楚了. Day -\(\infty\) 本来说只有我.llsw.wxk过了审核,后来wy.lyc也搞了个体验营名额,于是和高二的一起集训. Da ...

  9. Oracle中常用的to_char用法详解

    Oracle函数to_char转化数字型指定小数点位数的用法 to_char,函数功能,就是将数值型或者日期型转化为字符型. 比如最简单的应用: -- 1.0123=>1.0123 SELECT ...

  10. mysql group by语句流程是怎么样的

    group by流程是怎么样的 注意点: select id%10 as m, count(*) as c from t1 group by m; group by是用于对数据进行分组,我们排序用到了 ...