Spring之AOP(带你一篇文章搞定AOP)

这篇具有很好参考价值的文章主要介绍了Spring之AOP(带你一篇文章搞定AOP)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

Spring的核心之一:AOP


一、AOP概述和原理

用的依赖(包括上篇文章讲诉的IOC依赖):

       <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.2</version>
            </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>6.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.19</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>net.sourceforge.cglib</groupId>
            <artifactId>com.springsource.net.sf.cglib</artifactId>
            <version>2.1.3</version>
        </dependency>

1.概述和原理

  • AOP:面向切面编程。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。通俗来说就是在不修改代码的情况下添加新的功能。
  • 底层通过动态代理实现:
    (1)有接口情况:使用JDK动态代理,即创建接口实现类的代理对象。
    (2)无接口情况:使用CGLIB动态代理,即创建当前类子类的代理对象。

2.JDK动态代理实例

核心:

  • 通过 java.lang.reflect.Proxy类 的 newProxyInstance方法 创建代理类。
  • newProxyInstance方法
    Spring之AOP(带你一篇文章搞定AOP),spring,java,后端,AOP
    参数一:类加载器
    参数二:所增强方法所在的类,这个类实现的接口,支持多个接口
    参数三:实现InvocationHandle接口,重写invoke方法来添加新的功能
    模拟代理:
    UserDao、UserDaoImpl类:
package com.dragon.springaop;

public interface UserDao {
    public int add(int a,int b);
    public String update(String id);
}
================================================
package com.dragon.springaop;

public class UserDaoImpl implements UserDao{
    @Override
    public int add(int a,int b) {
        System.out.println("add方法执行了...");
        return a+b;
    }

    @Override
    public String update(String id) {
        System.out.println("update方法执行了...");
        return id;
    }
}

JDKProxy类(通过 java.lang.reflect.Proxy类 的 newProxyInstance方法创建代理类):

package com.dragon.springaop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class JDKProxy {
    public static void main(String[] args) {
        Class[] interfaces={UserDao.class};//创建接口实现类代理对象
        UserDaoImpl userDao=new UserDaoImpl();
        UserDao dao=(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDao)) ;
        int result=dao.add(1,2);
        System.out.println("result:"+result);
    }
}
class UserDaoProxy implements InvocationHandler{

    //创建的是谁的代理对象,把谁传递过来
    //有参构造传递
    private Object obj;
    public UserDaoProxy (Object obj){
        this.obj=obj;
    }
	//参数含义:代理对象、方法、参数
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法之前执行...."+ method.getName()+":传递参数...."+ Arrays.toString(args));
        Object res=method.invoke(obj,args);
        System.out.println("方法之后执行...."+obj);
        return res;
    }
}

Spring之AOP(带你一篇文章搞定AOP),spring,java,后端,AOP
其实JDK动态代理本质就是在原来要增强的方法前面或后面增加一些逻辑处理等,而不修改源代码。从上面运行结果看以看出,add方法执行结果是3,但是在执行add方法执行多一些语句输出,这些就是我们增加的逻辑处理部分。其中method.invoke()就是模拟的原add方法执行,而前后的输出语句是模拟的增强的代码

二、基于AspectJ实现的AOP操作

1.什么是AspectJ

AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用进行AOP操作。

2.AOP相关术语

  • 连接点:类中可以被增强的方法,称为连接点。
  • 切入点:实际被增强的方法,称为切入点。
  • 通知:增强的那一部分逻辑代码。通知有多种类型:
    (1)前置通知:增强部分代码在原代码前面。
    (2)后置通知:增强部分代码在原代码后面。
    (3)环绕通知:增强部分代码既有在原代码前面,也有在原代码后面。
    (4)异常通知:原代码发生异常后才会执行。
    (5)最终通知:类似与finally那一部分
  • 切面:指把通知应用到切入点这一个动作。

3.切点表达式

  • 语法:execution([权限修饰符] [返回类型] [类全路径] [方法名称] [参数列表])
  • 例1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
execution(* com.auguigu.dao.BookDao.add(..))
  • 例2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.*(..))
  • 例3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.*.* (..))

3.基于注解方式实现

(1)实例:

User:
注解方式创建User对象user

package com.dragon.springaop.anno;

import org.springframework.stereotype.Component;

@Component
public class User {
    public void add(){
        System.out.println("add....");
    }
}

UserProxy类(先忽略@Order注解):
注解方式创建UserProxy对象userProxy
@Aspect定义UserProxy为切面类(即指把通知应用到切入点的类)

package com.dragon.springaop.anno;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.junit.jupiter.api.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect//定义切面类
@Order(3)
public class UserProxy {
    @Before(value = "execution(* com.dragon.springaop.anno.User.add(..))")
    public void before(){
        System.out.println("before.....");
    }
    @AfterReturning(value = "execution(* com.dragon.springaop.anno.User.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning....");
    }
    @After(value = "execution(* com.dragon.springaop.anno.User.add(..))")
    public void after(){
        System.out.println("after....");
    }
    @AfterThrowing(value = "execution(* com.dragon.springaop.anno.User.add(..))")
    public void afterThrowing(){
        System.out.println("afterThrowing....");
    }
    @Around(value = "execution(* com.dragon.springaop.anno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
        System.out.println("环绕之前....");
            proceedingJoinPoint.proceed();
        System.out.println("环绕之后....");
    }
}

spring配置文件:

<?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 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">
         <!--开启组件扫描-->
        <context:component-scan base-package="com.dragon.springaop.anno"/>
        <!--开启AspectJ生成代理对象-->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

测试:

 	ApplicationContext context=new ClassPathXmlApplicationContext("beanaop1.xml");
        User user=context.getBean("user", User.class);
        user.add();

Spring之AOP(带你一篇文章搞定AOP),spring,java,后端,AOP
可以看出Befoe(前置通知,在add前运行)、AfterRetruning(后置通知或返回通知,在add返回值后运行)、AfterThrowing(异常通知,在add出现异常后,这个没有运行,因为没异常,大家在add内添加 int i=1/0 测试一下,不在演示)、After(最终通知,在add执行完后)、Around(环绕通知,在add前和后)的运行时期。

(2)切入点提取

上面的UserProxy 类中有很多重复的切入点表达式,可以进行公共提取

@Pointcut(value = "execution(* com.dragon.springaop.anno.User.add(..))")
public void pointDemo(){    
}

//前置通知
@Before(value="pointDemo()")
public void before(){
    System.out.println("before....");
}

(3)设置增强类优先级

上面的实例只有UserProxy一个增强类,当有多个增强类时,可以使用@Order(数值)设置优先级执行。(数字越小优先级越高)
在上诉例子中多创建一个PeopleProxy类,设置@Order:

package com.dragon.springaop.anno;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.junit.jupiter.api.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Order(1)
public class PersionProxy {
    @Before(value = "execution(* com.dragon.springaop.anno.User.add(..))")
    public void persionBefore(){
        System.out.println("persionBefore.....");
    }
}

上面的UserProxy类中我设置的是Order(3),所以PeopleProxylei类先运行。
Spring之AOP(带你一篇文章搞定AOP),spring,java,后端,AOP

(4)完全注解开发

AOPConfig类:

package com.dragon.springaop.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackages = {"com.dragon.springaop"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AopConfig {
}

Book、BookProxy:

package com.dragon.springaop.aopxml;

import org.springframework.stereotype.Component;

@Component
public class Book {
    public void buy(){
        System.out.println("buy......");
    }
}

========================================
package com.dragon.springaop.aopxml;

public class BookProxy {
    public void before(){
        System.out.println("before....");
    }
}

测试:

		ApplicationContext context=new AnnotationConfigApplicationContext(AopConfig.class);
        Book book=context.getBean("book", Book.class);
        book.buy();

4.基于xml配置文件实现(了解)

Book、BookProxy:

package com.dragon.springaop.aopxml;

import org.springframework.stereotype.Component;

public class Book {
    public void buy(){
        System.out.println("buy......");
    }
}

========================================
package com.dragon.springaop.aopxml;

public class BookProxy {
    public void before(){
        System.out.println("before....");
    }
}

spring配置文件:

 <bean id="book" class="com.dragon.springaop.aopxml.Book"></bean>
    <bean id="bookProxy" class="com.dragon.springaop.aopxml.BookProxy"></bean>

<!--    配置aop增强-->
    <aop:config>
<!--        切入点-->
        <aop:pointcut id="p" expression="execution(* com.dragon.springaop.aopxml.Book.buy(..))"/>
<!--        配置切面-->
        <aop:aspect ref="bookProxy">
<!--            增强作用在具体的方法上-->
            <aop:before method="before" pointcut-ref="p"></aop:before>
        </aop:aspect>
    </aop:config>

测试:

		ApplicationContext context=new ClassPathXmlApplicationContext("beanaop2.xml");
        Book book=context.getBean("book", Book.class);
        book.buy();

总结

以上就是AOP的讲解。文章来源地址https://www.toymoban.com/news/detail-604100.html

到了这里,关于Spring之AOP(带你一篇文章搞定AOP)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 一篇文章搞定克拉美罗界(CRB)

    二郎最近在研究LBL(长基线)定位,大部分论文都提到了文中算法获得的方差接近CRB,所以自己的算法性能较好。于是二郎就想知道克拉美罗界是什么意思,以及能应用的场景。 1)查文档: 克拉美罗界:为无偏估计量的方差确定一个下界,衡量无偏估计的性能。 无偏估计:

    2024年02月15日
    浏览(36)
  • 一篇文章搞定《APP的启动流程》

    前面已经铺垫了Binder、Handler、View的绘制流程 那么该来看看APP的启动流程了,是如何启动了我们这些重要的组件 本文会按照步骤和启动需要的成员并附带一点点源码进行讲解。 以了解熟悉启动的流程为主。不会大篇幅的利用源码深入。 本文结构: 1、冷启动、温启动、热启

    2024年02月16日
    浏览(29)
  • 一篇文章搞定Android权限问题(全版本)

    文章内容如下: 如果你只是想快速的完成你Android权限申请的工作,那么直接上工具PermissionX 如果是想真正的了解Android的权限问题,那么建议你用15分钟通读一下本文。(可以不去实验,收藏以备后用) 首先了解Android版本和SDK的关系,帮助我们分辨后面的权限版本。 其次把最常

    2023年04月20日
    浏览(40)
  • 一篇文章搞定《Android权限问题(全版本)》

    文章内容如下: 如果你只是想快速的完成你Android权限申请的工作,那么直接上工具PermissionX 如果是想真正的了解Android的权限问题,那么建议你用15分钟通读一下本文。(可以不去实验,收藏以备后用) 首先了解Android版本和SDK的关系,帮助我们分辨后面的权限版本。 其次把最常

    2024年02月03日
    浏览(37)
  • 【Unity】一篇文章搞定AStar(A*)算法

    AStar(A*)算法,是一种在静态网格中求解最短路径直接有效的搜索方法。在游戏开发中,A*算法常应用于部分RPG游戏和策略战棋类游戏。对于Unity开发者来说,掌握A*算法也是十分有必要的。不过在了解A*算法之前,有必要先回顾一下深度优先算法(DFS)、广度优先算法(BFS)

    2024年02月02日
    浏览(40)
  • Spring Boot 3 + JWT + Security 联手打造安全帝国:一篇文章让你掌握未来!

    Spring Security 已经成为 java 后台权限校验的第一选择.今天就通过读代码的方式带大家深入了解一下Security,本文主要是基于开源项目spring-boot-3-jwt-security来讲解Spring Security + JWT(Json Web Token).实现用户鉴权,以及权限校验. 所有代码基于 jdk17+ 构建.现在让我们开始吧! Springboot 3.0 Spri

    2024年02月07日
    浏览(37)
  • 一篇文章搞定Java中常用集合的排序方法

    目录 Array · 数组 List · 列表 Collections.sort() 简单类型 复杂对象 类 使用Lambda表达式 Stream API Map · 键值对 对 Map 的 Key 进行排序 对 Map 的 Value 进行排序 最近在做算法题的时候,发现排序在大部分题中都不可或缺,今天心血来潮,总结下Java中集合排序常用的方法,基本覆盖了大

    2024年02月09日
    浏览(37)
  • 一篇文章搞定什么是nodeJs它和NPM关系与应用

    现在前端的入门门槛越来越高了,不再是单纯 html+css+js ,各种前端框架 层出不穷,各种ui组件库层出不穷。 模块化,打包化,各种工具库层出不穷,前端变成 大前端 ,甚至前端可以搞定整个项目,通过 node 作为服务端api, 这里我们主角就是 nodeJs javaScript是一门脚本语言,

    2024年02月03日
    浏览(33)
  • 一篇文章搞定《实战中的设计模式之Android版》

    其实大多数可能和我一样,在开发项目的累积经验下,和对设计模式隐约的记忆下。 在开发项目的过程中其实已经使用到了设计模式,但是不能自知。 比如:之前开发的基于AI的一个对话IM,里面涉及到了很多的设计模式。但是都是下意识的去使用,甚至连他是那种设计模式

    2024年02月10日
    浏览(31)
  • 一篇文章搞定《动手学深度学习》-(李沐)PyTorch版本的所有内容

    目录 目录 简介 阅读指南 1. 深度学习简介 2. 预备知识 3. 深度学习基础 4. 深度学习计算 5. 卷积神经网络 6. 循环神经网络 7. 优化算法 8. 计算性能 9. 计算机视觉 10. 自然语言处理 环境 参考(大家可以在这里下载代码) 原书地址(大家可以在这里阅读电子版PDF内容) 引用 阅读

    2023年04月24日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包