Spring AOP(详解)

news2024/10/5 18:55:26

目录

1.AOP概述

 2.AOP相关术语

3.Spring AOP的原理机制

3.1JDK动态代理

3.2 CGLIB动态代理

3.3简单代码展示

3.3.1JDK动态代理

3.3.2CGLIB动态代理

4.Spring的AOP配置

4.1pom.xml

4.2增强方法

4.3切点

 4.4切面

5.基于注解的AOP配置

5.1.创建工程

5.2.增强

5.3AOP配置

5.3.1常用注解


1.AOP概述

AOP (Aspect Orient Programming),直译过来就是 面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。

简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对程序进行增强:权限校验,日志记录,性能监控,事务控制.

 2.AOP相关术语

(1)横切关注点

跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志、安全、缓存、事务等等。

(2)连接点

连接点是在应用执行中能够插入切面的一个点。即程序执行过程中能够应用通知的所有点。

(3)切点

切点是真正需要插入切面的一个或多个连接点。即通知被应用的具体位置(在哪些连接点)。通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点(比如Aspect切点表达式)。有些AOP框架允许我们创建动态的切点,可以根据运行时的决策(比如方法的参数值)来决定是否应用通知。

(4)通知

切面的工作被称为通知。即包含了需要用于多个应用对象的横切行为。

通知定义了切面是什么以及何时使用。除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题。它应该应用在某个方法被调用之前?之后?之前和之后都调用?还是只在方法抛出异常时调用?

Spring切面可以应用5种类型的通知:

  • 前置通知(Before):在目标方法被调用之前调用通知功能。
  • 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。
  • 返回通知(After-returning):在目标方法成功执行之后调用通知。
  • 异常通知(After-throwing)):在目标方法抛出异常后调用通知。
  • 环绕通知(Around) :通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

(5)切面

切面是通知和切点的结合。通知和切点共同定义了切面的全部内容——它是什么,在何时和何处完成其功能。

(6)织入

织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入:

  • 编译期:切面在目标类编译时被织入。这种方式需要特殊的编译器。Aspect的织入编译器就是以这种方式织入切面的。
  • 类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader) ,它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入(load-time weaving, LTW)就支持以这种方式织入切面。
  • 运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时, AOP容器会为目标对象动态地创建一个代理对象(动态代理)。Spring AOP就是以这种方式织入切面的。

(7)引入

引入指的是向现有的类添加新方法或属性。

(8 )目标对象

代理的目标对象

3.Spring AOP的原理机制

Spring 的AOP 部分使用使用JDK动态代理,部分使用CGLIB来为目标对象创建代理。如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理;如果目标对象没有实现任何接口,则会创建CGLIB动态代理。CGLIB是第三方包,从Spring4.3开始就无需再次导入包了。

3.1JDK动态代理

(1)实现原理

  JDK的动态代理是基于反射实现。JDK通过反射,生成一个代理类,这个代理类实现了原来那个类的全部接口,并对接口中定义的所有方法进行了代理。当我们通过代理对象执行原来那个类的方法时,代理类底层会通过反射机制,回调我们实现的InvocationHandler接口的invoke方法。并且这个代理类是Proxy类的子类(记住这个结论,后面测试要用)。这就是JDK动态代理大致的实现方式。

(2)优点

  1. JDK动态代理是JDK原生的,不需要任何依赖即可使用;
  2. 通过反射机制生成代理类的速度要比CGLib操作字节码生成代理类的速度更快;

(3)缺点

  1. 如果要使用JDK动态代理,被代理的类必须实现了接口,否则无法代理;
  2. JDK动态代理无法为没有在接口中定义的方法实现代理,假设我们有一个实现了接口的类,我们为它的一个不属于接口中的方法配置了切面,Spring仍然会使用JDK的动态代理,但是由于配置了切面的方法不属于接口,为这个方法配置的切面将不会被织入。
  3. JDK动态代理执行代理方法时,需要通过反射机制进行回调,此时方法执行的效率比较低;

3.2 CGLIB动态代理

(1)实现原理

  CGLib实现动态代理的原理是,底层采用了ASM字节码生成框架,直接对需要代理的类的字节码进行操作,生成这个类的一个子类,并重写了类的所有可以重写的方法,在重写的过程中,将我们定义的额外的逻辑(简单理解为Spring中的切面)织入到方法中,对方法进行了增强。而通过字节码操作生成的代理类,和我们自己编写并编译后的类没有太大区别。

(2)优点

  1. 使用CGLib代理的类,不需要实现接口,因为CGLib生成的代理类是直接继承自需要被代理的类;
  2. CGLib生成的代理类是原来那个类的子类,这就意味着这个代理类可以为原来那个类中,所有能够被子类重写的方法进行代理;
  3. CGLib生成的代理类,和我们自己编写并编译的类没有太大区别,对方法的调用和直接调用普通类的方式一致,所以CGLib执行代理方法的效率要高于JDK的动态代理;

(3)缺点

  1. 由于CGLib的代理类使用的是继承,这也就意味着如果需要被代理的类是一个final类,则无法使用CGLib代理;
  2. 由于CGLib实现代理方法的方式是重写父类的方法,所以无法对final方法,或者private方法进行代理,因为子类无法重写这些方法;
  3. CGLib生成代理类的方式是通过操作字节码,这种方式生成代理类的速度要比JDK通过反射生成代理类的速度更慢;

3.3简单代码展示

3.3.1JDK动态代理

(1)抽象角色

public interface Star {
    /**
     * 唱歌
     */
    void sing();
}

(2)真正角色

package com.by.JdkProxy;

//真实角色(周杰伦)
public class RealStar implements Star {
    //优点:此时代码不再重复

    public void sing() {
        System.out.println("周杰伦:快使用双截棍,哼哼哈嘿....");

    }
}

(3)代理角色

//代理类工厂
public class ProxyFactory {

    //优点:此时可以代理任意类型的对象
    //真实角色(周杰伦)
    private Object realObj;

    public ProxyFactory(Object realObj) {
        this.realObj = realObj;
    }

    //获得代理对象
    public Object getProxyObject(){

        /**
         * Proxy:作用创建代理对象
         *      ClassLoader loader:类加载器
         *      Class<?>[] interfaces:真实角色实现的接口,根据接口生成代理类
         *      InvocationHandler h:增强的逻辑,即如何代理(宋吉吉要做的事)
         */
        return Proxy.newProxyInstance(
                realObj.getClass().getClassLoader(),
                realObj.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     *
                     * @param proxy:代理类,一般不用
                     * @param method:要调用的方法
                     * @param args:调用方法时的参数
                     * @return
                     * @throws Throwable
                     */
                    public Object invoke(Object proxy, Method method, Object[] args)
                        											throws Throwable {

                        System.out.println("真正的方法执行前!");
                        System.out.println("面谈,签合同,预付款,订机票");

                        Object result = method.invoke(realObj, args);

                        System.out.println("真正的方法执行后!");
                        System.out.println("收尾款");

                        return result;
                    }
                }
        );
    }
}

(4)测试

public class Client {
    public static void main(String[] args) {
        //获得代理对象
        Star proxyObject = (Star) new ProxyFactory(new RealStar()).getProxyObject();
        System.out.println(proxyObject.getClass());//class com.sun.proxy.$Proxy0
        proxyObject.sing();
    }
}

3.3.2CGLIB动态代理

cglib与动态代理最大的区别就是:

  • 使用jdk动态代理的对象必须实现一个接口

  • 使用cglib代理的对象则无需实现接口

CGLIB是第三方提供的包,所以需要引入jar包的坐标:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>

如果你已经有spring-core的jar包,则无需引入,因为spring中包含了cglib。

(1)真正角色

public class RealStar{

	public void sing() {
		System.out.println("RealStar(周杰伦本人).sing()");
	}
}

(2)代理角色

//代理工厂
public class ProxyFactory implements MethodInterceptor {

    //真实角色
    private Object realObj;

    public ProxyFactory(Object realObj) {
        this.realObj = realObj;
    }

    /**'
     * 获得子类代理对象
     * @return
     */
    public Object getProxyObject() {
        //工具类
        Enhancer en = new Enhancer();
        //设置父类
        en.setSuperclass(realObj.getClass());
        //设置回调函数
        en.setCallback(this);
        //创建子类代理对象
        return en.create();
    }
    /*
        在子类中调用父类的方法
            intercept方法参数说明:
                obj : 代理对象
                method : 真实对象中的方法的Method实例
                args : 实际参数
                methodProxy :代理对象中的方法的method实例
     */
    public Object intercept(Object obj, Method method, Object[] args, 
                            	MethodProxy methodProxy)throws Throwable {
        System.out.println("真正的方法执行前!");
        System.out.println("面谈,签合同,预付款,订机票");

        Object result = method.invoke(realObj, args);

        System.out.println("真正的方法执行后!");
        System.out.println("收尾款");
        return object;
    }
}

(3)测试

package com.by.proxy.CglibProxy;

//测试类
public class Client {
    public static void main(String[] args) {
        //获取代理对象
        RealStar proxyObject = 
            (RealStar) new ProxyFactory(new RealStar()).getProxyObject();
        proxyObject.sing();
    }
}

4.Spring的AOP配置

4.1pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.by</groupId>
    <artifactId>Spring_AOP_Xml</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- Spring常用依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
         <!--支持切点表达式 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
    </dependencies>
</project>

4.2增强方法

(1)创建增强类

public class MyLogAdvice {

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

    //后置通知【try】
    public void afterReturning(){
        System.out.println("后置通知");
    }

    //异常通知【catch】
    public void afterThrowing(){
        System.out.println("异常通知");
    }

    //最终通知【finally】
    public void after(){
        System.out.println("最终通知");
    }

    //环绕通知
    public void around(ProceedingJoinPoint joinPoint){
        try {
            System.out.println("方法执行前的环绕通知");
            joinPoint.proceed();
            System.out.println("方法执行后的环绕通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

(2)配置增强类

<!--增强-->
<bean id="myLogger" class="com.by.advice.MyLogger"></bean>

4.3切点

  1. 切点表达式

    表达式语法:

    execution([修饰符] 返回值类型 包名.类名.方法名(参数))

    例如:

    execution(* com.by.service.UserService.add(..))

    execution(* com.by.service.UserService.*(..))

    execution(* com.by.service.*.*(..))

  2. 配置切点

<aop:config>
    <!--切点-->
    <aop:pointcut id="pointcut" expression="execution(* com.by.service.*.*(..))"/>
</aop:config>

 4.4切面

(1)增强的类型

  • aop:before:用于配置前置通知

  • aop:after-returning:用于配置后置【try】通知,它和异常通知只能有一个执行

  • aop:after-throwing:用于配置异常【catch】通知,它和后置通知只能执行一个

  • aop:after:用于配置最终【finally】通知

  • aop:around:用于配置环绕通知

 

(2)配置切面  

<!--切面-->
<aop:aspect ref="myLogger">
    <!-- 用于配置前置通知:指定增强的方法在切入点方法之前执行 
		method:用于指定通知类中的增强方法名称
		ponitcut-ref:用于指定切入点
	-->
	<aop:before method="before" pointcut-ref="pointcut"/>
    <aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
    <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"/>
    <aop:after method="after" pointcut-ref="pointcut"/>
    <aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>

5.基于注解的AOP配置

5.1.创建工程

(1)pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.by</groupId>
    <artifactId>Spring_AOP_Annotation</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- Spring常用依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
    </dependencies>
</project>

(2)dao

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.by</groupId>
    <artifactId>Spring_AOP_Annotation</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- Spring常用依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>
    </dependencies>
</project>

(3)service

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    public void addUser() {
        userDao.addUser();
    }
}

(4)applicationContext.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/aop
        		http://www.springframework.org/schema/aop/spring-aop.xsd
        		http://www.springframework.org/schema/context
        		http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.by"></context:component-scan>
</beans>

(5)测试

/**
 * 模拟表现层
 */
public class Client {
    public static void main(String[] args) {
        ApplicationContext ac = 
            new ClassPathXmlApplicationContext("applicationContext.xml");
        //使用对象
        UserService userService = ac.getBean("userServiceImpl",UserService.class);
        userService.addUser();
    }
}

5.2.增强

(1)applicationContext.xml

<!-- 开启spring对注解AOP的支持 -->
<aop:aspectj-autoproxy/>

5.3AOP配置

5.3.1常用注解

  • @Aspect:把当前类声明为切面类

  • @Before:前置通知,可以指定切入点表达式

  • @AfterReturning:后置【try】通知,可以指定切入点表达式

  • @AfterThrowing:异常【catch】通知,可以指定切入点表达式

  • @After:最终【finally】通知,可以指定切入点表达式

  • @Around:环绕通知,可以指定切入点表达式

5.3.2注解方式实现aop  

@Component
@Aspect
public class MyLogger {

    @Before("execution(* com.by.service.*.*(..))")
    public void before(){
        System.out.println("方法开始时间:"+new Date());
    }

    @After("execution(* com.by.service.*.*(..))")
    public void after(){
        System.out.println("方法结束时间:"+new Date());
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1366649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

抖去推账号矩阵+无人直播+文案引流系统开发搭建--开源

核心技术 1. AI自动直播&#xff1a; 智能系统通过丰富可定制的文案库&#xff0c; 拥有有料有趣的灵魂。不仅能自动语音讲解内容&#xff0c;还可以在直播中和用户灵活互动。直播中可将团购商品同话术自动上下架。 2. AI剪辑 可一键智能批量成片&#xff0c;也可跟着模板剪…

苹果IOS如何支持微信小程序分享

各位同学们好&#xff01;我是咕噜铁蛋&#xff01;&#xff0c;我们经常需要与读者分享有关移动应用的使用方法和技巧。微信小程序是一种便捷的应用形式&#xff0c;可以在微信内部直接使用&#xff0c;而无需下载和安装。本文铁蛋讲详细介绍iOS苹果支持微信小程序类型分享的使…

简单几步,实现餐厅扫码点餐

越来越多的人选择外出就餐&#xff0c;而餐厅的点餐方式也随着科技的发展而不断进步。其中&#xff0c;扫码点餐是最为常见的一种方式&#xff0c;它不仅方便快捷&#xff0c;还能节省人力成本。本文将介绍一种简单易行的餐厅扫码点餐解决方案。 打开乔拓云平台&#xff0c;登录…

【React】02-如何理解React通过对DOM的模拟,最大限度地减少与DOM的交互

如何理解React通过对DOM的模拟&#xff0c;最大限度地减少与DOM的交互 背景分析关于虚拟DOM 背景 在学习React的过程中&#xff0c;发现很多文档上关于React的高效都有这么一句话的描述——React通过对DOM的模拟&#xff0c;最大限度地减少与DOM的交互&#xff0c;对于我这种前…

Spark---RDD算子(单值类型转换算子)

文章目录 1.RDD算子介绍2.转换算子2.1 Value类型2.1.1 map2.1.2 mapPartitions2.1.3 mapPartitionsWithIndex2.1.4 flatMap2.1.5 glom2.1.6 groupBy2.1.7 filter2.1.8 sample2.1.9 distinct2.1.10 coalesce2.1.11 repartition2.1.12 sortBy 1.RDD算子介绍 RDD算子是用于对RDD进…

Redis(三)持久化

文章目录 RDB&#xff08;Redis Database&#xff09;自动触发保存频率修改dump文件保存路径修改文件保存名称dump恢复 手动触发save![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a56fdff44aee4efa96c2ce3615b69dc1.png)bgsave 优劣优点缺点 检查修复dump文件会触…

算法基础之耍杂技的牛

耍杂技的牛 核心思想&#xff1a; 贪心 推公式&#xff1a; 将 i 和 i1 个奶牛交换位置 比较交换位置后的危险系数最大值若Wi Si > Wi1 Si1 则交换前大 交换后更优 需要交换因此 按照WS从小到大排序 就是最优解 再计算危险系数 #include<iostream>#include<…

Spring学习之——事务控制

Spring中的事务控制 说明&#xff1a; JavaEE体系进行分层开发&#xff0c;事务处理位于业务层&#xff0c;Spring提供了分层设计业务层的事务处理解决方案。 Spring框架为我们提供了一组事务控制的接口。具体在后面的小节介绍。这组接口是在spring-tx.RELEASE.jar中。 spri…

24分+的医药顶刊带你学习表观组学解析超级热点“肿瘤耐药”的机制

对癌症患者采用治疗干预时获得性耐药是转移性癌症复发的主要原因。此前&#xff0c;获得性耐药发展的研究主要集中在识别耐药肿瘤中常见的基因突变。越来越多的证据表明&#xff0c;在永久性获得性耐药出现之前&#xff0c;癌症中存在一种表观遗传调控的可逆耐药状态&#xff0…

[足式机器人]Part3 机构运动学与动力学分析与建模 Ch00-1 坐标系与概念基准

本文仅供学习使用&#xff0c;总结很多本现有讲述运动学或动力学书籍后的总结&#xff0c;从矢量的角度进行分析&#xff0c;方法比较传统&#xff0c;但更易理解&#xff0c;并且现有的看似抽象方法&#xff0c;两者本质上并无不同。 2024年底本人学位论文发表后方可摘抄 若有…

关爱服务 |“冬日暖情”送温暖乐善公益行志愿服务活动(第十七期)

为大力弘扬“学习雷锋、奉献他人、提升自己”的志愿精神&#xff0c;有效整合动员全民志愿服务资源&#xff0c;全面推进清远市志愿服务事业发展。机构将以“三关爱”活动为主题&#xff0c;积极开展关爱他人、关爱自然、关爱社会志愿服务活动&#xff0c;积极宣传、倡导志愿者…

docker swarm 常用命令简介以及使用案例

docker swarm Docker Swarm 是Docker官⽅的跨节点的容器编排⼯具。⽤户只需要在单⼀的管理节点上操作&#xff0c;即可管理集群下的所有节点和容器 解决的问题 解决docker server的集群化管理和部署Swarm通过对Docker宿主机上添加的标签信息来将宿主机资源进⾏细粒度分区&am…

txt文档里筛选出重复数据,并保存到新的txt文档

txt文档里筛选出重复数据&#xff0c;并保存到新的txt文档 input_file rD:\pythonXangmu\quchong\input_file.txt #原始文档 #output_file output.txt#重复内容记录文档 output_file rD:\pythonXangmu\quchong\output.txt#绝对路径&#xff0c;解决报错找不到文件或文件夹 w…

20.Activity跳转时的参数传递

(1).如何传递数据 (2).如何接收数据 (3).如何回传数据

基于深度学习的PCB板缺陷检测系统(含UI界面、yolov5、Python代码、数据集)

项目介绍 项目中所用到的算法模型和数据集等信息如下&#xff1a; 算法模型&#xff1a;     yolov5 yolov5主要包含以下几种创新&#xff1a;         1. 添加注意力机制&#xff08;SE、CBAM、CA等&#xff09;         2. 修改可变形卷积&#xff08;DySnake-主…

【现代密码学】笔记2 -- 完善保密性《introduction to modern cryphtography》现代密码学原理与协议

【现代密码学】笔记2--完善保密性《introduction to modern cryphtography》 写在最前面2 完善保密性的介绍2.1 定义和基本属性加密方案的组成密钥产生算法 (Gen)加密算法 (Enc)解密算法 (Dec)概率分布独立性 完美保密加密3. 回顾加密词法4. 完美保密&#xff08;**Perfect Sec…

【书生·浦语大模型实战营03】《基于 InternLM 和 LangChain 搭建你的知识库》学习笔记

《基于 InternLM 和 LangChain 搭建你的知识库》 常见术语 RAG: Retrieval Augmented Generation&#xff0c;检索增强生成 1. 大模型开发范式 1.1 RAG VS Finetune RAGFinetune低成本可个性化微调可实时更新知识覆盖面广受基座模型影响大成本高昂单次回答知识有限无法实时…

Maven之多环境配置与应用

多环境配置与应用 1. 多环境配置作用 maven提供配置多种环境的设定&#xff0c;帮助开发者使用过程中快速切换环境 2. 多环境配置步骤 2.1 定义多环境 <!--定义多环境--> <profiles><!--定义具体的环境&#xff1a;生产环境--><profile><!--定义…

Spring——Spring的事务控制(1)基础篇

Spring事务控制 1.事务介绍 1.1.什么是事务&#xff1f; 当你需要一次执行多条SQL语句时&#xff0c;可以使用事务。通俗一点说&#xff0c;如果这几条SQL语句全部执行成功&#xff0c;则才对数据库进行一次更新&#xff0c;如果有一条SQL语句执行失败&#xff0c;则这几条S…

短视频矩阵系统+无人直播源码+视频批量分发----开发实践

核心技术 1. AI自动直播&#xff1a; 智能系统通过丰富可定制的文案库&#xff0c; 拥有有料有趣的灵魂。不仅能自动语音讲解内容&#xff0c;还可以在直播中和用户灵活互动。直播中可将团购商品同话术自动上下架。 2. AI剪辑 可一键智能批量成片&#xff0c;也可跟着模板剪…