Spring使用注解实现AOP

本文内容纲要:

- 一、AspectJ概述

- 二、@Aspect(定义切面)、@Before(前置增强)、@AfterReturning(后置增强)注解配置切面

- 1、使用注解定义切面以实现日志切面功能,如下

- 2、切面定义完后,还需要在Spring配置文件中完成织入工作,如下

- 三、@AfterThrowing(异常抛出增强)、@After(最终增强)、@Around(环绕增强)注解进行增强的配置

- 1、@AfterThrowing(异常抛出增强)

- 2、@After(最终增强)

- 3、@Around(环绕增强)

一、AspectJ概述

AspectJ是一个面向切面的框架,它扩展了Java语言、定义了AOP语法,能够在编译期提供代码的织入,它提供了一个专门的编译期用来生成遵守字节编码规范的Class文件。

@Aspect是AspectJ 5新增的功能,使用JDK 5.0注解技术和正规的AspectJ切点表达式语言描述切面。因此在使用@Aspect之前,需要保证所使用的JDK是5.0或更高版本,否则将无法使用注解技术。

Spring通过集成AspectJ实现了以注解的方式定义切面,大大减轻了配置文件的工作量。此外,因为Java的反射机制无法获取方法参数名,Spring还需要利用轻量级的字节码处理框架asm(已集成在Spring Core模块中)处理@AspectJ中所描述的方法参数名。

二、@Aspect(定义切面)、@Before(前置增强)、@AfterReturning(后置增强)注解配置切面

1、使用注解定义切面以实现日志切面功能,如下

package edu.cn.service;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.util.Arrays;

@Aspect

public class UserServiceLogger {

private static final Logger log = LoggerFactory.getLogger(UserServiceLogger.class);

@Before("execution(* edu.cn.service.UserService.*(..))")

public void before(JoinPoint jp){

log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName()

+ "方法。方法入参:" + Arrays.toString(jp.getArgs()));

}

@AfterReturning(pointcut = "execution(* edu.cn.service.UserService.*(..))", returning = "returnValue")

public void afterReturning(JoinPoint jp, Object returnValue){

log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName()

+ "方法。方法返回值:" + returnValue);

}

@Aspect等注解在aspectjweaver依赖下。在上述代码中,使用@Aspect注解将UserServiceLogger定义为切面,并且使用@Before注解将before()方法定义为前置增强,使用@AfterReturning方法将afterReturning()方法定于为后置增强

为了能够获得当前连接点的信息,在增强方法中添加了JoinPoint类型的参数,Spring会自动注入该实例。

对于后置增强,还可以定义一个参数用于接受目标方法的返回值。需要注意的是,必须在@AfterReturning注解中通过returning属性指定该参数的名称,Spring会将目标方法的返回值赋值给指定名称的参数。

1.1、对于相同的切入点要求,可以统一定义,以便于重用和维护,如下

package edu.cn.service;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.util.Arrays;

@Aspect

public class UserServiceLogger {

private static final Logger log = LoggerFactory.getLogger(UserServiceLogger.class);

@Pointcut("execution(* edu.cn.service.UserService.*(..))")

public void pointcut(){}

@Before("pointcut()")

public void before(JoinPoint jp){

log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName()

+ "方法。方法入参:" + Arrays.toString(jp.getArgs()));

}

@AfterReturning(pointcut = "pointcut()", returning = "returnValue")

public void afterReturning(JoinPoint jp, Object returnValue){

log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName()

+ "方法。方法返回值:" + returnValue);

}

}

切入点表达式可以使用@Pointcut注解来表示,而切入点签名则需要通过一个普通的方法定义来提供,如上述代码中的pointcut()方法,作为切入点签名的方法必须返回void类型。定义好切入点后,就可以使用“pointcut()”签名进行引用

2、切面定义完后,还需要在Spring配置文件中完成织入工作,如下

只需在配置文件中添加aop:aspectj-autoproxy/元素,就可以启用对于@AspectJ注解的支持,Spring将自动为匹配的Bean创建代理

为了注册定义好的切面,还需在Spring配置文件中声明UserServiceLogger的一个实例。如果不需要被其他Bean引用,可以不指定id属性

<?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-2.5.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop.xsd">

<context:component-scan base-package="service,dao"/>

<bean class="edu.cn.service.UserServiceLogger"></bean>

<aop:aspectj-autoproxy/>

</beans>

三、@AfterThrowing(异常抛出增强)、@After(最终增强)、@Around(环绕增强)注解进行增强的配置

1、@AfterThrowing(异常抛出增强)

使用@AfterThrowing注解可以定义异常抛出增强。如果需要获取抛出的异常,可以为增强方法声明相关类型的参数,并通过@AfterThrowing注解的throwing属性指定该参数名称,Spring会为其注入从目标方法抛出的异常实例,如下

package edu.cn.service;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Aspect;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

@Aspect

public class ErrorLogger {

private static final Logger log = LoggerFactory.getLogger(ErrorLogger.class);

@AfterThrowing(pointcut = "execution(* edu.cn.service.UserService.*(..))", throwing = "e")

public void afterThrowing(JoinPoint jp, RuntimeException e){

log.error(jp.getSignature().getName() + "方法方法异常:" + e);

}

}

2、@After(最终增强)

使用@After注解可以定义最终增强

package edu.cn.service;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.Aspect;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

@Aspect

public class AfterLogger {

private static final Logger log = LoggerFactory.getLogger(AfterLogger.class);

@After("execution(* edu.cn.service.UserService.*(..))")

public void afterLogger(JoinPoint jp){

log.info(jp.getSignature().getName() + "方法结束执行。");

}

}

3、@Around(环绕增强)

使用@Around注解可以定义环绕增强。通过为增强方法声明ProceedingJoinPoint类型的参数,可以获得连接点信息。通过它的proceed()方法可以调用真正的目标方法,从而实现对连接点的完全控制。

package edu.cn.service;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.util.Arrays;

@Aspect

public class AroundLogger {

private static final Logger log = LoggerFactory.getLogger(AroundLogger.class);

@Around("execution(* edu.cn.service.UserService.*(..))")

public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable {

log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName()

+ "方法。方法入参:" + Arrays.toString(jp.getArgs()));

try {

Object result = jp.proceed();

log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName()

+ "方法。方法返回值:" + result);

} catch (Throwable e) {

log.error(jp.getSignature().getName() + "方法发生异常:" + e);

throw e;

}finally {

log.info(jp.getSignature().getName() + "方法结束执行。");

}

}

}

本文内容总结:一、AspectJ概述,二、@Aspect(定义切面)、@Before(前置增强)、@AfterReturning(后置增强)注解配置切面,1、使用注解定义切面以实现日志切面功能,如下,2、切面定义完后,还需要在Spring配置文件中完成织入工作,如下,三、@AfterThrowing(异常抛出增强)、@After(最终增强)、@Around(环绕增强)注解进行增强的配置,1、@AfterThrowing(异常抛出增强),2、@After(最终增强),3、@Around(环绕增强),

原文链接:https://www.cnblogs.com/yanguobin/p/11707538.html

以上是 Spring使用注解实现AOP 的全部内容, 来源链接: utcz.com/z/296917.html

回到顶部