转自:https://www.kancloud.cn/lmkanyun/java_kuangjia/881881(感谢大佬的分享,本人搬运工)
-
AspectJ:Java 社区里最完整最流行的 AOP 框架.
-
在 Spring2.0 以上版本中, 可以使用基于 AspectJ 注解或基于 XML 配置的 AOP
使用步骤:
1.aopalliance.jar、aspectj.weaver.jar 和 spring-aspects.jar
2.spring配置文件中添加:xmlns:aop="http://www.springframework.org/schema/aop"
3.要在 Spring IOC 容器中启用 AspectJ 注解支持, 只要在 Bean 配置文件中定义一个空的 XML 元素 aop:aspectj-autoproxy 。使AspectJ相关注解生效:当调用目标方法,跟Aspect中声明的方法相匹配的时候,AOP框架会自动的为目标方法所在的类创建代理对象
1.基于注解的方式实现springAOP:
1.创建切面类(LoggingAspect)。
@Aspect:声明当前类为切面类。
@Component:交给springIOC容器进行管理。
@Before:前置通知。
需要使用切点表达式:@Before("execution(* cn.li.service.impl.*.*(..))"),/**
* 可以使用AspectJ表达式,对目标方法进行抽象概括。
*
* execution(* cn.li.service.impl.*.*(String,..))
*
* 第一个* 表示匹配所有访问修饰符 以及所有返回值类型的方法 第二个* 表示当前包下所有的类 第三个* 表示所有的方法名称 ..
* 表示匹配任意多个参数。 (String,.. )表示匹配第一个参数为String类型的方法,..表示匹配任意数量任意类型的参数。
* String,String 表示匹配参数为两个字符串的方法。
*/其中(Joinpoint)对象中封装了目标方法的一些信息,例如获取目标方法名称,获取目标方法参数等。
@Order(number)
:@Order 表示 配置多个切面之间的优先级问题 。 谁的值越小谁的优先级越高 。
@After
:后置通知。使用方法与前置通知相同。注意:后置通知即使方法异常也会成功执行,但是后置通知无法拿到目标方法的返回结果。需要返回通知。
@AfterReturnning
:返回通知,在方法正常之后之后执行的通知,可以拿到目标方法的返回结果。使用返回通知需要注意的是:指定returnning="result",afterReturnningAdvice(JoinPoint joinpoint,Object result)与方法入参位置的对象名称一致,否则会产生异常。
@AfterThrowing
:异常通知,方法产生异常的时候,可以拿到异常信息。同样需要注意的是:指定throwing="e",与afterThrowingAdvice(JoinPoint joinpoint,Exception e)方法入参位置的异常对象名称一致。
@Around:
环绕通知
具体代码实现如下:》》》》》
//当前类就是一个切面类
//想要一个类成为切面类,1.添加@Component 注释标注 当前类被springIOC容器所管理
//2.@Aspect表示当前类为一个切面类
//@Order 表示 配置多个切面之间的优先级问题 。 谁的值越小谁的优先级越高 。
//@Order(2)
//@Aspect
//@Component
public class LoggingAspect {
// @Before表示前置通知。指的是在特定位置之前,去执行该方法
// 通知 其实是切面类中一个具体的方法
// JoinPoint 表示连接点
/**
* 可以使用AspectJ表达式,对目标方法进行抽象概括。
*
* execution(* cn.li.service.impl.*.*(String,..))
*
* 第一个* 表示匹配所有访问修饰符 以及所有返回值类型的方法 第二个* 表示当前包下所有的类 第三个* 表示所有的方法名称 ..
* 表示匹配任意多个参数。 (String,.. )表示匹配第一个参数为String类型的方法,..表示匹配任意数量任意类型的参数。
* String,String 表示匹配参数为两个字符串的方法。
*/
//@Pointcut("execution(* cn.li.service.impl.*.*(..))")
public void declareRepeatJoinPointExpression(){
}
//@Before("execution(* cn.li.service.impl.*.*(..))")
public void beforeLog(JoinPoint joinpoint) {
// 通过连接点对象可以获得调用目标方法的名称和参数
// 获得方法名称。能拿到你要调用方法的名称
String method = joinpoint.getSignature().getName();
// 获得调用方法时传递的参数
List arguments = Arrays.asList(joinpoint.getArgs());
System.out.println("前置日志调用了方法" + method + "方法,参数是" + arguments);
}
// 注意:后置通知即使方法异常也会成功执行,但是后置通知无法拿到目标方法的返回结果。 需要使用返回通知。。。
//@After("execution(* cn.li.service.impl.*.*(..))")
public void afterLog(JoinPoint joinpoint) {
String method = joinpoint.getSignature().getName();
List arguments = Arrays.asList(joinpoint.getArgs());
System.out.println("后置日志 。");
}
// 返回通知
// 注意:返回通知 ,其实跟后置通知一样 。都是在目标方法执行完之后 才会被执行 。
// returning="result" 名字 要跟参数列表中 Object 对象的名称一致 ,不然产生异常。
//@AfterReturning(value = "execution(* cn.li.service.impl.*.*(..))", returning = "result")
public void testAfterReturning(JoinPoint joinpoint, Object result) {
String method = joinpoint.getSignature().getName();
System.out.println("我是返回通知 。 我在目标方法核心业务执行完才会执行 。" + result);
}
//@AfterThrowing(value="execution(* cn.li.service.impl.*.count(..))",throwing="e")
public void testAfterThrowing(JoinPoint joinpoint,Exception e){
System.out.println("我是异常通知 ,我是在方法产生异常后执行的。"+e);
}
//环绕通知 。 跟动态代理的代码很像。
//@Around("declareRepeatJoinPointExpression()")
// public void around(ProceedingJoinPoint pjp){
// //声明一个Object 对象 用来表示 目标方法的返回值 。
// Object result=null;
// String method=pjp.getSignature().getName();
// try {
// System.out.println("我是前置日志 。。。"+method);
// result = pjp.proceed();//调用proceed() 表示执行被代理类的目标方法。
// System.out.println("我是返回通知"+method+result);
// } catch (Throwable e) {
// //Throwable 所有异常类跟错误类的父类 。Exception Error ...
// // TODO Auto-generated catch block
// e.printStackTrace();
// System.out.println("异常通知,产生异常的时候 会执行catch 里面的代码 。");
// }
// System.out.println("我是后置通知 。。。"+result+method);
// }
}
//@Order(1)
//@Aspect
//@Component
public class CheckAspect {
//@Before("execution(* cn.li.service.impl.*.*(..))")
public void checkBeforeLog(JoinPoint joinpoint){
System.out.println("我是验证切面的前置通知 。");
}
}
2.基于XML文件的方式实现springAOP:
<!--
@Aspect 注解生效 。
让注解生效,切面中的注解生效。
当调用目标方法,跟Aspect中声明的方法相匹配的时候,
AOP框架会自动的为目标方法所在的类创建代理对象。
作用是让注解生效 ,当调用的方法,跟通知中声明的方法一致的时候。AOP框架会自动的为那个方法所在的类生成代理对象,然后在调用目标方法(之前或者之后)把通知中的方法加进去。
-->
<!-- <aop:aspectj-autoproxy></aop:aspectj-autoproxy> -->
<!-- 配置切面 的bean -->
<bean id="checkAspect" class="cn.li.aspect.CheckAspect"></bean>
<bean id="loggingAspect" class="cn.li.aspect.LoggingAspect"></bean>
<!-- 配置aop -->
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut expression="execution(* cn.li.service.impl.*.*(..))" id="pointcut"/>
<aop:aspect ref="checkAspect" order="1">
<aop:before method="checkBeforeLog" pointcut-ref="pointcut"/>
</aop:aspect>
<aop:aspect ref="loggingAspect" order="2">
<aop:before method="beforeLog" pointcut-ref="pointcut"/>
<aop:after method="afterLog" pointcut-ref="pointcut"/>
<aop:after-returning method="testAfterReturning" returning="result" pointcut-ref="pointcut"/>
<aop:after-throwing method="testAfterThrowing" throwing="e" pointcut-ref="pointcut"/>
<!-- <aop:around method="around" pointcut-ref="pointcut"/> -->
</aop:aspect>
</aop:config>