当前位置: 首页 > news >正文

企业级信息系统开发学习笔记1.5 初探Spring AOP

文章目录

  • 零、本讲学习目标
  • 一、Spring AOP
    • (一)AOP基本含义
    • (二)AOP基本作用
    • (三)AOP与OOP对比
    • (四)AOP使用方式
    • (五)AOP基本概念
  • 二、提出游吟诗人唱赞歌任务
    • (一)采用传统方式实现
    • (二)采用传统方式实现的缺点
  • 三、采用配置方式使用AOP
    • (一)创建本讲所需子包
    • (二)创建杀龙任务类
    • (三)创建勇敢骑士类
    • (四)创建游吟诗人类
    • (五)创建Spring配置文件
      • 1、切点
      • 2、切点表达式
      • 3、切点函数
    • (六)在pom文件里添加AOP相关依赖
    • (七)创建测试类 - TestKnight
    • (八)运行测试方法testBraveKnight(),查看结果
    • (九)课堂练习
      • 1、增加救美任务类与救美骑士类
      • 2、在测试类里增加测试方法 - testDamselRescuingKnight()
      • 3、运行testDamselRescuingKnight()方法,查看结果
  • 四、采用注解方式使用AOP
    • (一)创建本讲所需子包
    • (二)创建杀龙任务类
    • (三)创建勇敢骑士类
    • (四)创建游吟诗人切面
    • (五)创建Spring配置类
    • (六)创建骑士测试类
    • (七)运行测试方法testBraveKnight(),查看效果
    • (八)课堂练习
      • 1、增加救美任务类与救美骑士类
      • 2、在测试类里增救美骑士测试方法 - testDamselRescuingKnight()
      • 3、运行testDamselRescuingKnight()方法,查看结果
  • 四、实现注解式拦截
    • (一)拦截的含义
    • (二)创建注解接口
      • 1、@Target({ElementType.TYPE}) 注解
      • 2、 @Retention({RetentionPolicy.Runtime}) 注解
      • 3、@Documented注解
    • (三)修改勇敢骑士类
    • (四)修改游吟诗人切面
    • (五)运行测试方法testBraveKnight(),查看效果
    • (五)修改救美骑士类,给embarkOnQuest()添加自定义注解Action
    • (六)运行测试方法testDamselRescuingKnight(),查看效果
    • (七)课堂练习
      • 任务:输出骑士完成任务的耗时

零、本讲学习目标

  1. 理解AOP与OOP的关系
  2. 掌握采用配置方式使用AOP
  3. 掌握采用注解方式使用AOP

一、Spring AOP

(一)AOP基本含义

  • AOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。
  • OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
  • AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
  • AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

(二)AOP基本作用

  • 软件开发原则:高内聚,低耦合
  • Spring的AOP作用在于解耦。AOP让一组类共享相同的行为(比如事务管理、日志管理、安全管理)。
  • OOP(Object-Oriented Programming)只能通过继承类或实现接口来增加代码的耦合度,而且类继承是单根继承(不允许一子多父),阻碍了将更多的行为添加到一组类上,此时AOP可以弥补OOP的不足。

(三)AOP与OOP对比

  • AOP(Aspect-Oriented Programming)—— 横向的关系
  • OOP(Object-Oriented Programming)—— 纵向的关系
    在这里插入图片描述

(四)AOP使用方式

  1. Spring采用配置方式使用AOP
  2. Spring采用注解方式使用AOP

(五)AOP基本概念

  1. Aspect(切面):通常是一个类,里面可以定义切入点和通知
  2. JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
  3. Advice(通知):AOP在特定的切入点上执行的增强处理,有before、after、after-returning、after-throwing、around
  4. Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
  5. AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

二、提出游吟诗人唱赞歌任务

  • 骑士执行任务前和执行任务后,游吟诗人唱赞歌

(一)采用传统方式实现

  • 修改day04子包的勇敢骑士类
    在这里插入图片描述

  • 修改day04子包里的救美骑士类
    在这里插入图片描述

  • 执行测试类 - TestKnight
    在这里插入图片描述

(二)采用传统方式实现的缺点

  • 每个骑士类的embarkOnQuest()方法都要修改,耦合度太高,当骑士类数量很大时,这个任务完成起来就十分枯燥繁琐。

下面我们采用AOP方式来实现同样的功能,大家通过对比可以更好地体会采用AOP方式的优越性。

三、采用配置方式使用AOP

(一)创建本讲所需子包

  • 在net.hw.spring包里创建lesson05.aop_xml子包
    在这里插入图片描述

(二)创建杀龙任务类

  • 在aop_xml子包里创建杀龙任务类 - SlayDragonQuest
    在这里插入图片描述
package net.hw.spring.lesson05.aop_xml;import org.springframework.stereotype.Component;/*** 功能:杀龙任务类* 作者:华卫* 日期:2021年03月24日*/
@Component
public class SlayDragonQuest {public void embark() {System.out.println("执行杀龙任务。");}
}

(三)创建勇敢骑士类

  • 在aop_xml子包里创建勇敢骑士类 - BraveKnight
    在这里插入图片描述
package net.hw.spring.lesson05.aop_xml;/*** 功能:勇敢骑士类* 作者:华卫* 日期:2021年03月24日*/import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component("Mike")
public class BraveKnight {@Autowiredprivate SlayDragonQuest slayDragonQuest;public void embarkOnQuest() {slayDragonQuest.embark();}
}

(四)创建游吟诗人类

  • 在aop_xml子包里创建游吟诗人类 - Minstrel
    在这里插入图片描述
package net.hw.spring.lesson05.aop_xml;import org.springframework.stereotype.Component;/*** 功能:游吟诗人类* 作者:华卫* 日期:2021年03月24日*/
@Component
public class Minstrel {public void singBeforeQuest() {System.out.println("啦啦啦,骑士出发了!");}public void singAfterQuest() {System.out.println("真棒啊!骑士完成了任务!");}
}

(五)创建Spring配置文件

  • 在resources里创建aop_xml目录,在里面创建spring-config.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:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><!--组件扫描--><context:component-scan base-package="net.hw.spring.lesson05.aop_xml"/><!--AOP配置--><aop:config><!--定义切面--><aop:aspect ref="minstrel"><!--定义切点--><aop:pointcut id="embark" expression="execution(* net.hw.spring.lesson05..*.embarkOnQuest(..))"/><!--声明前置通知--><aop:before method="singBeforeQuest" pointcut-ref="embark"/><!--声明后置通知--><aop:after method="singAfterQuest" pointcut-ref="embark"/></aop:aspect></aop:config>
</beans>

在这里插入图片描述

1、切点

在使用Spring框架配置AOP时,不管是通过XML配置文件还是注解方式,都需要定义pointcut(切点)。

2、切点表达式

  • 拦截类里的指定方法:"execution(* net.hw.spring.lesson05..*.embarkOnQuest(..))"
  • 拦截类里的所有方法:"execution(* net.hw.spring.lesson05..*.*(..))"

3、切点函数

execution()是最常用的切点函数,整个表达式可以分为五个部分。

  • execution():表达式主体。
  • 第一个*号:表示返回类型,*号表示所有的类型。
  • 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,net.hw.spring.lesson05包、子孙包下所有类的方法。
  • 第二个*号:表示类名,*号表示所有的类。
  • *(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。

(六)在pom文件里添加AOP相关依赖

在这里插入图片描述

<!--Spring AOP-->                                         
<dependency>                                              <groupId>org.springframework</groupId>                <artifactId>spring-aop</artifactId>                   <version>${spring.version}</version>                  
</dependency>                                             
<!--AspectJ支持-->                                          
<dependency>                                              <groupId>aspectj</groupId>                            <artifactId>aspectjrt</artifactId>                    <version>1.5.4</version>                              
</dependency>                                             
<dependency>                                              <groupId>org.aspectj</groupId>                        <artifactId>aspectjweaver</artifactId>                <version>1.9.6</version>                              <scope>runtime</scope>                                
</dependency>                                             
  • 注意:添加新的依赖之后,记得更新
    在这里插入图片描述

(七)创建测试类 - TestKnight

  • 在test/java里创建net.hw.spring.lesson05.aop_xml包,在包里创建TestKnight
    在这里插入图片描述
package net.hw.spring.lesson05.aop_xml;import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** 功能:测试骑士类* 作者:华卫* 日期:2021年03月24日*/
public class TestKnight {private ClassPathXmlApplicationContext context; // 基于类路径XML配置文件的应用容器@Beforepublic void init() {// 基于Spring配置文件创建应用容器context = new ClassPathXmlApplicationContext("aop_xml/spring-config.xml");}@Testpublic void testBraveKnight() {// 根据名称从应用容器中获取勇敢骑士对象BraveKnight braveKnight = (BraveKnight) context.getBean("Mike");// 勇敢骑士执行任务braveKnight.embarkOnQuest();}@Afterpublic void destroy() {// 关闭应用容器context.close();}
}

(八)运行测试方法testBraveKnight(),查看结果

在这里插入图片描述

(九)课堂练习

1、增加救美任务类与救美骑士类

在这里插入图片描述

2、在测试类里增加测试方法 - testDamselRescuingKnight()

在这里插入图片描述

3、运行testDamselRescuingKnight()方法,查看结果

在这里插入图片描述

四、采用注解方式使用AOP

(一)创建本讲所需子包

  • 在net.hw.spring包里创建lesson05.aop_annotation子包
    在这里插入图片描述

(二)创建杀龙任务类

  • 在aop_annotation子包里创建杀龙任务类 - SlayDragonQuest
    在这里插入图片描述
package net.hw.spring.lesson05.aop_annotation;import org.springframework.stereotype.Component;/*** 功能:杀龙任务类* 作者:华卫* 日期:2021年03月29日*/
@Component
public class SlayDragonQuest {public void embark() {System.out.println("执行杀龙任务。");}
}

(三)创建勇敢骑士类

  • 在aop_annotation子包里创建勇敢骑士类 - BraveKnight
  • 在这里插入图片描述
package net.hw.spring.lesson05.aop_annotation;/*** 功能:勇敢骑士类* 作者:华卫* 日期:2021年03月29日*/import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component("Mike")
public class BraveKnight {@Autowiredprivate SlayDragonQuest slayDragonQuest;public void embarkOnQuest() {slayDragonQuest.embark();}
}

(四)创建游吟诗人切面

  • 在aop_annotation子包里创建游吟诗人切面 - MinstrelAspect
    在这里插入图片描述

在这里插入图片描述

package net.hw.spring.lesson05.aop_annotation;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;/*** 功能:游吟诗人切面* 作者:华卫* 日期:2021年03月29日*/
@Aspect // 声明为切面
@Component // 交给Spring容器管理
public class MinstrelAspect {// 注解声明切点@Pointcut("execution(* net.hw.spring.lesson05..*.embarkOnQuest(..))")public void embark() {}// 注解声明前置通知@Before("embark()")public void singBeforeQuest(JoinPoint joinPoint) {System.out.println("啦啦啦,骑士出发了!");}// 注解声明后置通知@After("embark()")public void singAfterQuest(JoinPoint joinPoint) {System.out.println("真棒啊!骑士完成了任务!");}
}

(五)创建Spring配置类

  • 在aop_annotation子包里创建Spring配置类 - AopConfig
    在这里插入图片描述
package net.hw.spring.lesson05.aop_annotation;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;/*** 功能:AOP配置类* 作者:华卫* 日期:2021年03月29日*/
@Configuration // 标明Spring配置类
@ComponentScan("net.hw.spring.lesson05.aop_annotation") // 组件扫描
@EnableAspectJAutoProxy // 开启Spring对AspectJ的支持
public class AopConfig {
}

(六)创建骑士测试类

  • 在test/java/aop_annotation子包里创建测试类 - TestKnight
    在这里插入图片描述
package net.hw.spring.lesson05.aop_annotation;import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;/*** 功能:测试骑士类* 作者:华卫* 日期:2021年03月29日*/
public class TestKnight {private AnnotationConfigApplicationContext context; // 基于注解配置类的应用容器@Beforepublic void init() {// 基于注解配置类创建应用容器context = new AnnotationConfigApplicationContext(AopConfig.class);}@Testpublic void testBraveKnight() {// 根据名称从应用容器里获取勇敢骑士对象BraveKnight knight = (BraveKnight) context.getBean("Mike");// 勇敢骑士执行任务knight.embarkOnQuest();}@Afterpublic void destroy() {// 关闭应用容器context.close();}
}

(七)运行测试方法testBraveKnight(),查看效果

在这里插入图片描述

(八)课堂练习

1、增加救美任务类与救美骑士类

在这里插入图片描述

2、在测试类里增救美骑士测试方法 - testDamselRescuingKnight()

在这里插入图片描述

3、运行testDamselRescuingKnight()方法,查看结果

在这里插入图片描述

四、实现注解式拦截

(一)拦截的含义

在某个方法被访问之前进行拦截,然后在方法执行之前或之后加入某些操作,其实就是AOP的一种实现策略。Spring提供拦截器(Interceptor),它通过动态拦截Action调用的对象,允许开发者定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。本案例,我们不用拦截器,学习注解式拦截。

(二)创建注解接口

  • 在aop_annotation子包里创建注解接口 - Action
    在这里插入图片描述
    在这里插入图片描述
package net.hw.spring.lesson05.aop_annotation;import java.lang.annotation.*;/*** 功能:动作注解接口* 作者:华卫* 日期:2021年03月29日*/
@Target(ElementType.METHOD) // 拦截目标 - 方法
@Retention(RetentionPolicy.RUNTIME) // 保留策略 - 运行时
@Documented // 注解文档化
public @interface Action {String name();
}

1、@Target({ElementType.TYPE}) 注解

  • ElementType 这个枚举类型的常量提供了一个简单的分类:注解可能出现在Java程序中的语法位置(这些常量与元注解类型(@Target)一起指定在何处写入注解的合法位置)

2、 @Retention({RetentionPolicy.Runtime}) 注解

  • RetentionPolicy这个枚举类型的常量描述保留注解的各种策略,它们与元注解(@Retention)一起指定注释要保留多长时间

3、@Documented注解

  • Documented注解表明这个注解是由 javadoc记录的,在默认情况下也有类似的记录工具。 如果一个类型声明被注解了文档化,它的注解成为公共API的一部分。

(三)修改勇敢骑士类

  • 给embarkOnQuest()添加自定义注解Action,并设置其name属性
    在这里插入图片描述
package net.hw.spring.lesson05.aop_annotation;/*** 功能:勇敢骑士类* 作者:华卫* 日期:2021年03月29日*/import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component("Mike")
public class BraveKnight {@Autowiredprivate SlayDragonQuest slayDragonQuest;@Action(name = "动作拦截器")public void embarkOnQuest() {slayDragonQuest.embark();}
}

(四)修改游吟诗人切面

在这里插入图片描述

package net.hw.spring.lesson05.aop_annotation;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;/*** 功能:游吟诗人切面* 作者:华卫* 日期:2021年03月29日*/
@Aspect // 声明为切面
@Component // 交给Spring容器管理
public class MinstrelAspect {// 注解声明切点@Pointcut("@annotation(net.hw.spring.lesson05.aop_annotation.Action)")public void embark() {}// 注解声明前置通知@Before("embark()")public void singBeforeQuest(JoinPoint joinPoint) {// 获取方法签名MethodSignature signature = (MethodSignature) joinPoint.getSignature();// 获取被拦截的方法Method method = signature.getMethod();// 获取注解式拦截Action action = method.getAnnotation(Action.class);// 提示用户被拦截了System.out.println("[" + action.name() + "]拦截了[" + method.getName() + "]:拦截前!");System.out.println("啦啦啦,骑士出发了!");}// 注解声明后置通知@After("embark()")public void singAfterQuest(JoinPoint joinPoint) {// 获取方法签名MethodSignature signature = (MethodSignature) joinPoint.getSignature();// 获取被拦截的方法Method method = signature.getMethod();// 获取注解式拦截Action action = method.getAnnotation(Action.class);// 提示用户被拦截了System.out.println("[" + action.name() + "]拦截了[" + method.getName() + "]:拦截后!");System.out.println("真棒啊!骑士完成了任务!");}
}

(五)运行测试方法testBraveKnight(),查看效果

在这里插入图片描述

(五)修改救美骑士类,给embarkOnQuest()添加自定义注解Action

在这里插入图片描述

(六)运行测试方法testDamselRescuingKnight(),查看效果

在这里插入图片描述

(七)课堂练习

任务:输出骑士完成任务的耗时

  • 创建耗时切面类 - ElapseAspect
    在这里插入图片描述

  • 运行测试方法testBraveKnight(),查看效果
    在这里插入图片描述

  • 运行测试方法testDamselRescuingKnight(),查看效果
    在这里插入图片描述

  • 只让耗时切面起作用,查看运行结果
    在这里插入图片描述

相关文章:

企业级信息系统开发学习笔记1.5 初探Spring AOP

文章目录零、本讲学习目标一、Spring AOP&#xff08;一&#xff09;AOP基本含义&#xff08;二&#xff09;AOP基本作用&#xff08;三&#xff09;AOP与OOP对比&#xff08;四&#xff09;AOP使用方式&#xff08;五&#xff09;AOP基本概念二、提出游吟诗人唱赞歌任务&#…...

Mysql数据库主主从设置

注意&#xff1a;在同一台服务器上部署主从或主主之类的时候&#xff0c;数据库data下有一个auto.cnf里的uuid不能重复。 原则&#xff1a;做同步之前要保证两个数据库数据一致. 锁表操作&#xff1a; FLUSH TABLES WITH READ LOCK; 注&#xff1a;没有锁定主服务器&#xf…...

监管持续,医疗卫生机构如何守好“涉疫”数据安全?

肆虐三年的新冠疫情&#xff0c;影响着全球经济发展、社会正常运行&#xff0c;也成为网络攻击、勒索软件攻击快速增长的温床&#xff0c;“滋生”了一系列网络、数据安全问题&#xff0c;受到各界关注。最近&#xff0c;上线运行三年的 “粤康码”发布公告、官宣部分服务下线&…...

STM32开发(13)----获取唯一设备标识符UID

获取唯一设备标识符UID前言一、什么事UID二、实验过程1.CubeMx配置2.代码实现3.实验结果总结前言 这一章节介绍如何获取STM32芯片中的唯一的ID号的两种方法。 一、什么事UID 在许多项目中&#xff0c;识别设备是必要的。从简单的设备描述到更复杂的设备&#xff0c;如 USB 串…...

华为OD机试 - 最优调度策略(Python) | 机试题+算法思路+考点+代码解析 【2023】

最优调度策略 题目 在通信系统中有一个常见的问题是对用户进行不同策略的调度 会得到不同系统消耗的性能 假设由 N 个待串行用户,每个用户可以使用 A/B/C 三种不同的调度策略 不同的策略会消耗不同的系统资源 请你根据如下规则进行用户调度 并返回总的消耗资源数 规则是:相…...

前端零基础入门-002-集成开发环境

本篇目标 了解市面上常用的前端集成开发环境&#xff08;ide&#xff09;掌握 HBuiberX 的使用&#xff1a;下载安装&#xff0c;新建项目、网页、运行网页。 内容摘要 本篇介绍了市面上流行的几款前端集成开发环境&#xff08;ide&#xff09;&#xff0c;并介绍了 Hbuilde…...

su和sudo的区别

linux中 su和sudo的区别 su和sudo是两个常用的切换到root超级用户命令。功能上类似&#xff0c;但使用上还是有不少差异。 su命令 su是切换到root用户的命令&#xff0c;主要用法如下&#xff1a; su&#xff1a;不带参数直接输入su将切换到root用户&#xff0c;需要输入root…...

【ChatGPT】使用ChatGPT进行51单片机程序编程体验

背景 最近ChatGPT大火&#xff0c;笔者尝试使用它进行了51单片机编程尝试。ChatGPT是一种由OpenAI训练的大型语言模型&#xff0c;具有强大的自然语言处理能力和生成代码的能力。 使用ChatGPT进行51单片机编程&#xff0c;笔者发现它可以帮助开发人员快速生成符合要求的代码&a…...

Docker之路(1.Docker概述、组成以及特点)

1.docker为什么会出现&#xff1f; 一款产品或者项目来说&#xff0c;一般有三个环境&#xff0c;日常/测试环境、预发环境、正式/线上环境 这么多环境&#xff0c;对其环境的配置是十分麻烦的&#xff0c;每一个机器都要部署环境&#xff0c;有的会有集群Redis、Hadoop等&…...

非对称加密算法在android的应用

前言android 系统安全内容总结 4、非对称加密算法应用 主要特性包括secure boot、AVB、OTA包签名、apk签名、apex、ko签名; 除此外上层应用keystore服务、涉及TEEOS非对称算法的功能安全会用到。属于功能安全本章节暂不描述。 4.1、secboot+avb secboot+avb属于安全启动参照…...

51单片机——定时器中断实验,小白讲解,相互学习

定时器介绍 1&#xff0c;CPU时序的有关知识 震荡周期&#xff1a;为单片机提供定时信号的震荡源的周期&#xff08;晶振周期或外加震荡周期&#xff09;。状态周期&#xff1a;2个震荡周期为1个状态周期&#xff0c;用S表示。震荡周期又称S周期或时钟周期。机器周期&#xff…...

什么是循环依赖,spring是如何去解决循环依赖问题的?什么是三级缓存?【spring】

文章目录什么是循环依赖&#xff1f;什么是三级缓存&#xff1f;执行流程什么是循环依赖&#xff1f; 在我们的开发中&#xff0c;会不可避免的遇到Bean之间循环依赖的&#xff0c;所谓循环依赖&#xff0c;就是两个或者两个以上的Bean互相持有对方&#xff0c;这样在程序运行…...

Cron表达式

网上搜一下就有在线生成网站&#xff0c;很方便。 比如&#xff1a;Cron表达式生成器 用途 定时调度任务&#xff0c;比如说服务器、云函数中定时执行脚本函数。 Cron 表达式构成 Cron 表达式是字符串&#xff0c;一般由 6 - 7 个字段构成&#xff0c;空格分隔。每个字段代…...

JavaScript 作用域

作用域是可访问变量的集合。在JavaScript中&#xff0c;能够定义全局作用域或者局部作用域。在 JavaScript 中, 对象和函数同样也是变量。在 JavaScript 中, 作用域为可访问变量&#xff0c;对象&#xff0c;函数的集合。JavaScript 函数作用域: 作用域在函数内修改。JavaScrip…...

Hive内部表与外部表的区别具体说明

目录 1.在/opt/atguigu/目录下&#xff0c;新建两个txt文件 2.在hadoop的web端递归创建一个目录&#xff0c;存储这两个文件 3.查看web端的文件 一、内部表&#xff1a; 1.创建一个内部表&#xff0c;并指定内部表的存储位置 2.查看内部表&#xff0c;内部表中没有数据 …...

Java流程控制

目录 前言 一、用户交互Scanner及其进阶使用 输入的数据为字符串类型 输入的数据为整型或者浮点型 练习 二、顺序结构 三、选择结构 if单选泽结构 if双选择结构 if多选择结构 嵌套的if结构 switch多选择结构 四、循环结构 while循环 Do...while循环 For循环 练习 利用for循环…...

I.MX6ULL_Linux_系统篇(17) uboot分析-启动linux

bootz 启动 Linux 内核 images 全局变量 不管是 bootz 还是 bootm 命令&#xff0c;在启动 Linux 内核的时候都会用到一个重要的全局变量&#xff1a;images&#xff0c; images 在文件 cmd/bootm.c 中有如下定义&#xff1a; images 是 bootm_headers_t 类型的全局变量&…...

C/C++每日一练(20230221)

目录 1. 格雷编码 2. 矩阵问题 3. 搜索旋转排序数组 II 1. 格雷编码 格雷编码是一个二进制数字系统&#xff0c;在该系统中&#xff0c;两个连续的数值仅有一个位数的差异。 给定一个代表编码总位数的非负整数 n&#xff0c;打印其格雷编码序列。即使有多个不同答案&#…...

用Python采集热门城市景点数据并简单制作数据可视化图

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 模块使用&#xff1a; 爬虫部分: requests parsel csv 数据分析部分: pandas pyecharts 如何安装模块: win R 输入 cmd 输入安装命令&#xff1a; pip install 模块名 回车 pycharm里面安装 terminal 输入安装命令…...

论文阅读:pixelNeRF: Neural Radiance Fields from One or Few Images

中文标题&#xff1a;从一或少量图像中构建神经辐射场 提出问题 NeRF效果虽然惊艳&#xff0c;但是其需要大量环绕图像以及长时间的训练。 创新点 与原始的NeRF网络不使用任何图像特征不同&#xff0c;pixelNeRF将与每个像素对齐的空间图像特征作为输入。也可以集合更多输入…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...