ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
- 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> ~~~