三(二)、AOP配置
一、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配置的更多相关文章
- Spring AOP编程(二)-AOP实现的三种方式
AOP的实现有三种方式: l aop底层将采用代理机制进行实现. l 接口 + 实现类 :spring采用 jdk 的动态代理Proxy. l 实现类: ...
- Linux的VMWare下Centos7的三种网络配置过程(网络二)
Linux之VMWare下Centos7的三种网络配置过程 环境:虚拟软件:VMWare 14.0客户机:windows 10虚拟机:centos 7 VMware三种网络连接方式 Bridge(桥接 ...
- 框架源码系列九:依赖注入DI、三种Bean配置方式的注册和实例化过程
一.依赖注入DI 学习目标1)搞清楚构造参数依赖注入的过程及类2)搞清楚注解方式的属性依赖注入在哪里完成的.学习思路1)思考我们手写时是如何做的2)读 spring 源码对比看它的实现3)Spring ...
- Spring的第三天AOP之xml版
Spring的第三天AOP之xml版 ssm框架 spring AOP介绍 AOP(Aspect Oriented Programming),面向切面编程.它出来的目的并不是去取代oop,而是对它的 ...
- Spring第三天——AOP注解实现与事务管理
大致内容: aspectJ的aop操作(基于注解,对比day02配置操作)(会用) *jdbcTemplate操作(实现CRUD) *spring配置连接池 *spring事务管理 一.AspectJ ...
- Spring的AOP配置
Spring的AOP配置 1.先写一个普通类: package com.spring.aop; public class Common { public void execute(String us ...
- 从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn)
从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://w ...
- ThinkPHP 3.2.3(二)配置
一.配置格式 1.PHP数组定义 默认所有配置文件的定义格式均采用返回PHP数组的方式,配置参数不区分大小写. 如果使用二维数组来配置更多的信息,则二级参数配置区分大小写.格式为: //项目配置文件r ...
- Maven提高篇系列之(二)——配置Plugin到某个Phase(以Selenium集成测试为例)
这是一个Maven提高篇的系列,包含有以下文章: Maven提高篇系列之(一)——多模块 vs 继承 Maven提高篇系列之(二)——配置Plugin到某个Phase(以Selenium集成测试为例) ...
随机推荐
- Java基础系列(8)- 数据类型
数据类型 强类型语言 要求变量的使用合乎规定,所有的变量都必须先定义才能使用.Java是强类型语言. 弱类型语言 变量定义比较随意,比如"12"+3,可以是int型123,也可以是 ...
- java eclipse 使用随笔
1,无法import java.awt. 等各种文件,解决办法:(在module-info.java文件中加入requires java,desktop这句话)
- VMware安装最新版CentOS7图文教程
https://blog.csdn.net/reticent_man/article/details/80732395 https://blog.csdn.net/q2158798/article/d ...
- TP框架中的一些登录代码分享
<?php namespace Admin\Controller;use Think\Controller;class LoginController extends Controller{ p ...
- P2012-拯救世界2【EGF】
正题 题目链接:https://www.luogu.com.cn/problem/P2012 题目大意 \(12\)种东西排列成长度为\(n\)的序列,要求前四种出现奇数次,后四种出现偶数次,求方案. ...
- Spring,IOC源码分析
有错勿喷 1.首先是Spring,IOC的基本概念 IOC是一个容器 容器启动的时候创建所有单实例对象 我们可以直接从容器中获取到这个对象 2.调试流程 ioc容器的启动过程?启动期间都做了什么(什么 ...
- NOIP 模拟一 考试总结
序列 考场上信心满满的打了nlogn的做法,我以为我稳了.据考试结束1h时发现看错题目了,打成了不连续的子序列.匆匆改了n2logn的做法.考试结束后,我发现我跪了.原来到终点才会发现我做的和人家不是 ...
- (googlechrome)未知错误导致安装失败,如果googlechrome....
https://jingyan.baidu.com/article/ea24bc39ffb699da63b33147.html#5827690-tsina-1-63512-fe183374908e7 ...
- CVPR2021提出的一些新数据集汇总
前言 在<论文创新的常见思路总结>(点击标题阅读)一文中,提到过一些新的数据集或者新方向比较容易出论文.因此纠结于选择课题方向的读者可以考虑以下几个新方向.文末附相关论文获取方式. ...
- Java(8)详解Random使用
作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201556.html 博客主页:https://www.cnblogs.com/testero ...