一、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. (转载)深入理解MDL元数据锁

    作者:MySQL技术本文为作者原创,转载请注明出处:https://www.cnblogs.com/kunjian/p/11993708.html 前言: 当你在MySQL中执行一条SQL时,语句并没 ...

  2. 如何理解 jmeter 的线程数与并发数之间的关系

    https://blog.csdn.net/weixin_39955351/article/details/110548162 多个线程组的并发是如何计算的?

  3. CF891E-Lust【EGF】

    正题 题目链接:https://www.luogu.com.cn/problem/CF891E 题目大意 \(n\)个数字的一个序列\(a_i\),每次随机选择一个让它减去一.然后贡献加上所有其他\( ...

  4. heoi2020树

    _ _01trie树合并 _ _ 在考场上一直想用数据结构维护,还花了好长时间算 $(a+1)^(b+1)$,现在看来当时好像在犯傻........ 异或有个神奇的工具是 01trie 树,此题就用此 ...

  5. mysql从零开始之MySQL LIKE 子句

    MySQL LIKE 子句 我们知道在 MySQL 中使用 SQL SELECT 命令来读取数据, 同时我们可以在 SELECT 语句中使用 WHERE 子句来获取指定的记录. WHERE 子句中可以 ...

  6. 从单体迈向 Serverless 的避坑指南

    作者 | 不瞋 导读:用户需求和云的发展两条线推动了云原生技术的兴起.发展和大规模应用.本文将主要讨论什么是云原生应用,构成云原生应用的要素是什么,什么是 Serverless 计算,以及 Serve ...

  7. The type name or alias SqlServer could not be resolved.Please check your configuration

    The type name or alias SqlServer could not be resolved.Please check your configuration file.... 检查一下 ...

  8. 沟谷网络的提取及沟壑密度的计算(ArcPy实现)

    一.背景 沟壑密度是描述地面被水道切割破碎程度的一个指标.沟壑密度是气候.地形.岩性.植被等因素综合影响的反映.沟壑密度越大,地面越破碎,平均坡度增大,地表物质稳定性降低,且易形成地表径流,土壤侵蚀加 ...

  9. luogu1081 开车旅行2012 D1T3 (倍增,set,O2)

    题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为Hi,城市 i ...

  10. centos无法建立ssl连接

    在centos下使用wget安装mysql5.7时,提示无法建立ssl连接 查阅资料,在命令wget后加上 --no-check-certificate也还是无法建立SSL连接. 后来,觉得可能是由于 ...