AspectJ是一个基于Java语言的AOP框架,Spring2.0以后新增了对AspectJ切点表达式支持,@AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面,它是一种新版本Spring框架,建议使用AspectJ方式来开发AOP。主要用途:自定义开发
为了能够灵活定义切入点位置,Spring AOP提供了多种切入点指示符。
语法结构: execution( 方法修饰符 方法返回值 方法所属类 匹配方法名 ( 方法中的形参表 ) 方法申明抛出的异常 )
其中红色字体的部分时不能省略的,各部分都支持通配符 “*” 来匹配全部。
比较特殊的为形参表部分,其支持两种通配符
例如:
()匹配一个无参方法
(..)匹配一个可接受任意数量参数和类型的方法
(*)匹配一个接受一个任意类型参数的方法
(*,Integer)匹配一个接受两个参数的方法,第一个可以为任意类型,第二个必须为Integer。
下面举一些execution的使用实例:
分类 | 示例 | 描述 |
通过方法签名定义切入点 | execution(public * * (..)) | 匹配所有目标类的public方法,第一个*为返回类型,第二个*为方法名 |
execution(* save* (..)) | 匹配所有目标类以save开头的方法,第一个*代表返回类型 | |
execution(**product(*,String)) | 匹配目标类所有以product结尾的方法,并且其方法的参数表第一个参数可为任意类型,第二个参数必须为String | |
通过类定义切入点 | execution(* aop_part.Demo1.service.*(..)) | 匹配service接口及其实现子类中的所有方法 |
通过包定义切入点 | execution(* aop_part.*(..)) | 匹配aop_part包下的所有类的所有方法,但不包括子包 |
execution(* aop_part..*(..)) | 匹配aop_part包下的所有类的所有方法,包括子包。(当".."出现再类名中时,后面必须跟“*”,表示包、子孙包下的所有类) | |
execution(* aop_part..*.*service.find*(..)) | 匹配aop_part包及其子包下的所有后缀名为service的类中,所有方法名必须以find为前缀的方法 | |
通过方法形参定义切入点 | execution(*foo(String,int)) | 匹配所有方法名为foo,且有两个参数,其中,第一个的类型为String,第二个的类型为int |
execution(* foo(String,..)) | 匹配所有方法名为foo,且至少含有一个参数,并且第一个参数为String的方法(后面可以有任意个类型不限的形参) |
例如:within(aop_part..*) 表示匹配包aop_part以及子包的所有方法
由于execution可以匹配包、类、方法,而within只能匹配包、类,因此execution完全可以代替within的功能。
例如:this(aop_part.service.GodService) 表示匹配了GodService接口的代理对象的所有连接点
this通过判断代理类的类型来决定是否和切入点匹配,两者限定的对象都是指定类型的实例。
例如: target(aop_part.service.GodService) 表示匹配实现了GodService接口的目标对象的所有连接点
例如:args(aop_part.service) 表示匹配时,出入的参数类型时service的方法
其与execution(**(aop_part.service))的区别为,execution针对的时方法签名,而args针对的是运行时的实际参数类型。
args既匹配buyGoods(service newService),也匹配buyGoods(Buyservice newService) <Buyservice为service的子类>
execution只匹配buyGoods(service newService)
支持 &&、 || 、!
与其他语言所代表的意思相同
例:args(aop_part.service) &&execution(**(aop_part.service))
aop联盟定义通知类型,具有特性接口,必须实现,从而确定方法名称。
aspectj 通知类型,只定义类型名称。已经方法格式。
个数:6种,知道5种,掌握1中。
before:前置通知(应用:各种校验)在方法执行前执行,如果通知抛出异常,阻止方法运行
afterReturning:后置通知(应用:常规数据处理)方法正常返回后执行,如果方法中抛出异常,通知无法执行必须在方法执行后才执行,所以可以获得方法的返回值。
around:环绕通知(应用:十分强大,可以做任何事情)方法执行前后分别执行,可以阻止方法的执行必须手动执行目标方法
afterThrowing:抛出异常通知(应用:包装异常信息)方法抛出异常后执行,如果方法没有抛出异常,无法执行
after:最终通知(应用:清理现场) 方法执行完毕后执行,无论方法中是否出现异常
Spring Aop实例:
UserService.java
package com.zk.b_annotation; public interface UserService { public void addUser(); public String updateUser(); public void deleteUser(); }
UserServiceImpl.java
package com.zk.b_annotation; import org.springframework.stereotype.Service; @Service("userServiceId") public class UserServiceImpl implements UserService { @Override public void addUser() { System.out.println("d_aspect.b_anno addUser"); } @Override public String updateUser() { System.out.println("d_aspect.b_anno updateUser"); int i = 1/ 0; return "阳志就是"; } @Override public void deleteUser() { System.out.println("d_aspect.b_anno deleteUser"); } }
切面
MyAspect.java
package com.zk.b_annotation; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * 切面类,含有多个通知 */ @Component @Aspect public class MyAspect { //前置通知 // @Before("execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))") public void myBefore(JoinPoint joinPoint){ System.out.println("前置通知" + joinPoint.getSignature().getName()); } //声明公共切入点 @Pointcut("execution(* com.zk.b_annotation.UserServiceImpl.*(..))") private void myPointCut(){ } // @AfterReturning(value="myPointCut()" ,returning="ret") public void myAfterReturning(JoinPoint joinPoint,Object ret){ System.out.println("后置通知" + joinPoint.getSignature().getName() + " , -->" + ret); } // @Around(value = "myPointCut()") public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("前置通知"); //手动执行目标方法 Object obj = joinPoint.proceed(); System.out.println("后置通知"); return obj; } // @AfterThrowing(value="execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))" ,throwing="e") public void myAfterThrowing(JoinPoint joinPoint,Throwable e){ System.out.println("抛出异常通知" + e.getMessage()); } @After("myPointCut()") public void myAfter(JoinPoint joinPoint){ System.out.println("后置通知"); } }
beans.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.扫描 注解类 --> <context:component-scan base-package="com.zk.b_annotation"></context:component-scan> <!-- 2.确定 aop注解生效 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
TestAspectAnno.java
package com.zk.b_annotation; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestAspectAnno { @Test public void demo01(){ String xmlPath = "com/zk/b_annotation/beans.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); //获得目标bean UserService userService = (UserService) applicationContext.getBean("userServiceId"); userService.addUser(); userService.updateUser(); userService.deleteUser(); } }
运行效果图:
原文:https://www.cnblogs.com/longlyseul/p/10023395.html