栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

聊聊注解@Aspect的AOP实现操作

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

聊聊注解@Aspect的AOP实现操作

Spring只支持XML方式而没有实现注解的方式(也叫AspectJ方式)的AOP,所以要使用@Aspect注解,只能引入AspectJ相关的 jar 包 aopalliance-1.0.jar 和 aspectjweaver.jar,这个坑把我给坑惨了。

使用步骤如下:

1、引入相关jar包

2、Spring的配置文件 applicationContext.xml 中引入context、aop对应的命名空间;配置自动扫描的包,同时使切面类中相关方法中的注解生效,需自动地为匹配到的方法所在的类生成代理对象。



 
 
 
 

3、创建简单计算器的接口ArithmeticCalculator.java及实现类ArithmeticCalculatorImpl.java

package com.qcc.beans.aop;
public interface ArithmeticCalculator {
 int add(int i, int j);
 int sub(int i, int j);
 int mul(int i, int j);
 int div(int i, int j);
}
package com.qcc.beans.aop;
import org.springframework.stereotype.Component;
//将实现类加入Spring的IOC容器进行管理
@Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
 @Override
 public int add(int i, int j) {
 int result = i + j;
 return result;
 }
 @Override
 public int sub(int i, int j) {
 int result = i - j;
 return result;
 }
 @Override
 public int mul(int i, int j) {
 int result = i * j;
 return result;
 }
 @Override
 public int div(int i, int j) {
 int result = i / j;
 return result;
 }
}

4、现在想在实现类中的每个方法执行前、后、以及是否发生异常等信息打印出来,需要把日志信息抽取出来,写到对应的切面的类中 LoggingAspect.java 中

要想把一个类变成切面类,需要两步,

① 在类上使用 @Component 注解 把切面类加入到IOC容器中

② 在类上使用 @Aspect 注解 使之成为切面类

下面直接上完整代码,用@Aspect注解方式来实现前置通知、返回通知、后置通知、异常通知、环绕通知。

package com.qcc.beans.aop;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class LoggingAspect {
 
 @Before("execution(* com.qcc.beans.aop.*.*(..))")
 public void beforeMethod(JoinPoint jp){
 String methodName = jp.getSignature().getName();
 System.out.println("【前置通知】the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
 }
 
 @AfterReturning(value="execution(* com.qcc.beans.aop.*.*(..))",returning="result")
 public void afterReturningMethod(JoinPoint jp, Object result){
 String methodName = jp.getSignature().getName();
 System.out.println("【返回通知】the method 【" + methodName + "】 ends with 【" + result + "】");
 }
 
 @After("execution(* com.qcc.beans.aop.*.*(..))")
 public void afterMethod(JoinPoint jp){
 System.out.println("【后置通知】this is a afterMethod advice...");
 }
 
 @AfterThrowing(value="execution(* com.qcc.beans.aop.*.*(..))",throwing="e")
 public void afterThorwingMethod(JoinPoint jp, NullPointerException e){
 String methodName = jp.getSignature().getName();
 System.out.println("【异常通知】the method 【" + methodName + "】 occurs exception: " + e);
 }
// 
// @Around(value="execution(* com.qcc.beans.aop.*.*(..))")
// public Object aroundMethod(ProceedingJoinPoint jp){
// String methodName = jp.getSignature().getName();
// Object result = null;
// try {
//  System.out.println("【环绕通知中的--->前置通知】:the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
//  //执行目标方法
//  result = jp.proceed();
//  System.out.println("【环绕通知中的--->返回通知】:the method 【" + methodName + "】 ends with " + result);
// } catch (Throwable e) {
//  System.out.println("【环绕通知中的--->异常通知】:the method 【" + methodName + "】 occurs exception " + e);
// }
// 
// System.out.println("【环绕通知中的--->后置通知】:-----------------end.----------------------");
// return result;
// }
}

5、编写Main方法进行测试

package com.qcc.beans.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
 public static void main(String[] args) {
 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
 ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
 System.out.println(arithmeticCalculator.getClass());
 int result = arithmeticCalculator.add(3, 5);
 System.out.println("result: " + result);
 result = arithmeticCalculator.div(5, 0);
 System.out.println("result: " + result);
 }
}
 

运行结果:

class com.sun.proxy.$Proxy10
【前置通知】the method 【add】 begins with [3, 5]
【后置通知】this is a afterMethod advice...
【返回通知】the method 【add】 ends with 【8】
result: 8
【前置通知】the method 【div】 begins with [5, 0]
【后置通知】this is a afterMethod advice...
Exception in thread "main" java.lang.ArithmeticException: / by zero
 at com.qcc.beans.aop.ArithmeticCalculatorImpl.div(ArithmeticCalculatorImpl.java:28)
 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.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58)
 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.$Proxy10.div(Unknown Source)
 at com.qcc.beans.aop.Main.main(Main.java:15)

把其它代码都注释掉,把环绕通知的方法释放出来,测试结果如下:

【环绕通知中的--->前置通知】:the method 【add】 begins with [3, 5]
【环绕通知中的--->返回通知】:the method 【add】 ends with 8
【环绕通知中的--->后置通知】:-----------------end.----------------------
result: 8
【环绕通知中的--->前置通知】:the method 【div】 begins with [5, 0]
【环绕通知中的--->异常通知】:the method 【div】 occurs exception java.lang.ArithmeticException: / by zero
【环绕通知中的--->后置通知】:-----------------end.----------------------
Exception in thread "main" org.springframework.aop.AopInvocationException: Null return value from advice does not match primitive return type for: public abstract int com.qcc.beans.aop.ArithmeticCalculator.div(int,int)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:219)
 at com.sun.proxy.$Proxy7.div(Unknown Source)
 at com.qcc.beans.aop.Main.main(Main.java:15)

从以上发现,返回通知和异常通知不会同时出现;不管是否发生异常,后置通知都会正常打印。

补充:基于@Aspect实现AOP的两种方式

第一种:
package com.anno; 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; 
@Retention(RetentionPolicy.RUNTIME) //什么时候运行和结束
@Target( {ElementType.METHOD , ElementType.TYPE}) //能放在哪里.
public @interface AnnotationTwo {
}
package com.anno; 
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component; 
@Aspect
@Component
@EnableAspectJAutoProxy
public class AspectAnnotationTOW { 
 @Pointcut("@annotation(AnnotationTwo)")
 public void aspectTow(){
 
 }
 
 @Around("aspectTow()")
 public void aspectservice(ProceedingJoinPoint joinPoint){
 System.out.println(111);
 try {
 Object proceed = joinPoint.proceed();
 } catch (Throwable e) {
 e.printStackTrace();
 }
 }
 
}
第二种:
package com.testAnnotation; 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; 
 
@Retention(RetentionPolicy.RUNTIME) //什么时候运行和结束
@Target( {ElementType.METHOD , ElementType.TYPE}) //能放在哪里.
public @interface AnnotationOfTest {
 public String say();
 public long howLong() default Long.MAX_VALUE;
}
package com.testAnnotation; 
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component; 
import com.rabbitmq.tools.jsonrpc.ProcedureDescription; 
@Component
@EnableAspectJAutoProxy
@Aspect
public class AspectAnnotation {
 @Around("@annotation(annotationOfTest)")
 public Object interceptor(ProceedingJoinPoint pjp, AnnotationOfTest annotationOfTest ) {
 String say = annotationOfTest.say();
 long howlong = annotationOfTest.howLong();
 try {
 System.out.println(say+"t"+howlong);
 Object object = pjp.proceed();
 return object;
 } catch (Throwable e) {
 e.printStackTrace();
 }
 return null;
 }
 }
配置文件:


 
 
 
  
  
 
  
service:
package com.service; 
import java.util.Date; 
import org.springframework.stereotype.Service; 
import com.anno.AnnotationTwo;
import com.testAnnotation.AnnotationOfTest;
 
@Service
public class service {
 @AnnotationTwo
 public void go()
 {
 System.out.println(new Date().toLocaleString());
 } 
}
项目结构:

测试:
package com.test;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
import com.service.service;
import com.testAnnotation.AnnotationOfTest;
 
public class Test {
 public static void main(String[] args) {
 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
 service bean = applicationContext.getBean(service.class);
 bean.go();
 }
}
所需要的包:

以上为个人经验,希望能给大家一个参考,也希望大家多多支持考高分网。如有错误或未考虑完全的地方,望不吝赐教。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/129344.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号