Spring应用之AOP

本文介绍了Spring的面向切面编程(AOP)概念,包括切面、织入、连接点、切入点和通知等关键术语。通过示例展示了如何使用XML配置和注解方式实现切面,包括前置、后置、异常和最终通知,并解释了切入点表达式和通知类型的用法。
摘要由CSDN通过智能技术生成

1. SpringAOP介绍

AOP即面向切面编程,切面泛指系统中与主业务无关的代码,比如安全检查、日志记录、事物等等。AOP可以让主业务逻辑代码与切面代码分别开发,在运行时再进行合并。AOP减少了代码的纠缠,使业务逻辑代码更加清晰。

术语说明
切面切面泛指交叉业务逻辑。比如事务处理、日志处理就可以理解为切面。常用的切面有通知与顾问。实际就是对主业务逻辑的一种增强
织入织入是指将切面代码插入到目标对象的过程。
连接点连接点指切面可以织入的位置。
切入点切入点指切面具体织入的位置。
通知(Advice)通知是切面的一种实现,可以完成简单织入功能(织入功能就是在这里完成的)。通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。
顾问(Advisor)顾问是切面的另一种实现,能够将通知以更为复杂的方式织入到目标对象中,是将通知包装为更复杂切面的装配器。 不仅指定了切入时间点,还可以指定具体的切入点

2. 基于XML方式实现

2.1. 添加依赖

    <dependencies>
        <!-- Spring核心依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.17.RELEASE</version>
        </dependency>
        <!-- Spring-Aspect切面依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
        <!-- junit方便测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2.2. 创建切面类

创建切面类实现不同时机的通知方法

package com.wxw.aspectj;

public class AspectJBean {

    public void before(){
        System.out.println("AspectJBean前置通知!!!");
    }

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

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

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

}

2.3. 创建目标类

package com.wxw.controller;

public class UserController {

    public void queryUser(){
        System.out.println("【UserController】的【queryUser】方法执行了!!!");
    }

}

2.4. 配置文件

<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <bean id="userController" class="com.wxw.controller.UserController"></bean>

    <bean id="aspectJBean" class="com.wxw.aspectj.AspectJBean"></bean>

    <aop:config>
        <!-- 配置切入点 -->
        <aop:pointcut id="pointcut"
                      expression="execution(public * com.wxw.controller.UserController.*(..)) " />
        <!-- 配置切面 -->
        <aop:aspect ref="aspectJBean">
            <!-- 配置相应通知 -->
            <aop:before pointcut-ref="pointcut" method="before" />
            <aop:after-returning pointcut-ref="pointcut" method="afterReturning" />
            <aop:after-throwing pointcut-ref="pointcut" method="afterThrowing"/>
            <aop:after pointcut-ref="pointcut" method="after" />
        </aop:aspect>
    </aop:config>
</beans>

2.5. 运行测试

package com.wxw.test;

import com.wxw.controller.UserController;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestDemo {

    @Test
    public void test01(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
        UserController userController = applicationContext.getBean("userController", UserController.class);
        userController.queryUser();
    }

}

AspectJBean前置通知!!!
【UserController】的【queryUser】方法执行了!!!
AspectJBean后置通知!!!
AspectJBean最终通知!!!

进程已结束,退出代码为 0

3. 基于注解方式实现

3.1. 添加依赖

    <dependencies>
        <!-- Spring核心依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.17.RELEASE</version>
        </dependency>
        <!-- Spring-Aspect切面依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
        <!-- junit方便测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

3.2. 创建切面类

创建切面类实现不同时机的通知方法

package com.wxw.aspectj;

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

@Aspect // 显示的表明当前类是一个切面类
@Component  // 将该对象加载到IoC容器中
public class AspectJBean {

    @Before("execution(* com.wxw.controller.UserController.*(..))")
    public void before(){
        System.out.println("AspectJBean前置通知!!!");
    }

    @AfterReturning("execution(* com.wxw.controller.UserController.*(..))")
    public void afterReturning(){
        System.out.println("AspectJBean后置通知!!!");
    }

    @AfterThrowing("execution(* com.wxw.controller.UserController.*(..))")
    public void afterThrowing(){
        System.out.println("AspectJBean异常通知!!!");
    }

    @After("execution(* com.wxw.controller.UserController.*(..))")
    public void after(){
        System.out.println("AspectJBean最终通知!!!");
    }

}

3.3. 创建目标类

package com.wxw.controller;

import org.springframework.stereotype.Controller;

@Controller
public class UserController {

    public void queryUser(){
        System.out.println("【UserController】的【queryUser】方法执行了!!!");
    }

}

3.4. 运行测试

package com.wxw;

import com.wxw.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class JavaConfig {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(JavaConfig.class);
        UserController bean = applicationContext.getBean(UserController.class);
        bean.queryUser();
    }

}
AspectJBean前置通知!!!
【UserController】的【queryUser】方法执行了!!!
AspectJBean最终通知!!!
AspectJBean后置通知!!!

进程已结束,退出代码为 0

4. 切入点表达式

表达式类型说明
execution定位到目标对象的方法上
within定位到具体的类型上
this代理对象的类型
target目标对象的类型
args参数的类型
@args传入的参数有被该注解修饰
@within类型修饰的注解
@annotation方法修饰的注解

execution表达式语法: execution([访问权限类型] 返回值类型 [全限定类名] 方法名(参数名) [抛出的异常类型])

符合含有
*0到多个符合
方法参数中表示任意个参数,用在报名后表示当前包及其子包
+用在类名后表示当前类及其子类,用在接口后表接口及其实现

示例:

execution(public * *(. .))
指定切入点为:任意公共方法。
execution(* set *(. .))
指定切入点为:任何一个以“set”开始的方法。
execution(* com.xyz.service.*.*(. .))
指定切入点为:定义在service包里的任意类的任意方法。
execution(* com.xyz.service. .*.*(. .))
指定切入点为:定义在service包或者子包里的任意类的任意方法。“..”出现在类名中时,
后面必须跟“*”,表示包、子包下的所有类。
execution(* *.service.*.*(. .))
指定只有一级包下的serivce子包下所有类(接口)中的所有方法为切入点
execution(* *. .service.*.*(. .))
指定所有包下的serivce子包下所有类(接口)中的所有方法为切入点

4. 通知类型

通知类型说明
前置通知目标方法执行之前调用
后置通知目标方法执行完成之后调用
环绕通知目标方法执行前后都会调用方法,且能增强结果
异常处理通知目标方法出现异常调用
最终通知无论程序执行是否正常,该通知都会执行。类似于try…catch中finally代码块
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值