4 Spring AOP

目录

AOP 简介

传统开发模式

先来看一个需求

解决方案

AOP 图示

Spring 启用 AspectJ 基于 xml 配置

创建 pom.xml

创建 UserService 借口和 UserServiceImpl实现类

创建 LogAdvice 日志通知

创建 log4j.properties

重点:创建 spring-context-xml.xml 配置

创建 AopTest_Xml 测试类

Spring 启用 AspectJ 基于注解配置

改造实现类 UserServiceImpl ,加上 @Service 注解

改造 LogAdvice 日志通知,加上 @Component 和 @Aspect 注解

创建 spring-context-anno.xml 注解配置

创建 AopTest_Anno 测试类


AOP 简介

  1. AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论,是对传统 OOP(Object-Oriented Programming,面向对象编程) 的补充。
  2. AOP 的主要编程对象是切面(aspect),而切面是模块化的横切关注点。
  3. 在应用 AOP 编程时, 仍然需要定义公共功能,但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类。这样一来横切关注点就被模块化到特殊的对象(切面)里。
  4. AOP 的好处:(1) 每个事物逻辑位于一个位置, 代码不分散,便于维护和升级;(2) 业务模块更简洁,只包含核心业务代码。

传统开发模式

先来看一个需求

下面是分别定义了一个接口和它的实现类,功能非常简单,实现正整数的加、减、乘、除操作,代码如下:

CalculateService.java

package com.springdemo.service;/*** Created by qfxl on 2024/05/03.*/
public interface CalculateService {int add(int a, int b);int subtract(int a, int b);int times(int a, int b);int divide(int a, int b);
}

CalculateServiceImpl.java

package com.springdemo.service.impl;import com.springdemo.service.CalculateService;
import org.springframework.stereotype.Component;/*** Created by qfxl on 2024/05/03.*/
@Component
public class CalculateServiceImpl implements CalculateService {@Overridepublic int add(int a, int b) {return a + b;}@Overridepublic int subtract(int a, int b) {return a - b;}@Overridepublic int times(int a, int b) {return a * b;}@Overridepublic int divide(int a, int b) {return a / b;}
}

我们的额外需求是:

需求1-做日志:在程序执行期间追踪正在发生的活动
需求2-做验证:希望计算器只能处理正数的运算

如果我们采用传统的方式,只能在每个方法里面先做参数的验证,然后再进行日志记录,这样不仅代码,冗余,而且不利于后期的维护,每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。

以日志需求为例, 只是为了满足这个单一需求, 就不得不在多个模块(方法)里多次重复相同的日志代码。 如果日志需求发生变化, 必须修改所有模块。

类似于这样:

@Component
public class CalculateServiceImpl implements CalculateService {private static final Logger LOGGER = Logger.getLogger(CalculateServiceImpl.class);@Overridepublic int add(int a, int b) {//先进行参数有效性的验证if(a < 0 || b < 0) {System.out.println("参与计算的两个整数有一个为负数: "+a+","+b);return -1;}//做日志LOGGER.debug("add操作之前日志...");//计算int c = a + b;LOGGER.debug("add操作之后日志...");//返回return c;}//....
}

可以看出,在 add 方法中插入了验证和日志的功能,但是,此方法的核心只是做加法操作,我们在业务实现时还要考虑一些共性的东西,这显然是不好的一种方式,那如何在不改变业务类实现的基础上,动态添加验证、日志功能呢?

解决方案

一种比较好的方式是:使用动态代理解决上述问题
代理设计模式的原理:

使用一个代理将对象包装起来,然后用该代理对象取代原始对象。
任何对原始对象的调用都要通过代理。 代理对象决定是否以及何时将方法调用转到原始对象上。
关于使用程序编写动态代理代码,自己可以去查看相关文档,我们这里不做介绍。
实际上,Spring 中的 AOP 就是基于动态代理技术来实现的,下面我们来详细讲解 AOP 。

AOP 图示

我们把上面的需求以图的方式呈现出来,可以清晰地看到共性的操作,把共性的地方抽取出来,模块化成切面,然后让这个切面按我们的预期进行工作,这就是 AOP 的作用。

1

上面的图示中,我们抽取出来共性,也就是验证和日志功能,但是,光有这个共性,还是不能够模块化成切面的,它还需要其它的辅助元素才能成为一个切面。具体如何使用 AOP 完成上述的需求,Spring 给出了具体的方案,下面让我们来看看详细的案例。

Spring 启用 AspectJ 基于 xml 配置

在演示案例前我们先来了解些 AOP 术语:

  • Aspect 中文意思:切面,它只是一个统称,一种名词,它由 Advice 和 PointCut 组成;
  • Advice 中文意思:通知,它是切面的代码载体,可以想象成一个封装好的 JAVA 类,把共性代码封装在这里;
  • PointCut 中文意思:切点,它是用来匹配目标方法的一段配置信息,可以使用注解也可以使用 XML 来配置,它由多个JoinPoint 组成;
  • JoinPoint 中文意思:连接点,它是指匹配到目标方法之后执行 Advice 的时机,共有如下5种:
    • before: 在目标方法执行之前
    • after:在目标方法之后
    • afterThrowing: 在目标方法的 catch 块中
    • afterReturn: 在目标方法的 finally 块中
    • around: 环绕,相当于是上面4种的一个综合体
  • Weave 中文织入:它是一个过程,就是切面织入到目标对象方法的过程,它的原理是基于 代理 来实现的,Spring 目前支持两种代理:
    • 基于 JDK 自带的动态代理类,java.lang.reflect.Proxy,这是默认的情况,但是这个实现有一个前提条件是目标对象必需要有实现的接口。
    • 基于第三方组件 CGLIB 来生成我们的代理类,它不需要目标对象实现任何接口。

创建 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.example</groupId><artifactId>spring-aop-demo</artifactId><version>1.0.0-SNAPSHOT</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><spring.version>5.1.5.RELEASE</spring.version><lombok.version>1.16.20</lombok.version><junit.version>4.12</junit.version><log4j.version>1.2.17</log4j.version><slf4j.version>1.7.25</slf4j.version></properties><dependencies><!-- Spring Begin --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version><scope>test</scope></dependency>
<!--        <dependency>-->
<!--            <groupId>org.springframework</groupId>-->
<!--            <artifactId>spring-aop</artifactId>-->
<!--            <version>${spring.version}</version>-->
<!--        </dependency>--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>${spring.version}</version></dependency><!-- Spring End --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version></dependency><!-- lombok Begin --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version><scope>provided</scope></dependency><!-- lombok End --><!-- Log Begin --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>jul-to-slf4j</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency><!-- Log End --></dependencies><build><plugins><!-- Compiler 插件, 设定 JDK 版本 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.7.0</version><configuration><source>${java.version}</source><target>${java.version}</target><encoding>${project.build.sourceEncoding}</encoding><showWarnings>true</showWarnings></configuration></plugin></plugins></build></project>

创建 UserService 借口和 UserServiceImpl实现类

package com.example.spring.aop.demo.xml.service;public interface UserService {public void addUser();public boolean updateUser();public int deleteUser(int id);
}
package com.example.spring.aop.demo.xml.service.impl;import com.example.spring.aop.demo.xml.service.UserService;public class UserServiceImpl implements UserService {@Overridepublic void addUser() {System.out.println("addUser:添加用户!!!");}@Overridepublic boolean updateUser() {System.out.println("updateUser:修改用户!!!");return true;}@Overridepublic int deleteUser(int id) {System.out.println("deleteUser:删除用户!!!");return id;}}

 

创建 LogAdvice 日志通知

package com.example.spring.aop.demo.xml.advice;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;public class LogAdvice {private static final Logger LOGGER = LoggerFactory.getLogger(LogAdvice.class);public void beforeMethod(JoinPoint joinPoint) {LOGGER.trace("前置通知...");System.out.println("本次要调用的目标对象:" + joinPoint.getTarget());System.out.println("本次要调用的目标方法名:" + joinPoint.getSignature().getName());System.out.println("本次要调用的目标方法参数:" + Arrays.toString(joinPoint.getArgs()));}public void afterReturn(Object obj) {LOGGER.trace("目标方法返回后, 返回对象结果是:" + obj);}public void afterMethod() {LOGGER.trace("后置通知...");}public Object aroundMethod(ProceedingJoinPoint pjp){Object result = null;LOGGER.warn("前置通知!!!");try {result = pjp.proceed();} catch (Throwable e) {
//            e.printStackTrace();LOGGER.warn("异常通知!!!");throw new RuntimeException(e);}LOGGER.warn("后置通知!!!");return result;}
}

创建 log4j.properties

log4j.rootLogger=INFO, console, filelog4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d %p [%c] - %m%nlog4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File=logs/log.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.A3.MaxFileSize=1024KB
log4j.appender.A3.MaxBackupIndex=10
log4j.appender.file.layout.ConversionPattern=%d %p [%c] - %m%n# 便于控制台日志的识别,所以用TRACE日志级别
# 基于 xml 配置的日志打印
log4j.logger.com.example.spring.aop.demo.xml.advice =TRACE# 基于注解配置的日志打印
log4j.logger.com.example.spring.aop.demo.anno.advice =TRACE

重点:创建 spring-context-xml.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"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"><!-- 1.创建目标类 --><bean id="userService" class="com.example.spring.aop.demo.xml.service.impl.UserServiceImpl"></bean><!-- 2.创建切面类(通知对象) --><bean id="logAdvice" class="com.example.spring.aop.demo.xml.advice.LogAdvice"></bean><!-- 3.aop 编程 --><aop:config><!--<aop:aspect>:把切面类声明成 "切面",从而获取到通知(方法)ref:切面类引用--><aop:aspect id="logAdviceAapect" ref="logAdvice"><!--<aop:pointcut>:声明一个切入点,所有的通知都可以使用id:名称,供所有通知引用;expression:切入点表达式--><aop:pointcut id="log_pc"expression="execution(* com.example.spring.aop.demo.xml.service.impl.UserServiceImpl.*(..))"/><!--<aop:before>:前置通知,在目标方法执行前执行method:通知,方法名pointcut:切入点表达式,此表达式只能当前通知使用pointcut-ref:切入点引用,可以与其他通知共享切入点--><aop:before method="beforeMethod" pointcut-ref="log_pc"/><!--<aop:after-returning>:返回通知,返回通知在方法返回结果之后执行returning:通知方法返回参数的名称--><aop:after-returning method="afterReturn" pointcut-ref="log_pc" returning="obj"/><!--<aop:after>:后置通知,在目标方法执行后(无论是否发生异常),执行的通知--><aop:after method="afterMethod" pointcut-ref="log_pc"/><!--<aop:around>:环绕通知,环绕目标方法执行注意:通知方法格式:public Object aroundMethod(ProceedingJoinPoint pjp){...}返回值类型:"Object" ,必须要有返回值;返回目标方法执行之后的结果即调用 "pjp.proceed()" 的结果,否则会出现空指针异常参数类型:"org.aspectj.lang.ProceedingJoinPoint",其是 "JoinPoint" 的子类执行目标方法:"Object result = pjp.proceed();" ,并抛出异常--><aop:around method="aroundMethod" pointcut-ref="log_pc" /></aop:aspect></aop:config></beans>

创建 AopTest_Xml 测试类

package com.example.spring.aop.demo;import com.example.spring.aop.demo.xml.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class AopTest_Xml {@Testpublic void xmlTest(){ApplicationContext ac = new ClassPathXmlApplicationContext("spring-context-xml.xml");UserService userService = (UserService) ac.getBean("userService");userService.addUser();System.out.println();boolean b = userService.updateUser();System.out.println();int i = userService.deleteUser(10);System.out.println();}}

测试结果:

2

Spring 启用 AspectJ 基于注解配置

改造实现类 UserServiceImpl ,加上 @Service 注解

package com.example.spring.aop.demo.anno.service.impl;import com.example.spring.aop.demo.xml.service.UserService;
import org.springframework.stereotype.Service;@Service("userService")
public class UserServiceImpl implements UserService {@Overridepublic void addUser() {System.out.println("addUser:添加用户!!!");}@Overridepublic boolean updateUser() {System.out.println("updateUser:修改用户!!!");return true;}@Overridepublic int deleteUser(int id) {System.out.println("deleteUser:删除用户!!!");return id;}
}

改造 LogAdvice 日志通知,加上 @Component 和 @Aspect 注解

package com.example.spring.aop.demo.anno.advice;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import java.util.Arrays;@Component
@Aspect
public class LogAdvice {private static final Logger LOGGER = LoggerFactory.getLogger(LogAdvice.class);/** 声明一个公共切入点,所有的通知都可以使用*      @Pointcut(value = "execution(* com.example.spring.aop.demo.anno.service.impl.UserServiceImpl.*(..))")*      等同于 xml 配置里的:*      <aop:pointcut id="log_pc" expression="execution(* com.example.spring.aop.demo.anno.service.impl.UserServiceImpl.*(..))"/>*/@Pointcut(value = "execution(* com.example.spring.aop.demo.anno.service.impl.UserServiceImpl.*(..))")public void log_pc() {}@Before("log_pc()")public void beforeMethod(JoinPoint joinPoint) {LOGGER.trace("前置通知...");System.out.println("本次要调用的目标对象:" + joinPoint.getTarget());System.out.println("本次要调用的目标方法名:" + joinPoint.getSignature().getName());System.out.println("本次要调用的目标方法参数:" + Arrays.toString(joinPoint.getArgs()));}@AfterReturning(value = "log_pc()", returning = "obj")public void afterReturn(Object obj) {LOGGER.trace("目标方法返回后, 返回对象结果是:" + obj);}@After("log_pc()")public void afterMethod() {LOGGER.trace("后置通知...");}/** 声明一个切入点表达式,此表达式只能当前通知使用*      @Around("execution(* com.example.spring.aop.demo.anno.service.impl.UserServiceImpl.*(..))")*      等同于 xml 配置里的:*      <aop:around method="aroundMethod" pointcut="execution(* com.example.spring.aop.demo.anno.service.impl.UserServiceImpl.*(..))" />*/@Around("execution(* com.example.spring.aop.demo.anno.service.impl.UserServiceImpl.*(..))")public Object aroundMethod(ProceedingJoinPoint pjp) {Object result = null;LOGGER.warn("前置通知!!!");try {result = pjp.proceed();} catch (Throwable e) {
//            e.printStackTrace();LOGGER.warn("异常通知!!!");throw new RuntimeException(e);}LOGGER.warn("后置通知!!!");return result;}
}

创建 spring-context-anno.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.example.spring.aop.demo.anno"/><!-- 开启aop动态代理 --><aop:aspectj-autoproxy/></beans>

创建 AopTest_Anno 测试类

package com.example.spring.aop.demo;import com.example.spring.aop.demo.xml.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-context-anno.xml")
public class AopTest_Anno {@Autowiredprivate UserService userService;@Testpublic void annoTest() {userService.addUser();System.out.println();boolean b = userService.updateUser();System.out.println();int i = userService.deleteUser(10);System.out.println();}
}

测试结果:

3

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

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

相关文章

MYSQL从入门到精通(二)

1、MYSQL高级概述 【1】架构概述 【2】索引优化 【3】查询截取 【4】mysql锁机制 【5】主从复制 2、MYSQL概述 【1】mysql内核 【2】sql优化工程师 【3】mysql服务器的优化 【4】各种参数常量设定 【5】查询语句优化 【6】主从复制 【7】软硬件升级 【8】容灾百分 【9】sql编…

使用Neo4j和Langchain创建知识图谱

使用Neo4j和Langchain创建知识图谱 知识图谱是组织和整合信息的强大工具。通过使用实体作为节点和关系作为边缘&#xff0c;它们提供了一种系统的知识表示方法。这种有条理的表示有利于简化查询、分析和推理&#xff0c;使知识图在搜索引擎、推荐系统、自然语言处理和人工智能…

从0开始学习制作一个微信小程序 学习部分(6)组件与事件绑定

系列文章目录 学习篇第一篇我们讲了编译器下载&#xff0c;项目、环境建立、文件说明与简单操作&#xff1a;第一篇链接 第二、三篇分析了几个重要的配置json文件&#xff0c;是用于对小程序进行的切换页面、改变图标、控制是否能被搜索到等的操作第二篇链接、第三篇链接 第四…

Windows设置Redis为开机自启动

前言 Redis作为当前最常用的当前缓存技术&#xff0c;基本上Web应用中都有使用。所以&#xff0c;每次我们在本地启动项目前&#xff0c;都必须将Redis服务端启动&#xff0c;否则项目就会启动失败。但是&#xff0c;每次都要去启动Redis就很麻烦&#xff0c;有没有办法做到开…

Python爬虫--爬取糗事百科段子

爬取糗事百科段子&#xff1a; 段子在 <div class"content"> 里面的 <span> 标签里面 不过这里有个坑&#xff0c;div 标签跟 span 标签 之间有很多空行 普通 .*? 是匹配不了的&#xff0c;需要使用模式修饰符 S S 的意思 让 .(点) 匹配&#xff0c…

吴恩达2022机器学习专项课程(一)正则化(正则化成本函数正则化线性回归正则化逻辑回归)

目录 一.正则化1.1 正则化的好处1.2 正则化的实现方式 二.正则化改进线性回归的成本函数2.1 正则化后的成本函数的意义2.2 λ参数的作用2.3 不同λ对算法的影响2.4 为什么参数b没有正则化项 三.正则化线性回归的梯度下降3.1 为什么正则化可以在梯度下降迭代中减小w3.2 导数的计…

机器学习笔记-18

异常检测问题 异常检测虽然主要用于无监督学习问题上&#xff0c;但是和监督学习问题很相似。 异常检测(Anomaly Detection)&#xff1a;给定正确样本集{ x ( 1 ) , x ( 2 ) . . . x ( n ) x^{(1)},x^{(2)}...x^{(n)} x(1),x(2)...x(n)}&#xff0c;记新样本即要检测的样本为…

eNSP-抓包解析HTTP、FTP、DNS协议

一、环境搭建 1.http服务器搭建 2.FTP服务器搭建 3.DNS服务器搭建 二、抓包 三、http协议 1.HTTP协议&#xff0c;建立在FTP协议之上 2.http请求 3.http响应 请求响应报文参考&#xff1a;https://it-chengzi.blog.csdn.net/article/details/113809803 4.浏览器开发者工具抓包…

002-ChatGLM4接入Langchain

智谱AI GLM-4 新一代基座大模型GLM-4,整体性能相比GLM3全面提升60%,逼近GPT-4;支持更长上下文;更强的多模态;支持更快推理速度,更多并发,大大降低推理成本;同时GLM-4增强了智能体能力。 基础能力(英文):GLM-4 在 MMLU、GSM8K、MATH、BBH、HellaSwag、HumanEval等…

ubuntu搭建jupyter_notebook服务器

环境&#xff1a;ubuntu 22.04 目录 环境&#xff1a;ubuntu 22.04 一、创建一个anaconda用户 创建用户condaUser 为用户condaUser设置密码 开放opt文件夹的权限 登录condaUser用户 二、安装anaconda 下载anaconda 安装anaconda 三、添加环境变量 四、anaconda换源 …

【Unity Shader入门精要 第4章】数学基础(二)

1. Unity中的坐标空间 1.1 五个坐标空间 模型空间 模型自身的3D坐标系空间&#xff0c;左手坐标系是一个相对空间&#xff0c;坐标轴指向随模型旋转变化当物体有父节点时&#xff0c;Transform组件中各属性的值表示的即为该物体在其父物体的模型空间中的值当模型顶点传入顶点…

ARP防火墙能够为网络安全贡献什么样的力量

ARP防火墙&#xff08;Address Resolution Protocol Firewall&#xff09;作为网络安全的一环&#xff0c;起到保护网络免受ARP欺骗攻击的关键作用。今天德迅云安全给您介绍ARP防火墙的相关方面&#xff0c;帮助您深入了解和认识这一关键的安全措施。 网络安全对于现代社会的信…

「 网络安全常用术语解读 」SBOM主流格式CycloneDX详解

CycloneDX是软件供应链的现代标准。CycloneDX物料清单&#xff08;BOM&#xff09;可以表示软件、硬件、服务和其他类型资产的全栈库存。该规范由OWASP基金会发起并领导&#xff0c;由Ecma International标准化&#xff0c;并得到全球信息安全界的支持&#xff0c;如今CycloneD…

Java——认识异常

目录 一.异常的概念与体系结构 1.异常的概念 1.1算术异常 1.2数组越界异常 1.3空指针异常 2.异常的体系结构 3.异常的分类 3.1编译时异常 3.2运行时异常 二.异常的处理 1.防御式编程 1.1LBYL 1.2EAFP&#xff08;核心&#xff09; 2.异常的抛出 3.异常的捕获 3…

使用 ORPO 微调 Llama 3

原文地址&#xff1a;https://towardsdatascience.com/fine-tune-llama-3-with-orpo-56cfab2f9ada 更便宜、更快的统一微调技术 2024 年 4 月 19 日 ORPO 是一种新的令人兴奋的微调技术&#xff0c;它将传统的监督微调和偏好校准阶段合并为一个过程。这减少了训练所需的计算…

【深度学习】第二门课 改善深层神经网络 Week 2 3 优化算法、超参数调试和BN及其框架

&#x1f680;Write In Front&#x1f680; &#x1f4dd;个人主页&#xff1a;令夏二十三 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;深度学习 &#x1f4ac;总结&#xff1a;希望你看完之后&#xff0c;能对…

python实现验证码-图片类型

1 utils.py import randomdef get_random_code():code for i in range(5):# 随机生成大写字母upper_char chr(random.randint(65, 90))lower_char chr(random.randint(97, 122))num_char str(random.randint(0, 9))res random.choice([upper_char, lower_char, num_char]…

软件应用开发安全设计指南

1.1 应用系统架构安全设计要求 设计时要充分考虑到系统架构的稳固性、可维护性和可扩展性&#xff0c;以确保系统在面对各种安全威胁时能够稳定运行。 在设计系统架构时&#xff0c;要充分考虑各种安全威胁&#xff0c;如DDoS攻击、SQL注入、跨站脚本攻击&#xff08;XSS&…

如何使用 Node.js 开发一个文件上传功能?

在 Node.js 中实现文件上传功能可以通过多种方式完成&#xff0c;但其中最常用的方法之一是使用 Express 框架和 Multer 中间件。Express 是一个流行的 Node.js Web 框架&#xff0c;而 Multer 是一个用于处理文件上传的中间件。 步骤 1: 准备工作 首先&#xff0c;确保你已经…

《Fundamentals of Power Electronics》——升压隔离型变换器、SEPIC隔离型变换器

以下是升压型隔离变换器的相关知识点&#xff1a; 升压型隔离变换器可以通过互换降压型隔离变换器的电源与负载的位置得到。升压型隔离变换器有许多种结构&#xff0c;此处简短的讨论两种情况。这些转换器主要使用在高压电源和低谐波整流器中。 图6.36所示是一种全桥型电路结…