三(二)、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容器管理

三(二)、AOP配置三(二)、AOP配置
 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>
上一篇:e645. 处理键盘事件


下一篇:nagios监控linux设置