Spring框架--AOP面向切面编程

Posted 肖帆咪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring框架--AOP面向切面编程相关的知识,希望对你有一定的参考价值。

Spring框架往期文章

AOP(Aspect Oriented Programming 面向切面编程)

不使用 AOP 的开发方式的例子

先定义好接口与一个实现类,该实现类中除了要实现接口中的方法外,还要再写两个非业务方法。非业务方法也称为交叉业务逻辑:

不使用aop,我们需要显式调用

AOP概述

AOP是OOP的延续,利用AOP可以对业务逻辑的各个部分进行隔离,降低业务逻辑部分间的耦合度,提高代码的重用性和开发效率

AOP和OOP的关系:

OOP是针对业务处理过程的实体及其属性,行为进行抽象封装,使得更加清晰高效的逻辑单元划分

AOP是针对业务处理过程中的切面进行提取,面对的是某个步骤或者阶段,以获得逻辑过程中各部分间低耦合的隔离效果

原理 😗 使用动态代理的方式在执行方法前后加入相关逻辑

案例😗 事务处理:开启/关闭事务,出现异常后回滚事务

​ 权限判断:在执行方法前,判断是否具有权限

​ 日志:在执行前进行日志处理

AOP的基本概念

连接点(joinpoint)😗 类中可以被增强的方法(添加额外的功能)

切入点(pointcut)😗 类中很多方法可以被加强,若实际只有add被增强了,那么add方法就是切入点

通知(Advice)😗 一个切面在特定的连接点需要做的事

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

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

代理(Proxy)😗 向目标对象应用通知之后创建的代理对象

springAOP 实现

AspectJ 实现了 AOP 的功能,AspectJ 是一个基于 Java 语言的 AOP框架,它提供了强大的 AOP 功能,且其实现方式更为简捷,使用更为方便,而且还支持注解式开发。所以,Spring 又将 AspectJ 的对于 AOP 的实现也引入到了自己的框 架中。
在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式。

AspectJ 是一个优秀面向切面的框架,它扩展了 Java 语言,提供了强大的切面实现。

AspectJ 中常用的通知有五种类型:前置通知,后置通知,环绕通知,异常通知,最终通知.

1.下载 AOP 相关 jar

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aspects</artifactId>
	<version>5.2.2.RELEASE</version>
</dependency>

2.基于 aspectj 的 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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       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="aopdemo" class="com.ff.spring.aop.AopDemo"></bean>
	<aop:config>
		<!-- 配置切入点 -->
		<aop:pointcut expression="execution(*com.ff.spring.service.UserService.adduser(..))" id="adduser"/>
			<aop:pointcut expression="execution(*com.ff.spring.service.UserService.*(..))" id="allmethod"/>
		<!-- 配置通知和切入点 -->
		<aop:aspect ref="aopdemo">
			<aop:before method="savelog" pointcut-ref="adduser"/>
			<aop:after method="savelog" pointcut-ref="adduser"/>
		</aop:aspect>
	</aop:config>
    
</beans>

3.环绕通知和异常通知特殊

<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       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="aopdemo" class="com.ff.spring.aop.AopDemo"></bean>
	<aop:config>
		<!-- 配置切入点 -->
		<aop:pointcut expression="execution(*com.ff.spring.service.UserService.adduser(..))" id="adduser"/>
			<aop:pointcut expression="execution(*com.ff.spring.service.UserService.*(..))" id="allmethod"/>
		<!-- 配置通知和切入点 -->
		<aop:aspect ref="aopdemo">
			<aop:around method="aroundAdvice" pointcut-ref="adduser"/>
			<aop:after-throwing method="exceptionAdvice" pointcut-ref="allmethod"throwing="e" />
		</aop:aspect>
	</aop:config>
    
</beans>

切面类

package com.spring0.common;


import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

public class Common 
    /*
    环绕通知:需要传入ProceedingJoinPoint
    使用ProceedingJoinPoint对象代理调用方法
     */
    public void trans(ProceedingJoinPoint proceedingJoinPoint) throws Throwable 
        System.out.println("开启事务");
        proceedingJoinPoint.proceed();//代理调用我们的业务代码
        System.out.println("提交事务");
    

    /*
    异常通知
     */
    public void exception(Throwable e)
        System.out.println("出错了"+e.getMessage());
    

使用注解实现AOP

1.在spring.xml中添加开启<aop:aspectj-autoproxy />
2.在切面类中加注解@Component@Aspect
3.在方法前加注解
package com.spring0.common;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

/*
1.在spring.xml中添加开启<aop:aspectj-autoproxy />
2.在切面类中加注解
@Component
@Aspect
3.在方法前加注解
 */
@Component
@Aspect
public class Common 
    /*
    通知:在连接点上做的事情
    通知类型:前置通知,后置通知,环绕通知,异常通知,最终通知
     */
//    @Before("execution(* com.spring0.dao.UserDao.save(..))")注解方式的前置通知

    //注解方式的后置通知
    @After("execution(* com.spring0.dao.UserDao.save(..))")
    public void saveLog()
        System.out.println("保存日志");
    

    /*
    环绕通知
    注解方式:@Around("execution(* com.spring0.dao.UserDao.save(..))")
     */
    @Around("execution(* com.spring0.dao.UserDao.save(..))")
    public void trans(ProceedingJoinPoint proceedingJoinPoint) throws Throwable 
        System.out.println("开启事务");
        proceedingJoinPoint.proceed();//代理调用我们的业务代码
        System.out.println("提交事务");
    

    /*
    异常通知
    注解方式@AfterThrowing(value = "execution(* com.spring0.dao.UserDao.save(..))" , throwing = "e")
     */
    @AfterThrowing(value = "execution(* com.spring0.dao.UserDao.save(..))" , throwing = "e")
    public void exception(Throwable e)
        System.out.println("出错了"+e.getMessage());
    

以上是关于Spring框架--AOP面向切面编程的主要内容,如果未能解决你的问题,请参考以下文章

Spring框架--AOP面向切面编程

spring框架学习——AOP( 面向切面编程)

Spring框架——AOP(面向切面编程)详解

动力节点Spring框架学习笔记-王鹤AOP面向切面编程

Spring框架AOP面向切面编程

面向切面编程的介绍和使用(Spring框架)