Spring AOP 的实现

Spring AOP 的实现

环境搭建

坐标依赖引入 pom.xml

    <!--引入spring环境-->
    <!-- 添加Spring框架的核心依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.4.RELEASE</version>
    </dependency>

    <!--Spring AOP-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.9</version>
    </dependency>

添加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
       		https://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">


    <!-- 设置⾃动化扫描的范围 -->
    <context:component-scan base-package="com.xxxx"/>

    <!--开启AOP代理-->
    <aop:aspectj-autoproxy/>

</beans>

注解实现

UserService.java

package com.xxxx.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    
    
    public void test(){
    
    
        System.out.println("UserService...");
        //int i= 1/0;
    }
}

定义切面

package com.xxxx.aspect;

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

/**
 * 定义切面(通过注解的方式)
 *      设置注解:@Aspect
 *
 *      由切入点与通知的结合
 *
 *      定义切入点 Pointcut
 *          规定需要拦截哪些方法,哪些方法需要被处理
 *          @PointCut("匹配规则")
 *
 *      定义通知
 *          前置通知 @Before
 *          返回通知 @AfterReturning
 *          异常通知 @AfterThrowing
 *          最终通知 @After
 *          环绕通知 @Around
 *
 */
@Component//将对象交给IOC容器维护
@Aspect//表示当前是一个切面类
public class LogCut {
    
    

    /**
     * 切⼊点:
     *      匹配规则。规定什么⽅法被拦截、需要处理什么⽅法
     * 定义切⼊点
     *      @Pointcut("匹配规则")
     *
     * Aop 切⼊点表达式简介
     *      1. 执⾏任意公共⽅法:
     *          execution(public *(..))
     *      2. 执⾏任意的set⽅法
     *          execution(* set*(..))
     *      3. 执⾏com.xxxx.service包下任意类的任意⽅法
     *          execution(* com.xxxx.service.*.*(..))
     *      4. 执⾏com.xxxx.service 包 以及⼦包下任意类的任意⽅法
     *          execution(* com.xxxx.service..*.*(..))
     *
     *      注:表达式中的第⼀个* 代表的是⽅法的修饰范围
     *      可选值:private、protected、public (* 表示所有范围)
     */
    @Pointcut("execution (* com.xxxx.service..*.*(..) )")
    public void cut(){
    
    }

    /**
     * 定义前置通知
     *      在方法执行前执行的通知
     */
    @Before(value = "cut()")
    public void before(){
    
    
        System.out.println("前置通知...在方法执行前执行的通知");
    }

    /**
     * 定义返回通知
     *      方法正常执行完后执行的通知
     */
    @AfterReturning(value = "cut()")
    public void afterReturning(){
    
    
        System.out.println("返回通知...方法正常执行完后的通知");
    }

    /**
     * 定义最终通知
     *      方法执行结束后执行的通知(无论方法是否能够正常执行)
     */
    @After(value = "cut()")
    public void after(){
    
    
        System.out.println("最终通知...方法执行结束执行的通知");
    }

    /**
     * 定义异常通知
     *      方法抛出异常时执行的通知
     */
    @AfterThrowing(value = "cut()",throwing = "e")
    public void afterThrowing(Exception e){
    
    
        System.out.println("异常通知...方法抛出异常时执行的通知"+ " 异常原因:" + e.getMessage());
    }

    /**
     * 声明环绕通知 并将通知应⽤到切⼊点上
     * ⽅法执⾏前后 通过环绕通知定义相应处理
     * 需要通过显式调⽤对应的⽅法,否则⽆法访问指定⽅法 (pjp.proceed();)
     * @param pjp
     * @return
     */
    @Around(value = "cut()")
    public Object around(ProceedingJoinPoint pjp) {
    
    
        System.out.println("环绕通知---前置通知...");
        Object object = null;
        try {
    
    
            //需要通过显式调⽤对应的⽅法,否则⽆法访问指定⽅法
            object = pjp.proceed();
            System.out.println(pjp.getTarget() + "======" + pjp.getSignature());
            System.out.println("环绕通知---返回通知...");
        } catch (Throwable throwable) {
    
    
            throwable.printStackTrace();
            System.out.println("环绕通知---异常通知...");
        }
        System.out.println("环绕通知---最终通知...");
        return object;
    }

}

starter.java

package com.xxxx;

import com.xxxx.dao.UserDao;
import com.xxxx.service.UserService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Starter {
    
    

    public static void main(String[] args) {
    
    

        //得到上下文环境
        BeanFactory factory = new ClassPathXmlApplicationContext("spring.xml");

        //得到bean对象
        UserService userService = (UserService) factory.getBean("userService");
        userService.test();

    }
}

XML实现

定义切面

package com.xxxx.aspect;

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

/**
 * 定义切面(通过XML的方式)
 *
 *      由切入点与通知的结合
 *
 *      定义切入点 Pointcut
 *          规定需要拦截哪些方法,哪些方法需要被处理
 *          @PointCut("匹配规则")
 *
 *
 *
 */
@Component//将对象交给IOC容器维护
public class LogCut {
    
    

    /**
     * 切⼊点:
     *      匹配规则。规定什么⽅法被拦截、需要处理什么⽅法
     * 定义切⼊点
     *      @Pointcut("匹配规则")
     *
     * Aop 切⼊点表达式简介
     *      1. 执⾏任意公共⽅法:
     *          execution(public *(..))
     *      2. 执⾏任意的set⽅法
     *          execution(* set*(..))
     *      3. 执⾏com.xxxx.service包下任意类的任意⽅法
     *          execution(* com.xxxx.service.*.*(..))
     *      4. 执⾏com.xxxx.service 包 以及⼦包下任意类的任意⽅法
     *          execution(* com.xxxx.service..*.*(..))
     *
     *      注:表达式中的第⼀个* 代表的是⽅法的修饰范围
     *      可选值:private、protected、public (* 表示所有范围)
     */
    public void cut(){
    
    }

    /**
     * 定义前置通知
     *      在方法执行前执行的通知
     */
    public void before(){
    
    
        System.out.println("前置通知...在方法执行前执行的通知");
    }

    /**
     * 定义返回通知
     *      方法正常执行完后执行的通知
     */
    public void afterReturning(){
    
    
        System.out.println("返回通知...方法正常执行完后的通知");
    }

    /**
     * 定义最终通知
     *      方法执行结束后执行的通知(无论方法是否能够正常执行)
     */
    public void after(){
    
    
        System.out.println("最终通知...方法执行结束执行的通知");
    }

    /**
     * 定义异常通知
     *      方法抛出异常时执行的通知
     */
    public void afterThrowing(Exception e){
    
    
        System.out.println("异常通知...方法抛出异常时执行的通知"+ " 异常原因:" + e.getMessage());
    }

    /**
     * 声明环绕通知 并将通知应⽤到切⼊点上
     * ⽅法执⾏前后 通过环绕通知定义相应处理
     * 需要通过显式调⽤对应的⽅法,否则⽆法访问指定⽅法 (pjp.proceed();)
     * @param pjp
     * @return
     */
    public Object around(ProceedingJoinPoint pjp) {
    
    
        System.out.println("环绕通知---前置通知...");
        Object object = null;
        try {
    
    
            //需要通过显式调⽤对应的⽅法,否则⽆法访问指定⽅法
            object = pjp.proceed();
            System.out.println(pjp.getTarget() + "======" + pjp.getSignature());
            System.out.println("环绕通知---返回通知...");
        } catch (Throwable throwable) {
    
    
            throwable.printStackTrace();
            System.out.println("环绕通知---异常通知...");
        }
        System.out.println("环绕通知---最终通知...");
        return object;
    }

}

配置文件

<?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
       		https://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">


    <!-- 设置⾃动化扫描的范围 -->
    <context:component-scan base-package="com.xxxx"/>


    <!--切面的配置-->
    <aop:config>
   		<!--aop切⾯-->
        <aop:aspect ref="logCut">
            <!--定义切入点 id对应的是切面类中的切入点的方法-->
            <aop:pointcut id="cut" expression="execution (* com.xxxx.service..*.*(..) )"/>
            <!-- 配置前置通知 指定前置通知⽅法名 并引⽤切⼊点定义 -->
            <aop:before method="before" pointcut-ref="cut"/>
            <!-- 配置返回通知 指定返回通知⽅法名 并引⽤切⼊点定义 -->
            <aop:after-returning method="afterReturning" pointcut-ref="cut"/>
            <!-- 配置异常通知 指定异常通知⽅法名 并引⽤切⼊点定义 -->
            <aop:after-throwing method="afterThrowing" throwing="e" pointcut-ref="cut"/>
            <!-- 配置最终通知 指定最终通知⽅法名 并引⽤切⼊点定义 -->
            <aop:after method="after" pointcut-ref="cut"/>
            <!-- 配置环绕通知 指定环绕通知⽅法名 并引⽤切⼊点定义 -->
            <aop:around method="around" pointcut-ref="cut"/>
        </aop:aspect>
    </aop:config>

</beans>

Guess you like

Origin blog.csdn.net/lln1540295459/article/details/121163092