跳转至

面向切面编程#

约 183 个字 8 行代码 预计阅读时间 4 分钟

名词解释#

  • 连接点(JoinPoint):程序执行过程中,可以织入切面的位置。比如方法执行前后或异常抛出之后。
  • 切点(Pointcut):我们配置的满足条件的目标方法
  • 通知(Advice):具体增强的方法
  • 切面(Aspect)切点+通知
  • 织入(Weaving):把通知应用到目标对象上的过程。
  • 代理对象(proxy):目标对象被织入后产生的新对象
  • 目标对象(Target):被织入的对象

AspectJ XML方式开发#

目标对象:

Java
package com.luguosong.xml;

import org.springframework.stereotype.Component;

/**
 * @author luguosong
 */
public class UserServiceImpl {
    public void addUser() {
        System.out.println("添加用户");
    }

    public void deleteUser() {
        System.out.println("删除用户");
        //模拟异常
        int i = 1 / 0;
    }

    public void updateUser() {
        System.out.println("更新用户");
    }
}

切面类:

Java
package com.luguosong.xml;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

/**
 * @author luguosong
 */
public class UserAspect {
    //前置通知
    public void before() {
        System.out.println("前置通知");
    }

    //后置通知
    public void afterReturning() {
        System.out.println("后置通知");
    }

    /*
     * 环绕通知
     *
     * ❗如果发生异常,不会执行 环绕后置通知
     * */
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前置通知");
        Object o = joinPoint.proceed();
        System.out.println("环绕后置通知");
        return o;
    }

    //异常通知
    public void afterThrowing() {
        System.out.println("异常通知");
    }

    //最终通知
    public void after(){
        System.out.println("最终通知");
    }
}

Spring配置文件:

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/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">
    <bean id="userService" class="com.luguosong.xml.UserServiceImpl"/>
    <bean id="userAspect" class="com.luguosong.xml.UserAspect"/>

    <!--aop配置-->
    <aop:config>
        <!--配置切点表达式-->
        <aop:pointcut id="myPointCut" expression="execution(* com.luguosong.xml.UserServiceImpl.*(..))"/>
        <!--配置切面-->
        <aop:aspect ref="userAspect">
            <aop:before method="before" pointcut-ref="myPointCut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="myPointCut"/>
            <aop:around method="around" pointcut-ref="myPointCut"/>
            <aop:after method="after" pointcut-ref="myPointCut"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut"/>
        </aop:aspect>
    </aop:config>
</beans>

测试:

Java
package com.luguosong.xml;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author luguosong
 */
public class Test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aspect.xml");
        UserServiceImpl userService = context.getBean("userService",UserServiceImpl.class);
        userService.addUser();
    }
}

AspectJ注解方式开发🔥#

目标对象:

Java
package com.luguosong.anno;

import org.springframework.stereotype.Component;

/**
 * @author luguosong
 */
@Component("userService")
public class UserServiceImpl {
    public void addUser() {
        System.out.println("添加用户");
    }

    public void deleteUser() {
        System.out.println("删除用户");
        //模拟异常
        int i = 1 / 0;
    }

    public void updateUser() {
        System.out.println("更新用户");
    }
}

Spring配置类,配置组件扫描和启用基于AspectJ的自动代理

Java
package com.luguosong.anno;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * 注解@EnableAspectJAutoProxy表示开启自动代理
 * @author luguosong
 */
@Configuration
@ComponentScan({"com.luguosong.anno"})
@EnableAspectJAutoProxy
public class SpringConfig {
}

切面类:

Java
package com.luguosong.anno;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * 切面
 *
 * 注解@Order控制多个切面的执行顺序
 * @author luguosong
 */
@Component
@Aspect
@Order(3)
public class UserAspect {

    /*
    * 通用切点表达式
    * */
    @Pointcut("execution(* com.luguosong.anno.UserServiceImpl.*(..))")
    public void pointcut() {
    }

    //前置通知
    @Before("execution(* com.luguosong.anno.UserServiceImpl.*(..))")
    public void before() {
        System.out.println("前置通知");
    }

    //后置通知
    @AfterReturning("pointcut()")
    public void afterReturning() {
        System.out.println("后置通知");
    }

    /*
    * 环绕通知
    *
    * ❗如果发生异常,不会执行 环绕后置通知
    * */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前置通知");
        Object o = joinPoint.proceed();
        System.out.println("环绕后置通知");
        return o;
    }

    //异常通知
    @AfterThrowing("pointcut()")
    public void afterThrowing() {
        System.out.println("异常通知");
    }

    //最终通知
    @After("pointcut()")
    public void after(){
        System.out.println("最终通知");
    }

}

测试:

Java
package com.luguosong.anno;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author luguosong
 */
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserServiceImpl userService = context.getBean("userService", UserServiceImpl.class);
        userService.addUser();
        userService.deleteUser();
    }
}

评论