Spring框架AOP原理及实现

本文详细介绍了Spring框架中的AOP思想,包括AOP的定义、功能、核心概念,如连接点、切入点、增强和切面。阐述了Pointcut语法,并列举了两种实现方式:XML编程和注解实现。在XML实现中,讲述了从创建Service层和Dao层,到配置AOP的全过程。而在注解实现中,讲解了如何添加注解解析器以及如何在事务类中应用注解进行增强。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、AOP思想

1.1 什么是AOP

Aspect oritention programming(面向切面编程),把一个个的横切关注点(这些零散存在于业务方法中的功能代码,我们称之为横切面关注点)放到某个模块中去,称之为切面。那么每一个的切面都能影响业务的某一种功能,切面的目的就是功能增强,如日志切面就是一个横切关注点,应用中许多方法需要做日志记录的只需要插入日志的切面即可。这种面向切面编程的思想就是AOP思想了。
在这里插入图片描述
在这里插入图片描述

1.2 AOP的功能

AOP能够将那些与Service业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

1.3 AOP当中的概念

Joinpoint:连接点,被拦截到需要被增强的方法。where:去哪里做增强
Pointcut:切入点,哪些包中的哪些类中的哪些方法,可认为是连接点的集合。where:去哪些地方做增强
Advice:增强,当拦截到Joinpoint之后,在方法执行的什么时机(when)做什么样(what)的增强。
Aspect:切面,Pointcut+Advice,去哪些地方+在什么时候+做什么增强
Weaving:织入,把Advice加到Target上之后,创建出Proxy对象的过程。
注意:
Spring的AOP使用动态代理实现:
如果一个类实现了接口,那么spring就使用JDK的动态代理完成AOP;
如果一个类没有实现接口,那么spring就是用cglib完成AOP;

1.4 Pointcut语法:

切入点一般指业务类

  1. AspectJ切入点语法如下:
    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
  2. 翻译成中文:
    execution(<访问修饰符>? <返回类型> <声明类型>? <方法名>(<参数>) <异常>?)
  3. 举例:public static Class java.lang.Class.forName(String className)throws ClassNotFoundException
  4. 通配符:
    *:匹配任何部分,只能表示一个单词
    … 可用于全限定名中和方法参数中,分别表示子包和0到N个参数
    在这里插入图片描述

1.4 AOP实现方式

(1)xml编程实现
(2)注解实现

2、xml编程实现

在这里插入图片描述

(1)创建Service层和Dao层

定义好业务层和dao代码

public class UserServiceImpl implements IUserService {
    @Setter
    private IUserDao dao;

    @Override
    public void save() {
        dao.save();
    }

    @Override
    public void update() {
        dao.update();
    }
}

(2)创建事务类

获取增强函数
JoinPoint :提供访问当前被增强方法的真实对象、代理对象、方法参数等数据。
ProceedingJoinPoint:JinPoint子类,只用于环绕增强中,可以处理被增强方法

public class BusManager {

    public void begin(JoinPoint jp){
        System.out.println("开启事务...");
        /*JoinPoint  :提供访问当前被增强方法的真实对象、代理对象、方法参数等数据。*/
        /*获取被代理的对象(房间主人)*/
        System.out.println(jp.getTarget().getClass());
        /*获取代理对象(中介)*/
        System.out.println(jp.getThis().getClass());
        /*获取被增强方法的参数,(接口方法)*/
        System.out.println(jp.getSignature());
        /*获取传入目标方法的参数对象*/
        System.out.println(Arrays.toString(jp.getArgs()));
    }

    public void commit(){
        System.out.println("提交事务...");
    }

    /*通过xml文件配置增强标签,可以捕获异常信息,在这里打印*/
    public void rollback(Exception ex)
    {
        System.out.println("回滚事务...");
        System.out.println(ex);
    }

    public void destory(){
        System.out.println("释放资源...");
    }

    /*环绕方法,自定义逻辑。*/
    public Object around(ProceedingJoinPoint pjp){
        /*ProceedingJoinPoint:JinPoint子类,只用于环绕增强中,可以处理被增强方法。 */
        Object res = null;

        try{
            System.out.println("开启事务");

            //执行被增强的方法
            res = pjp.proceed();

            System.out.println("提交事务");

        }catch (Throwable e){
            System.out.println("回滚事务");
            e.printStackTrace();

        }finally {
            System.out.println("释放资源");
        }
        return res;
    }
}

(3)Spring AOP开发依赖的jar:(除基础依赖之外)

spring-aop-4.1.2.RELEASE.jar
 com.springsource.org.aopalliance-1.0.0.jar
 com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
 spring5开始在spring-aop库中纳入了AOP联盟的API,不再需要拷贝aopalliance-1.0.0.jar。
<project.spring.version>5.0.0.RELEASE</project.spring.version>

<dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.16.20</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${project.spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>${project.spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>${project.spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>${project.spring.version}</version>
    </dependency>


    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${project.spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${project.spring.version}</version>
    </dependency>

    <!--德鲁伊连接池-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.10</version>
    </dependency>
    <!--mysql连接驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.38</version>
    </dependency>
    <dependency>
      <groupId>commons-dbutils</groupId>
      <artifactId>commons-dbutils</artifactId>
      <version>1.6</version>
    </dependency>
    <!--Aop依赖之一-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.2</version>
    </dependency>

(4)配置aop命名空间:

在这里插入图片描述

(5)配置文件中添加aop标签

配置切入点,切面

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

    <bean id="ser" class="com.project.AOP4xml.service.impl.UserServiceImpl">
        <property name="dao" ref="dao"/>
    </bean>

    <bean id="dao" class="com.project.AOP4xml.dao.impl.UserDaoImpl" />

    <bean id="busmanager" class="com.project.AOP4xml.business.BusManager"/>

    <!--配置aop,底层是动态代理proxy-->
    <aop:config>
        <!--
            pointcut:切入点:
            哪些包里的那些类中的那些方法,需要被增强(where)
            execution(<访问修饰符>? <返回类型> <声明类型>? <方法名>(<参数>) <异常>?)
            ?可以被省略
        -->
        <aop:pointcut id="pc" expression="execution( * com.project.AOP4xml.service.IUserService.*(..))"/>
        <!--
            配置切面:
            Aspect = pointcut+Advice(when+what)  切面 = 切入点+增强
        -->
        <aop:aspect ref="busmanager">
            <!-- 前置增强,在执行业务方法之前要执行的方法-->
            <aop:before method="begin" pointcut-ref="pc"/>

            <!--后置增强,在执行业务方法之后要执行的方法-->
            <aop:after-returning method="commit" pointcut-ref="pc"/>

            <!--异常增强,执行业务方式时,出错要执行的的方法 通过throwing标签捕获异常-->
            <aop:after-throwing method="rollback" pointcut-ref="pc" throwing="ex"/>

            <!--最终增强,无论业务方式能否执行,都会执行的方法-->
            <aop:after method="destory" pointcut-ref="pc"/>

            <!--环绕方法,自定义逻辑-->
            <!--<aop:around method="around" pointcut-ref="pc"/>-->

        </aop:aspect>

    </aop:config>

</beans>

在这里插入图片描述

(6)测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestRun {

    @Autowired
    private IUserService usi;


    @Test
    public void run(){
        usi.save();

    }
    @Test
    public void run1(){
        usi.update();

    }
}

3、注解实现

在xml实现的基础上,修改为注解实现AOP

(1)添加AOP的注解解析器:

在xml配置文件中,添加AOP的注解解析器:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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.xsd
">
    <bean id="service" class="com.project.AOP4anno.service.impl.UserServiceImpl">
        <property name="dao" ref="dao"/>
    </bean>

    <bean id="dao" class="com.project.AOP4anno.dao.impl.UserDaoImpl" />

    <bean id="busmanager" class="com.project.AOP4anno.business.BusManager"/>


    <!--添加AoP注解解析器-->
    <aop:aspectj-autoproxy/>

</beans>

(2)修改事务类

1、在事务控制的类中添加@Aspect注解
在这里插入图片描述
2、在类中新建任意无参数无返回的方法,为方法添加注解"@Pointcut",注解的value值为execution表达式.方法名为Pointcut的id;
在这里插入图片描述
3、事务控制的方法添加各自增强时机的注解.
@Before:前置增强
@AfterReturning:后置增强
@AfterThrowing:异常增强,标签写法与其他有区别
@After:最终增强
@Around:环绕增强
各个注解的value值为Pointcut的id.

package com.project.AOP4anno.business;

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

import java.util.Arrays;

@Aspect
public class BusManager {

    @Pointcut("execution( * com.project.AOP4anno.service.IUserService.*(..))")
    public void bm(){
    }

    @Before("bm()")
    public void begin(JoinPoint jp){
        System.out.println("开启事务...");
        /*JoinPoint  :提供访问当前被增强方法的真实对象、代理对象、方法参数等数据。*/
        /*获取被代理的对象(房间主人)*/
        System.out.println(jp.getTarget().getClass());
        /*获取代理对象(中介)*/
        System.out.println(jp.getThis().getClass());
        /*获取被增强方法的参数,(接口方法)*/
        System.out.println(jp.getSignature());
        /*获取传入目标方法的参数对象*/
        System.out.println(Arrays.toString(jp.getArgs()));
    }

    @After("bm()")
    public void commit(){
        System.out.println("提交事务...");
    }

    /*通过xml文件配置增强标签,可以捕获异常信息,在这里打印*/
    @AfterThrowing(value = "bm()",throwing = "ex")
    public void rollback(Exception ex)
    {
        System.out.println("回滚事务...");
        System.out.println(ex);
    }

    @After("bm()")
    public void destory(){
        System.out.println("释放资源...");
    }

    /*环绕方法,自定义逻辑。*/
    /*@Around("bm()")*/
    public Object around(ProceedingJoinPoint pjp){
        /*ProceedingJoinPoint:JinPoint子类,只用于环绕增强中,可以处理被增强方法。 */
        Object res = null;

        try{
            System.out.println("开启事务");

            //执行被增强的方法
            res = pjp.proceed();

            System.out.println("提交事务");

        }catch (Throwable e){
            System.out.println("回滚事务");
            e.printStackTrace();

        }finally {
            System.out.println("释放资源");
        }


        return res;
    }
}

(3)测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestRun {

    @Autowired
    private IUserService service;


    @Test
    public void run(){
        service.save();

    }
    @Test
    public void run1(){
        service.update();

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值