[学习笔记] Spring之Spring AOP

# 学习 # · 2021-02-09

实现Spring AOP

(1)配置pom.xml,导入Aspectj依赖包。

<!--Asceptj-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

(2)编写业务逻辑接口及其实现类:

public class UserServiceImpl implements UserService {

    public void insert() {
        System.out.println("增加用户");
    }

    public void delete() {
        System.out.println("删除用户");
    }

    public void update() {
        System.out.println("修改用户");
    }

    public void select() {
        System.out.println("查询用户");
    }
}

(3)编辑Spring配置文件applicationContext.xml,注册Bean:

<bean id="UserService" class="com.demo.service.impl.UserServiceImpl"></bean>

(4)创建测试类:

@Test
public void run() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    //动态代理接口
    UserService service = context.getBean(UserService.class);

    service.insert();
}

实现Spring AOP方法一:使用Spring的API接口实现

1、创建两个类:BeforeLogger和AfterLogger。

//使用Spring的MethodBeforeAdvice接口,实现前置增强
public class BeforeLogger implements MethodBeforeAdvice {
    /**
     * 前置增强
     * @param method 要执行的目标对象的方法
     * @param objects 参数
     * @param o 目标对象
     * @throws Throwable
     */
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println(o.getClass().getName() + "的" + method.getName() + "方法被执行了");
    }
}

//使用Spring的AfterReturningAdvice接口,实现后置增强
public class AfterLogger implements AfterReturningAdvice {
    /**
     * 后置增强
     * @param o 返回值
     * @param method 目标对象的方法
     * @param objects 目标对象
     * @param o1
     * @throws Throwable
     */
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了" + method.getName() + "方法,返回值为:" + o);
    }
}

2、编辑Spring配置文件applicationContext.xml,注册Bean:

<bean id="BeforeLogger" class="com.demo.log.BeforeLogger"></bean>
<bean id="AfterLogger" class="com.demo.log.AfterLogger"></bean>

(3)编辑Spring配置文件applicationContext.xml,注册AOP:

<!--配置AOP,需要导入AOP的约束-->
<aop:config>
    <!--
  定义切入点aop:pointcut
  id:切入点的命名
  expression:切入点指示符,括号内容是一个切入点表达式,支持模糊匹配
  -->
    <aop:pointcut id="pointcute" expression="execution(* com.demo.service.impl.UserServiceImpl.*(..))"/>

    <!--执行环绕增加-->
    <aop:advisor advice-ref="BeforeLogger" pointcut-ref="pointcute"></aop:advisor>
    <aop:advisor advice-ref="AfterLogger" pointcut-ref="pointcute"></aop:advisor>
</aop:config>

4、执行结果:


实现Spring AOP方法二:使用自定义类实现

(1)创建并编写增强类:

public class UserPointCut {
    /**
     * 前置增强
     * @param jp 当前连接点的信息
     * 通过该实例的getTarget()方法可以获取到被代理的对象目标
     * getSignature()方法返回被代理的目标方法
     * getArgs()方法返回传递给目标方法的参数数组
     */
    public void before(JoinPoint jp) {
        System.out.println("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName() + " 方法");
    }

    /**
     * 后置增强
     * @param jp
     * @param result
     */
    public void after(JoinPoint jp, Object result) {
        System.out.println("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName() + " 方法。方法返回值:" + result);
    }
}

2、编辑Spring配置文件applicationContext.xml,注册Bean:

<bean id="UserPointCut" class="com.demo.aop.UserPointCut"></bean>

3、编辑Spring配置文件applicationContext.xml,注册AOP:

<!--配置AOP,需要导入AOP的约束-->
<aop:config>
    <aop:pointcut id="pointcute" expression="execution(* com.demo.service.impl.UserServiceImpl.*(..))"/>

    <!-- 引用包含增强方法的Bean -->
    <aop:aspect ref="UserPointCut">
        <!-- 将before()方法定义为前置增强并引用pointcut切入点 -->
        <aop:before method="before" pointcut-ref="pointcute"></aop:before>
        <!-- 将afterReturning()方法定义为后置增强并引用pointcut切入点 -->
        <!-- 通过returning属性指定为名为result的参数注入返回值 -->
        <aop:after-returning method="after" pointcut-ref="pointcute" returning="result" />
    </aop:aspect>
</aop:config>

(4)执行结果:


实现Spring AOP方法三:使用注解实现

1、AspectJ:是一个面向切面的框架,它扩展了Java语言,定义了AOP语法,能够在编译期提供代码的织入。

2、@AspectJ:是AsceptJ5新增的功能,使用JDK5.0注解技术和正规的AsceptJ切点表达式语言描述切面。

3、使用注解标注切面:

(1)使用注解定义前置增强和后置增强实现日志功能:

//使用@Aspect注解将UserPointCut定义为切面
@Aspect
public class UserPointCut {

    //使用@Pointcut注解定义切入点表达式
    @Pointcut("execution(* com.demo.service.impl.UserServiceImpl.*(..))")
    public void pointcut() {}

    //使用@Before注解将before()方法定义为前置增强
    @Before("pointcut()")
    public void before(JoinPoint jp) {
        System.out.println("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName() + " 方法");
    }

    //使用@AfterReturning注解将afterReturning()方法定义为后置增强
    @AfterReturning(pointcut = "pointcut()", returning = "returnValue")
    public void afterReturning(JoinPoint jp, Object returnValue) {
        System.out.println("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName() + " 方法。方法返回值:" + result);
    }

}

(2)编写Spring配置文件,完成切面织入:

<context:component-scan base-package="service,dao" />
<!-- 启用对@AspectJ注解的支持,Spring将自动为匹配的Bean创建代理 -->
<aop:aspectj-autoproxy />

5、使用注解定义其他类型的增强:

(1)通过注解实现异常抛出增强:

/**
 * 通过注解实现异常抛出增强
 */
@AfterThrowing(pointcut = "execution(* com.demo.service.impl.UserServiceImpl.*(..))", throwing = "e")
public void afterThrowing(JoinPoint jp, RuntimeException e) {
    System.out.println(jp.getSignature().getName() + " 方法发生异常:" + e);
}

(2)通过注解实现最终增强:

/**
 * 通过注解实现最终增强
 */
@After("execution(* com.demo.service.impl.UserServiceImpl.*(..))")
public void afterLogger(JoinPoint jp) {
    System.out.println(jp.getSignature().getName() + " 方法结束执行。");
}

(3)通过注解实现环绕增强:

/**
 * 通过注解实现环绕增强
 */
@Around("execution(* com.demo.service.impl.UserServiceImpl.*(..))")
public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable {
    System.out.println("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName()
             + " 方法。方法入参:" + Arrays.toString(jp.getArgs()));
    try {
        Object result = jp.proceed();
        System.out.println("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName() + " 方法。方法返回值:" + result);
        return result;
    } catch (Throwable e) {
        System.out.println(jp.getSignature().getName() + " 方法发生异常:" + e);
        throw e;
    } finally {
        System.out.println(jp.getSignature().getName() + " 方法结束执行。");
    }
}

Spring AOP补充

1、切入指示符几种常用的模糊匹配:

(1)public * addNewsUser(entity.User):表示匹配所有类型的返回值。

(2)public void *(entity.User):表示匹配所有方法名。

(3)public void addNewsUser(...):表示匹配所有参数个数和类型。

(4)* com.service.*.*(...):表示匹配com.service包下所有类的所有方法。

(5)* com.servce..*.*(...):表示匹配com.service包及其子包下所有类的所有方法。

如无特殊说明,本博所有文章均为博主原创。

如若转载,请注明出处:一木林多 - https://www.l5v.cn/archives/216/

评论