Java框架--spring(三、AOP--面向切面编程)

本文详细介绍了Spring中的面向切面编程(AOP)概念,包括AOP与OOP的区别、基本概念如连接点、切入点、通知等,并通过XML配置和注解方式展示了如何在Spring中实现AOP。此外,还探讨了AOP在事务管理中的应用,以及如何通过AOP减少重复代码,提高代码复用性和开发效率。
摘要由CSDN通过智能技术生成

事务:看作一次对数据的若干操作组成的一个序列,是一个整体的过程,要么成功要么都不成功(转账)
JdbcTemplate默认使用jdbc的事务,提交事务,自动的(执行完自动提交)
spirng中提供了事务管理
实现原理:AOP的思想
开发之前已经写好了一个功能,后来又要添加新的功能,那么必须修改源代码,这样很麻烦
AOP是OOP的延续,在OOP的基础上增加额外的功能,将业务代码与非业务代码分离

一、AOP

1.AOP概述

AOP(Aspect Oriented Programming)面向切面编程,其中Aspect 意为切面.AOP是OOP( Object Oriented Programming 面向对象编程)的延续.利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低提高程序的可重用性,同时提高了开发的效率

AOP与OOP的区别:

  • OOP:面向对象编程,针对业务处理过程的实体及其属性行为进行抽象封装,以获

    得更加清晰高效的逻辑单元划分

  • AOP:针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中

    各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异

  • OOP是整体设计,AOP是针对业务代码的公共部分进行抽取

  • 面向切面编程只是面向对象编程的一种补充

使用AOP的好处:减少重复,专注业务

AOP的核心原理:

  • 使用动态代理的方式在执行方法前后或者出现异常的时候做加入相关的逻辑
  • 可以实现在不修改代码的情况下,为程序添加新的功能
  • 抽取的代码也是有一定条件(功能与业务逻辑没有直接关系)

2.AOP 的基本概念

连接点(Joinpoint):类中可以被增强(在原来基础上增加功能)的方法,这个方法就被称为连接点

切入点(pointcut):类中有很多方法可以被增强,但实际中只有 add 和 update被增了,那么 add 和 update 方法就被称为切入点(实际实现的连接点)

通知(Advice):

  • 通知是指一个切面在特定的连接点要做的事情(增强的功能)。

  • 通知分为方法执行前通知,方法执行后通知,环绕通知等.

切面(Aspect):把通知添加到切入点的过程叫切面.

目标(Target): 代理的目标对象(要增强的类)

代理(Proxy): 向目标对象应用通知之后创建的代理对象(mybatis中的mapper对象就是一个代理对象)

在这里插入图片描述

3.spring AOP的实现

概述

​ 对于 AOP 这种编程思想,很多框架都进行了实现。Spring 就是其中之一,可以完成面向切面编程,然而,AspectJ实现了 AOP 的功能,AspectJ 是一个基于 Java 语言的 AOP 框架,它提供了强大的 AOP 功能,且其实现方式更为简捷,使用更为方便, 而且还支持注解式开发。所以,Spring 又将 AspectJ 的对于 AOP 的实现也引入到了自己的框架中

​ 在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式。 AspectJ 是一个优秀面向切面的框架,它扩展了 Java 语言,提供了强大的切面实现。

AspectJ常用的通知五种类型:

  • 前置通知
  • 后置通知
  • 环绕通知
  • 异常通知
  • 最终通知

测试AOP功能

1)下载aop相关jar包
<!--aop-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>
2)编写要增强的类和被增强的类

要增强的类UserDao

package com.ffyc.spring.dao;
import org.springframework.stereotype.Repository;

@Repository(value = "userDao")//创建对象
public class UserDao {

    //要增强的方法,在基础上增强一个保存日志的功能
    public void save(){
        System.out.println("保存用户");
    }
}

被增强的类

package com.ffyc.spring.aop;

public class AopDemo {
    /**
     * 通知:在连接点上要做的事(增强的功能)
     *      通知分为:前置,后置,异常,环绕通知
     */
    public void savelog(){
        System.out.println("保存日志");
    }
}

service层

package com.ffyc.spring.service;

import com.ffyc.spring.dao.UserDao;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

//创建对象
@Service(value = "userService")
public class UserService {

    @Resource(name="userDao")
    private UserDao  userDao;

    public void saveUser() {
        userDao.save();
    }
}
3)基于aspectj的xml配置实现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: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">

    <!--把装有增强功能的类交给spring管理-->
    <bean id="aopDemo" class="com.ffyc.spring.aop.AopDemo"></bean>

    <aop:config>
        <!--配置切入点  expression:增强的类的方法-->
        <aop:pointcut id="save" expression="execution(* com.ffyc.spring.dao.UserDao.save(..))"/>

        <!--配置切面-->
        <aop:aspect ref="aopDemo">
            <aop:before method="savelog" pointcut-ref="save"></aop:before>
        </aop:aspect>
    </aop:config>

</beans>

在这里插入图片描述

4.在spring配置文件中导入aop的xml
	<!--注解扫描-->
	<context:component-scan base-package="com.ffyc.spring"></context:component-scan>
    <!--导入实现aop的配置文件-->
    <import resource="aop.xml"></import>

测试

package test;
import com.ffyc.spring.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test2 {
    public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("springConfig.xml");
        UserService service = app.getBean("userService",UserService.class);
                    service.saveUser();
    }
}

在这里插入图片描述

AOP配置实现

所有的配置写在一个xml文件中,在spring配置文件中import

配置

  • 把装有增强功能的类交给spring管理

  • aop:config

  • aop:pointcut切入点

  • aop:aspect切面

    • aop:before
    • aop:after
    • aop:after-returning
    • aop:after-throwing
    • aop:around

连接点

	public void save(){
        System.out.println("保存用户1");
    }

    public void save(int a){
        System.out.println("保存用户2");
        int x =10/0;
    }

    public boolean save(String s){
        System.out.println("保存用户3");
        return true;
    }

切入点配置

<!--* :任意返回值类型   (..)任意参数列表-->
<aop:pointcut id="save1" expression="execution(* com.ffyc.spring.dao.UserDao.save(..))"/>
<!--* :任意返回值类型   (int)指定参数列表的方法-->
        <aop:pointcut id="save2" expression="execution(* com.ffyc.spring.dao.UserDao.save(int))"/>
<!--* :指定返回值类型   (String)指定参数列表-->
        <aop:pointcut id="save3" expression="execution(boolean com.ffyc.spring.dao.UserDao.save(String))"/>

通知

	public void savelog(){
        System.out.println("保存日志");
    }

    public void ExceptionAdvice(Throwable e){
        System.out.println("*******异常通知********");
        System.out.println(e.getMessage());
    }
    
    public void aroundAdvice(ProceedingJoinPoint point){
        System.out.println("前置通知");
        try {
            point.proceed();
        } catch (Throwable throwable) {
            System.out.println("异常通知");
            throwable.printStackTrace();
        }
        System.out.println("后置通知");
    }

配置切面

  • before 前置通知
  • after 后置通知
  • after-returning 最终通知
  • after-throwing 异常通知 (throwing = 对应的java方法异常参数)
  • around 环绕通知
 <!--配置切面-->
        <aop:aspect ref="aopDemo">
            <!--<aop:before method="savelog" pointcut-ref="save1"></aop:before>
            <aop:after method="savelog" pointcut-ref="save2"></aop:after>-->
           <!-- <aop:after-returning method="show" pointcut-ref="save3"></aop:after-returning>-->
            <!--<aop:after-throwing method="ExceptionAdvice" pointcut-ref="save1" throwing="e"></aop:after-throwing>-->
            <aop:around method="savelog" pointcut-ref="save1"></aop:around>
        </aop:aspect>

AOP注解实现

  • 开启注解扫描
    <context:component-scan base-package="com.ffyc.spring"></context:component-scan>
  • 在spring配置文件中启动AspectJ 实现的AOP
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
package com.ffyc.spring.aop;

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

@Component//声明此类交由spring管理
@Aspect //声明这是一个切面(把通知添加到切入点)
public class AopDemo {

    /**
     * 通知:在连接点上要做的事(增强的功能)
     *      通知分为:前置,后置,异常,环绕通知
     */
    
    @Before("execution(* com.ffyc.spring.dao.UserDao.save())")//切入点
    public void before(){//通知
        System.out.println("before");
    }

    @After("execution(* com.ffyc.spring.dao.UserDao.save())")
    public void after(){
        System.out.println("after");
    }

    
    @AfterThrowing(value = "execution(* com.ffyc.spring.dao.UserDao.save(int))",throwing = "e")
    public void ExceptionAdvice(Throwable e){
        System.out.println("异常通知");
        System.out.println(e.getMessage());
    }

    /*@Around("execution(* com.ffyc.spring.dao.UserDao.save(int))")
    public void aroundAdvice(ProceedingJoinPoint point){
        System.out.println("前置通知");
        try {
            point.proceed();
        } catch (Throwable throwable) {
            System.out.println("异常通知");
            throwable.printStackTrace();
        }
        System.out.println("后置通知");
    }*/
}

注意:环绕通知可以替代所有通知,若使用环绕通知,可以不使用其他通知

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值