Spring学习--用 ASpectJ 注解实现 AOP

用 AspectJ 注解声明切面:

  • 要在 Spring 中声明 AspectJ 切面 , 只需要在 IOC 容器中将切面声明为 bean 实例。当在 Spring IOC 容器中初始化 AsjectJ 切面之后 , Spring IOC 容器就会为那些与 AspectJ 切面相匹配的 bean 创建代理。
  • 在 ApectJ 注解中 , 切面只是一个带有 @Asject 注解的 Java 类。
  • 通知是标注有某种注解的简单的 Java 方法。
  • AspectJ 支持 5 种类型的通知注解:
    1. @Before:前置通知 , 在方法执行之前执行。
    2. @After:后置通知 , 在方法执行之后执行。
    3. @AfterReturning:返回通知 , 在方法返回结果之后执行。
    4. @AfterThrowing:异常通知 , 在方法抛出异常之后。
    5. @Around:环绕通知 , 围绕着方法执行。

前置通知:

 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
 8        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
 9
10     <!-- IOC 扫描包 -->
11     <context:component-scan base-package="com.itdoc.spring.aop.impl"></context:component-scan>
12     <!-- 使 AspectJ 注解起作用, 自动为匹配的类生成代理对象 -->
13     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
14
15 </beans>

注意:一定要添加 aop 命名空间。

 1 package com.itdoc.spring.aop.impl;
 2
 3 import org.springframework.stereotype.Component;
 4
 5 /**
 6  * http://www.cnblogs.com/goodcheap
 7  *
 8  * @author: Wáng Chéng Dá
 9  * @create: 2017-03-03 19:34
10  */
11 @Component
12 public interface Arithmetic {
13
14     int add(int i, int j);
15
16     int sub(int i, int j);
17
18     int mul(int i, int j);
19
20     int div(int i, int j);
21
22 }
 1 package com.itdoc.spring.aop.impl;
 2
 3 import org.springframework.stereotype.Component;
 4
 5 /**
 6  * http://www.cnblogs.com/goodcheap
 7  *
 8  * @author: Wáng Chéng Dá
 9  * @create: 2017-03-03 19:35
10  */
11 @Component("arithmetic")
12 public class ArithmeticImpl implements Arithmetic {
13     @Override
14     public int add(int i, int j) {
15         int result = i + j;
16         return result;
17     }
18
19     @Override
20     public int sub(int i, int j) {
21         int result = i - j;
22         return result;
23     }
24
25     @Override
26     public int mul(int i, int j) {
27         int result = i * j;
28         return result;
29     }
30
31     @Override
32     public int div(int i, int j) {
33         int result = i / j;
34         return result;
35     }
36 }
 1 package com.itdoc.spring.aop.impl;
 2
 3
 4 import org.aspectj.lang.JoinPoint;
 5 import org.aspectj.lang.annotation.Aspect;
 6 import org.aspectj.lang.annotation.Before;
 7 import org.springframework.stereotype.Component;
 8
 9 import java.util.Arrays;
10
11 /**
12  * http://www.cnblogs.com/goodcheap
13  * 声明为一个切面的类: 需要把该类放到 IOC 容器中, 再声明为一个切面。
14  * @author: Wáng Chéng Dá
15  * @create: 2017-03-03 21:37
16  */
17 @Aspect
18 @Component
19 public class LoggingAspect {
20
21     //声明该方法为前置通知: 在目标方法执行之前开始执行。
22     @Before("execution(* com.itdoc.spring.aop.impl.*.*(..))")
23     public void beforeMethod(JoinPoint joinPoint) {
24         Object methodName = joinPoint.getSignature().getName();
25         Object args = Arrays.asList(joinPoint.getArgs());
26         System.out.println("The method " + methodName + " begins with " + args);
27     }
28 }

@Before("execution(* com.itdoc.spring.aop.impl.*.*(..))")

  • 第一颗 * :代表任意修饰符 , 任意返回值。
  • 第二颗 * :代表任意对象。
  • 第三颗 * :代表任意方法。
  • 最后的 .. :代表任意参数。

注意:在 AspectJ 中 , 切点表达式可以通过操作符 && , || , ! 结合起来。

 1 package com.itdoc.spring.aop.impl;
 2
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5
 6 /**
 7  * http://www.cnblogs.com/goodcheap
 8  *
 9  * @author: Wáng Chéng Dá
10  * @create: 2017-03-03 21:32
11  */
12 public class Main {
13
14     public static void main(String[] args) {
15
16         ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
17         Arithmetic arithmetic = (Arithmetic) ctx.getBean("arithmetic");
18         System.out.println("result = " + arithmetic.add(9, 5));
19         System.out.println("result = " + arithmetic.sub(9, 5));
20     }
21 }

控制台输出:


The method add begins with [9, 5]
result = 14
The method sub begins with [9, 5]
result = 4

后置通知:

  • 后置通知是在连接点完成之后执行的 , 即连接点返回结果或者抛出异常的时候。
  • 一个切面可以包括一个或者多个通知。
 1 package com.itdoc.spring.aop.impl;
 2
 3
 4 import org.aspectj.lang.JoinPoint;
 5 import org.aspectj.lang.annotation.After;
 6 import org.aspectj.lang.annotation.Aspect;
 7 import org.aspectj.lang.annotation.Before;
 8 import org.springframework.stereotype.Component;
 9
10 import java.util.Arrays;
11
12 /**
13  * http://www.cnblogs.com/goodcheap
14  * 声明为一个切面的类: 需要把该类放到 IOC 容器中, 再声明为一个切面。
15  * @author: Wáng Chéng Dá
16  * @create: 2017-03-03 21:37
17  */
18 @Aspect
19 @Component
20 public class LoggingAspect {
21
22     //声明该方法为前置通知: 在目标方法执行之前开始执行。
23     @Before("execution(* com.itdoc.spring.aop.impl.*.*(..))")
24     public void beforeMethod(JoinPoint joinPoint) {
25         Object methodName = joinPoint.getSignature().getName();
26         Object args = Arrays.asList(joinPoint.getArgs());
27         System.out.println("The method " + methodName + " begins with " + args);
28     }
29
30     //声明该方法为后置通知: 在目标方法执行之后(无论是否发生异常)开始执行。
31     @After("execution(* com.itdoc.spring.aop.impl.*.*(..))")
32     public void afterMethod(JoinPoint joinPoint) {
33         Object methodName = joinPoint.getSignature().getName();
34         Object args = Arrays.asList(joinPoint.getArgs());
35         System.out.println("The method " + methodName + " ends with " + args);
36     }
37 }
 1 package com.itdoc.spring.aop.impl;
 2
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5
 6 /**
 7  * http://www.cnblogs.com/goodcheap
 8  *
 9  * @author: Wáng Chéng Dá
10  * @create: 2017-03-03 21:32
11  */
12 public class Main {
13
14     public static void main(String[] args) {
15
16         ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
17         Arithmetic arithmetic = (Arithmetic) ctx.getBean("arithmetic");
18         System.out.println("result = " + arithmetic.add(9, 5));
19         System.out.println("result = " + arithmetic.div(9, 0));
20     }
21 }

控制台输出:


Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.itdoc.spring.aop.impl.ArithmeticImpl.div(ArithmeticImpl.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:43)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy8.div(Unknown Source)
at com.itdoc.spring.aop.impl.Main.main(Main.java:19)
The method add begins with [9, 5]
The method add ends with [9, 5]
result = 14
The method div begins with [9, 0]
The method div ends with [9, 0]

返回通知:

无论连接点是正常返回还是抛出异常 , 后置通知都会执行。如果只想在连接点返回的时候记录日志 , 应使用返回通知代替后置通知。

 1 package com.itdoc.spring.aop.circular;
 2
 3 import org.aspectj.lang.JoinPoint;
 4 import org.aspectj.lang.annotation.AfterReturning;
 5 import org.aspectj.lang.annotation.Aspect;
 6 import org.springframework.stereotype.Component;
 7
 8 /**
 9  * 通知
10  * http://www.cnblogs.com/goodcheap
11  *
12  * @author: Wáng Chéng Dá
13  * @create: 2017-03-04 9:50
14  */
15 @Aspect
16 @Component
17 public class AsjectLogging {
18
19     /**
20      * 在方法正常结束后执行代码。
21      * 返回通知是可以访问到方法的返回值的。
22      */
23     @AfterReturning(value = "execution(* com.itdoc.spring.aop.circular.*.*(..))", returning = "result")
24     public void afterReturning(JoinPoint joinPoint, Object result) {
25         Object methodName = joinPoint.getSignature().getName();
26         System.out.println("The method " + methodName + " ends with " + result);
27     }
28 }

异常通知:

 1 package com.itdoc.spring.aop.circular;
 2
 3 import org.aspectj.lang.JoinPoint;
 4 import org.aspectj.lang.annotation.AfterReturning;
 5 import org.aspectj.lang.annotation.AfterThrowing;
 6 import org.aspectj.lang.annotation.Aspect;
 7 import org.springframework.stereotype.Component;
 8
 9 /**
10  * 通知
11  * http://www.cnblogs.com/goodcheap
12  *
13  * @author: Wáng Chéng Dá
14  * @create: 2017-03-04 9:50
15  */
16 @Aspect
17 @Component
18 public class AsjectLogging {
19
20     /**
21      * 在目标方法出现异常时候执行的代码。
22      * 可以访问到异常对象, 且可以指定在出现特定异常时再执行的代码。
23      */
24     @AfterThrowing(value = "execution(* com.itdoc.spring.aop.circular.*.*(..))", throwing = "e")
25     public void afterThrowing(JoinPoint joinPoint, Exception e) {
26         Object methodName = joinPoint.getSignature().getName();
27         System.out.println("The method " + methodName + " exception with " + e);
28     }
29 }

环绕通知:

 1 package com.itdoc.spring.aop.circular;
 2
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 import org.aspectj.lang.annotation.Around;
 5 import org.aspectj.lang.annotation.Aspect;
 6 import org.springframework.stereotype.Component;
 7
 8 import java.util.Arrays;
 9
10 /**
11  * 通知
12  * http://www.cnblogs.com/goodcheap
13  *
14  * @author: Wáng Chéng Dá
15  * @create: 2017-03-04 9:50
16  */
17 @Aspect
18 @Component
19 public class AsjectLogging {
20
21     /**
22      * 环绕通知需携带 ProceedingJoinPoint 类型的参数。
23      * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型参数可以决定是否执行目标方法。
24      * 环绕通知必须有返回值, 返回值即目标方法的返回值。
25      *
26      * @param point
27      * @return
28      */
29     @Around("execution(* com.itdoc.spring.aop.circular.*.*(..))")
30     public Object around(ProceedingJoinPoint point) {
31         Object methodName = point.getSignature().getName();
32         Object[] args = point.getArgs();
33         Object result = null;
34         try {
35             //前置通知
36             System.out.println("The method " + methodName + " begins with" + Arrays.asList(args));
37             //执行方法
38             result = point.proceed();
39             //返回通知
40             System.out.println("The method " + methodName + " ends with " + result);
41         } catch (Throwable e) {
42             e.printStackTrace();
43             //异常通知
44             System.out.println("The method " + methodName + " exception with " + e);
45         } finally {
46             //后置通知
47             System.out.println("The method " + methodName + " ends");
48         }
49         return result;
50     }
51 }
时间: 2024-10-13 07:42:58

Spring学习--用 ASpectJ 注解实现 AOP的相关文章

spring学习2:基于注解+xml实现ioc和依赖注入

spring学习2:基于注解+xml实现ioc和依赖注入 一.在spring配置文件中开启spring对注解的支持 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&qu

spring学习之aspectj的注解aop

基于aspectj的注解aop 1 使用注解方式实现aop操作 第一步 创建对象 第二步 在spring核心配置文件中,开启aop配置 第三步 在增强类上面使用注解完成aop操作 原文地址:https://www.cnblogs.com/czsy/p/10390181.html

spring学习笔记——面向切面编程AOP二

上一篇介绍了一些概念,这篇我们开始进行编写代码. 1.编写切点: 如图所示的切点表达式表示当Instrument的play()方法执行时会触发通知.方法表达式以*号开始,标识了我们不关心方法返回值的类型.然后,我们指定了全限定类名和方法名.对于参数列表,我们使用(..)标识切点选择任意的play()方法,无论该方法的入参是什么.当我们需要配置切点仅匹配com.springinaction.springidol包,可以使用within()指示器来限制匹配. 除此之外,spring 2.5还引入一个

spring学习笔记——面向切面编程AOP一

1.基本术语: 横切关注点:分布于应用中多处的功能被称为横切关注点,比如日志.安全.事务管理 切面:横切关注点可以被模块化为特殊的类,这些类被称为切面 通知:spring切面可以应用5种类型的通知 a.Before——在方法被调用之前调用通知 b.After——在方法完成之后调用通知,无论方法执行是否成功 c.After-returning——在方法成功执行之后调用通知 d.After-throwing——在方法抛出异常后调用通知 f.Around——通知包裹了被通知的方法,在被通知的方法调用之

Spring学习8-Spring事务管理(AOP/声明式式事务管理)

一.基础知识普及 声明式事务的事务属性: 一:传播行为 二:隔离级别 三:只读提示 四:事务超时间隔 五:异常:指定除去RuntimeException其他回滚异常.  传播行为: 所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为. spring的事务传播规则: 传播行为 意义 PROPAGATION_REQUIRED 如果当前存在事务,则加入该事务:如果当前没有事务,则创建一个新的事务. PROPAGATION_REQUIR

Spring学习4-面向切面(AOP)之schema配置方式

一.通过Scheme配置实现AOP步骤(Spring AOP环境的环境与上篇博文 Spring接口方式相同)    步骤一.编写业务类: public class AspectBusiness {    //切入点     public String delete(String obj) {         System.out.println("==========调用切入点:" + obj + "说:你敢删除我!===========\n");        

Spring学习之事务注解@Transactional

今天学习spring中的事务注解,在学习Spring注解事务之前需要明白一些事务的基本概念: 事务:并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位.通过事务数据库能将逻辑相关的一组操作绑定在一起,以便服务器保持数据的完整性. 事务隔离级别:在并发处理数据中,为了保持数据的完整性和正确性,而执行的操作数据方式. 脏读 :一个事务读取到另一事务未提交的更新数据. 幻读:一个事务读到另一个事务已提交的insert数据. 不可重复读: 是指在一个事务内多

spring学习3_通过注解简单实现AOP

在上一篇中通过XML配置演示了Spring实际进行AOP的过程,这里简单介绍一下通过注解实现这一功能的过程. 1.Spring配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-ins

Spring学习总结(2)- AOP

一,什么是AOP AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率. 在学习AOP时,先要了解什么是代理模式,可以参考: 代理模式 二,使用Spring实现AOP