(十五)Spring之面向切面编程AOP

news2025/7/20 23:58:09

文章目录

  • 基础环境
  • AOP介绍
  • AOP的七大术语
  • 切点表达式
  • Spring的AOP的使用
    • 环境准备
    • 基于AspectJ的AOP注解式开发
      • 通知类型
        • 前置通知@Before
        • 后置通知@AfterReturning
        • 环绕通知@Around
        • 异常通知@AfterThrowing
        • 最终通知@After
        • 关于JoinPoint
      • 切面的先后顺序
      • 通用切点表达式
      • 全注解式开发AOP
    • 基于XML配置方式的AOP(了解)

上一篇:(十四)Spring之回顾代理模式

IoC使软件组件松耦合。AOP让你能够捕捉系统中经常使用的功能,把它转化成组件。
AOP(Aspect Oriented Programming):面向切面编程,面向方面编程。(AOP是一种编程技术)
AOP是对OOP的补充延伸。
AOP底层使用的就是动态代理来实现的。
Spring的AOP使用的动态代理是:JDK动态代理 + CGLIB动态代理技术。Spring在这两种动态代理中灵活切换,如果是代理接口,会默认使用JDK动态代理,如果要代理某个类,这个类没有实现接口,就会切换使用CGLIB。当然,你也可以强制通过一些配置让Spring只使用CGLIB。

基础环境

spring6里程碑版本的仓库
依赖:spring context依赖、junit依赖、log4j2依赖
log4j2.xml文件放到类路径下。

AOP介绍

一般一个系统当中都会有一些系统服务,例如:日志、事务管理、安全等。这些系统服务被称为:交叉业务
这些交叉业务几乎是通用的,不管你是做银行账户转账,还是删除用户数据。日志、事务管理、安全,这些都是需要做的。
如果在每一个业务处理过程当中,都掺杂这些交叉业务代码进去的话,存在两方面问题:

  • 第一:交叉业务代码在多个业务流程中反复出现,显然这个交叉业务代码没有得到复用。并且修改这些交叉业务代码的话,需要修改多处。
  • 第二:程序员无法专注核心业务代码的编写,在编写核心业务代码的同时还需要处理这些交叉业务。

使用AOP可以很轻松的解决以上问题。
在这里插入图片描述
总结AOP:将与核心业务无关的代码独立的抽取出来,形成一个独立的组件,然后以横向交叉的方式应用到业务流程当中的过程被称为AOP。

AOP的优点:

  • 第一:代码复用性增强。
  • 第二:代码易维护。
  • 第三:使开发者更关注业务逻辑。

AOP的七大术语

  • 1.连接点 Joinpoint:描述的是位置
    在程序的整个执行流程中,可以织入切面的位置。方法的执行前后,异常抛出之后等位置。

  • 2.切点 Pointcut:本质上就是方法
    在程序执行流程中,真正织入切面的方法。(一个切点对应多个连接点)

  • 3.通知 Advice:本质上就是增强代码

    通知又叫增强,就是具体你要织入的代码。
    通知包括:

    • 前置通知:切点(方法)之前
    • 后置通知:切点(方法)之后
    • 环绕通知:前置后置都有通知
    • 异常通知:catch里面
    • 最终通知:finally里面
  • 4.切面 Aspect
    切点 + 通知就是切面。

  • 5.织入 Weaving
    把通知应用到目标对象上的过程。

  • 6.代理对象 Proxy
    一个目标对象被织入通知后产生的新对象。

  • 7.目标对象 Target
    被织入通知的对象。

代码体现:

public class UserService{
    public void do1(){
        System.out.println("do 1");
    }
    public void do2(){
        System.out.println("do 2");
    }
    public void do3(){
        System.out.println("do 3");
    }
    public void do4(){
        System.out.println("do 4");
    }
    public void do5(){
        System.out.println("do 5");
    }
    // 核心业务方法
    public void service(){
        try {
            //连接点 Joinpoint
            // 对于do1()来说 前置通知
            do1();//切点 Pointcut  (1)前置通知和后置通知都有叫环绕通知    (2)这一整个叫做切面(切点+通知)
            // 对于do1()来说 后置通知
            //连接点 Joinpoint

            do2();//切点 Pointcut
            //连接点 Joinpoint
            do3();//切点 Pointcut
            //连接点 Joinpoint
            do5();//切点 Pointcut
            //连接点 Joinpoint
        }catch (Exception e){
            //连接点 Joinpoint   异常通知

        }finally {
            //连接点 Joinpoint  最终通知
        }
    }
}

切点表达式

切点表达式用来定义通知(Advice)往哪些方法上切入。
切入点表达式语法格式:

execution([访问控制权限修饰符] 返回值类型 [全限定类名]方法名(形式参数列表) [异常])

访问控制权限修饰符:

  • 可选项。
  • 没写,就是4个权限都包括。
  • 写public就表示只包括公开的方法。

返回值类型:

  • 必填项。
  • *表示返回值类型任意。

全限定类名:

  • 可选项。
  • 两个点“…”代表当前包以及子包下的所有类。
  • 省略时表示所有的类。

方法名:

  • 必填项。
  • *表示所有方法。
  • set*表示所有的set方法。

形式参数列表:

  • 必填项
  • () 表示没有参数的方法
  • (…) 参数类型和个数随意的方法
  • (*) 只有一个参数的方法
  • (*, String) 第一个参数类型随意,第二个参数是String的。

异常:

  • 可选项。
  • 省略时表示任意异常类型。

例如:
表示service包下所有的类中以delete开始的所有方法

execution(public * com.mall.service.*.delete*(..))

所有类的所有方法

execution(* *(..))

mall包下所有的类的所有的方法

execution(* com.mall..*(..))

Spring的AOP的使用

Spring对AOP的实现包括以下3种方式:

  • 第一种方式:Spring框架结合AspectJ框架实现的AOP,基于注解方式。(常用)
  • 第二种方式:Spring框架结合AspectJ框架实现的AOP,基于XML方式。(不常用)
  • 第三种方式:Spring框架自己实现的AOP,基于XML配置方式。

实际开发中,都是Spring+AspectJ来实现AOP。所以我们重点学习第一种和第二种方式。而实际开发基本使用注解方式,最重点的是注解方式的学习。
什么是AspectJ?(Eclipse组织的一个支持AOP的框架。AspectJ框架是独立于Spring框架之外的一个框架,Spring框架用了AspectJ)
AspectJ项目起源于帕洛阿尔托(Palo Alto)研究中心(缩写为PARC)。该中心由Xerox集团资助,Gregor Kiczales领导,从1997年开始致力于AspectJ的开发,1998年第一次发布给外部用户,2001年发布1.0 release。为了推动AspectJ技术和社团的发展,PARC在2003年3月正式将AspectJ项目移交给了Eclipse组织,因为AspectJ的发展和受关注程度大大超出了PARC的预期,他们已经无力继续维持它的发展。

环境准备

使用Spring+AspectJ的AOP除了还需要引入aop依赖和aspects依赖:
而如果使用Maven则只需引入context依赖就会自动关联spring-aop依赖,没有使用Maven则需要把aop的jar包引入项目。

    <!--spring aspects依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>6.0.0-M2</version>
    </dependency>

Spring配置文件中添加context命名空间和aop命名空间:

<?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">

</beans>

基于AspectJ的AOP注解式开发

首先需要创建spring.xml文件:

  • 1.引入context命名空间和aop命名空间
  • 2.添加组件扫描
  • 3.开启自动代理
    开启之后,Spring容器在扫描类的时候,会查看类上是否有@Aspect注解,如果有,则会自动给这个类生成代理对象。
    使用aop:aspectj-autoproxy开启自动代理
    • proxy-target-class属性:默认为false
      • true:表示强制使用CGLIB动态代理

      • false:表示,接口使用JDK动态代理,类使用CGLIB动态代理

<?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.aop.annotation.service"/>
    <!--
        开启aspectj自动代理
    -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>

创建目标类和目标方法,纳入spring管理:

@Service
public class UserService {//目标类


    public void login(){//目标方法
        System.out.println("正在登录。。。");
    }

    public void logout(){
        System.out.println("正在退出。。。");
    }
}

创建切面类:纳入spring管理,除此之外,需要加一个@Aspect注解,通知Spring框架这个类是一个切面类,到时候这个切面类会编写通知,添加切点表达式

@Component
@Aspect
public class LogAspect {//切面=切点+通知
}

通知类型

通知类型包括:

  • 前置通知:@Before 目标方法执行之前的通知
  • 后置通知:@AfterReturning 目标方法执行之后的通知
  • 环绕通知:@Around 目标方法之前添加通知,同时目标方法执行之后添加通知。
  • 异常通知:@AfterThrowing 发生异常之后执行的通知
  • 最终通知:@After 放在finally语句块中的通知

前置通知@Before

@Before注解代表该通知为前置通知,注解里面需要写切点表达式
在LogAspect 切面类添加前置通知:

	//前置通知
	@Before("execution(* com.aop.annotation.service..*(..))")
    public void beforeAdvice(){
        System.out.println("前置通知。。。增强代码。。。");
    }

测试程序:

    @Test
    public void testAOP(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);

        userService.login();
        System.out.println("---------------------------------");
        userService.logout();
    }

请添加图片描述

后置通知@AfterReturning

@AfterReturning代表该通知为后置通知,注解里面需要写切点表达式
在LogAspect 切面类添加后置通知:

//后置通知
    @AfterReturning("execution(* com.aop.annotation.service..*(..))")
    public void afterReturningAdvice(){
        System.out.println("后置通知。。。增强代码。。。");
    }

再次运行测试程序:
请添加图片描述

环绕通知@Around

@Around代表该通知为环绕通知,注解里面需要写切点表达式
环绕通知会收到一个ProceedingJoinPoint参数,用来执行目标方法。
在LogAspect 切面类添加环绕通知:

    @Around("execution(* com.aop.annotation.service..*(..))")
    public void aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //前面代码
        System.out.println("前环绕。。。");
        //执行目标
        joinPoint.proceed();
        //后面代码
        System.out.println("后环绕。。。");
    }

再次运行测试程序:
可见环绕是最大的通知,在前置之前,在后置之后。
请添加图片描述

异常通知@AfterThrowing

@AfterThrowing代表该通知为异常通知,注解里面需要写切点表达式
为了更好演示,重新创建一个目标类和目标方法:该类抛一个异常

@Service
public class OrderService {
    public void generate(){
        System.out.println("正在生成订单。。。");
        throw new RuntimeException("异常");
    }
}

在LogAspect 切面类添加异常通知:

	@AfterThrowing("execution(* com.aop.annotation.service..*(..))")
    public void afterThrowingAdvice(){
        System.out.println("异常通知。。。");
    }

修改测试程序:

    @Test
    public void testAOP(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);

        userService.login();
        System.out.println("---------------------------------");
        userService.logout();
        System.out.println("---------------------------------");
        OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
        orderService.generate();
    }

运行程序:发现发生异常后,后环绕和后置通知已经没了,这是因为执行方法的时候抛异常之后不会再往下执行通知
请添加图片描述

最终通知@After

@After代表该通知为最终通知,注解里面需要写切点表达式
在LogAspect 切面类添加最终通知:

	@After("execution(* com.aop.annotation.service..*(..))")
    public void afterAdvice(){
        System.out.println("最终通知。。。");
    }

再次运行测试程序:
可见最终通知一定会执行,不管有没有异常,最终通知,在后置之后,后环绕之前,由此可见环绕通知确实是最大的通知
请添加图片描述

关于JoinPoint

JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.。
JoinPoint是在Spring调用的切面方法时候自动传过来的,我们可以直接使用

方法名功能
Signature getSignature();获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
Object[] getArgs();获取传入目标方法的参数对象
Object getTarget();获取被代理的对象
Object getThis();获取代理对象

ProceedingJoinPoint对象是JoinPoint的子接口,该对象只用在@Around的切面方法中, 添加了两个方法.

Object proceed() throws Throwable //执行目标方法 
Object proceed(Object[] var1) throws Throwable //传入的新的参数去执行目标方法 

切面的先后顺序

我们知道,业务流程当中不一定只有一个切面,可能有的切面控制事务,有的记录日志,有的进行安全控制,如果多个切面的话,顺序如何控制:可以使用@Order注解来标识切面类,为@Order注解的value指定一个整数型的数字,数字越小,优先级越高。

在LogAspect切面类添加注解:

@Order(2)

把OrderService目标类的异常注释掉:

@Service
public class OrderService {
    public void generate(){
        System.out.println("正在生成订单。。。");
        //throw new RuntimeException("异常");
    }
}

再定义一个切面类:优先级设置为1,使用一下JoinPoint

/**
 * 安全切面
 */
@Component
@Aspect
@Order(1)//数字越小优先级越高
public class SecurityAspect {
    @Before("execution(* com.aop.annotation.service..*(..))")
    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("安全的前置通知。。。");
        
        Signature signature = joinPoint.getSignature();//获取目标方法的签名
        System.out.println(signature.getName());
    }
}

测试程序:

    @Test
    public void test(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
        orderService.generate();
    }

请添加图片描述
如果把优先级换一下,再次运行:
请添加图片描述

通用切点表达式

回顾之前的切点表达式,发现切点表达式是重复的
这样的缺点是:

  • 第一:切点表达式重复写了多次,没有得到复用。
  • 第二:如果要修改切点表达式,需要修改多处,难维护。

怎么解决,可以使用通用切点表达式:@Pointcut注解将切点表达式单独的定义出来,在需要的位置引入即可。
在LogAspect 切面类添加一个方法使用@Pointcut注解:
方法只是个标记,方法名随意,方法体不需要写任何代码,只需要使用一个@Pointcut注解标注

    //通用切点表达式
    @Pointcut(value = "execution(* com.aop.annotation.service..*(..))")
    public void execution_use(){
    }

怎么引用,只需要在通知注解中写该方法即可,例如:

    //@After("execution(* com.aop.annotation.service..*(..))")
    @After("execution_use()")

这个通用表达式配置,只要一配置,任何切面类都可以使用,例如刚才的安全切面类,可以这样写。

/**
 * 安全切面
 */
@Component
@Aspect
@Order(3)//数字越小优先级越高
public class SecurityAspect {
    //@Before("execution(* com.aop.annotation.service..*(..))")
    @Before("com.aop.annotation.service.LogAspect.execution_use()")
    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("安全的前置通知。。。");
        /*
            这个JoinPoint是在Spring调用的这个方法时候自动传过来的
            我们可以直接使用
         */
        Signature signature = joinPoint.getSignature();//获取目标方法的签名
        System.out.println(signature.getName());
    }
}

再次运行test的测试程序:
请添加图片描述

全注解式开发AOP

就是编写一个类,在这个类上面使用大量注解来代替spring的配置文件,spring配置文件消失了,如下:

@Configuration //代替Spring配置文件
@ComponentScan("com.aop.annotation.service")//代替注解扫描
@EnableAspectJAutoProxy(proxyTargetClass = true)//代替开启aspectj自动代理,
public class SpringConfig {
}

测试程序:

    @Test
    public void testNoXML(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
        orderService.generate();
    }

请添加图片描述

基于XML配置方式的AOP(了解)

第一步:编写目标类

/**
 * 目标类
 */
public class UserService {
    public void login(){
        System.out.println("正在登录。。。");
    }
}

第二步:编写切面类,并且编写通知

/**
 * 切面
 */
public class TimerAspect {
    //通知
    public void arountAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //前环绕
        long begin = System.currentTimeMillis();
        joinPoint.proceed();//执行目标
        //后环绕
        long end = System.currentTimeMillis();
        System.out.println("耗时:"+ (end-begin));
    }
}

第三步:编写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">
    <!--配置bean-->
    <bean id="userService" class="com.spring.aspectj.service.UserService"></bean>
    <bean id="timerAspect" class="com.spring.aspectj.service.TimerAspect"></bean>

    <!--aop配置-->
    <aop:config>
        <!--切点表达式-->
        <aop:pointcut id="mypointcut" expression="execution(* com.spring.aspectj.service..*(..))"/>
        <!--切面-->
        <aop:aspect ref="timerAspect">
            <!--哪个通知就配哪个-->
            <aop:around method="arountAdvice" pointcut-ref="mypointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

测试程序:

    @Test
    public void testXML(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.login();
    }

请添加图片描述

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

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

相关文章

9、前端笔记-CSS-CSS三大特性

三大特性&#xff1a;层叠性、继承性、优先级 1、层叠性&#xff08;覆盖性&#xff09; 给相同的选择器设置相同的样式&#xff0c;此时一个样式会覆盖&#xff08;层叠&#xff09;其他冲突的样式。 层叠性原则&#xff1a; 同一选择器&#xff0c;样式冲突&#xff0c;遵…

【SpringBoot】MVC配置解决跨域但仍然存在跨域

文章目录1. 跨域问题出现与解决1. 跨域问题出现与解决 检查SpringBoot中的MVC配置。 public void addCorsMappings(CorsRegistry registry) {//允许跨域访问资源定义registry.addMapping("/**")//(只允许本地的指定端口访问)允许所有.allowedOrigins("*")…

数据结构之线性表中的单链表【详解】

文章目录前言&#xff1a;一、单链表1.单链表和顺序表的优缺点2.单链表的概念和学习3.单链表的各个接口的实现&#xff08;详解每一步&#xff09;3.1.先铺垫一下大致的思路3.2.然后这边我们看一下我们大致要实现的函数有哪些3.3.接下来我们就开始实现这些代码&#xff0c;并且…

用信号量实现进程同步与互斥(含代码分析)

信号量简单的来说就是一个变量&#xff0c;代表着系统中互斥资源的数量&#xff0c;通常用原语来实现对信号量机制的操作。 一对原语&#xff1a;wait(S)也称为P操作&#xff0c;singnal(S)也称为V操作。S表示信号量 对于wait原语本身的内部逻辑代码如下&#xff08;这里以一…

黑苹果外接显示器最优解决方案

黑苹果无法外接显示器 黑苹果外接显示器解决方案 先给解决方案 电脑端 > 安装 PC端 Duet Display买个二手电视盒子40块钱左右&#xff0c;还带电源电视盒子 > 安装安卓端 Duet Display&#xff08;U盘安装就行&#xff09;电视盒子 > 用鼠标开启开发者模式双头USB&…

SpringBoot SpringBoot 原理篇 1 自动配置 1.12 bean 的加载控制【注解式】

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 原理篇 文章目录SpringBootSpringBoot 原理篇1 自动配置1.12 bean 的加载控制【注解式】1.12.1 问题引入1.12.2 bean的加载…

【JVM技术专题】「原理专题」全流程分析Java对象的创建过程及内存布局

前言概要 对应过程则是&#xff1a;对象创建、对象内存布局、对象访问定位的三个过程。 对象的创建过程 对象的创建方式 java中对象的创建方式有很多种&#xff0c;常见的是通过new关键字和反射这两种方式来创建。除此之外&#xff0c;还有clone、反序列化等方式创建。 通过n…

CSS @property,让不可能变可能

本文主要讲讲 CSS 非常新的一个特性&#xff0c;CSS property&#xff0c;它的出现&#xff0c;极大的增强的 CSS 的能力&#xff01; 根据 MDN -- CSS Property&#xff0c;property CSS at-rule 是 CSS Houdini API 的一部分, 它允许开发者显式地定义他们的 CSS 自定义属性&…

vue项目分环境配置打包处理

vue项目分环境配置打包处理 目录 vue项目分环境配置打包处理 本地环境配置 生产环境配置 打包处理 打包配置处理&#xff08;扩展&#xff09; 本地环境配置 定义需要的变量&#xff0c;这里定义了各种变量标识&#xff0c;可参考使用&#xff0c;自定义项目需要的变量&…

设计问卷调查有哪些技巧?

调查问卷可以很好地帮助我们进行市场调研&#xff0c;所以想要做出一份有效的调查问卷&#xff0c;首先要确定问卷的主题。明确的主题就是定基调&#xff0c;可以让我们的后续过程更加顺利。然后我们再开始进行题目的设置和问卷的设计等动作。不过&#xff0c;在问卷设计的过程…

【js】【爬虫】fetch + sessionStorage 快速搭建爬虫环境及各种踩坑

文章目录导读需求开发环境fetch介绍为什么选择fetchfetch的封装使用数据存储数据访问封装多页面处理方案数据过大&#xff0c;拆分处理参考资料导读 需求 一说爬虫&#xff0c;很多人都会向导python&#xff0c;不过&#xff0c;真正省心的方案&#xff0c;应当是通过js控制获…

Reactive源码分析

Reactive用来绑定引用数据类型, 例如对象和数组等,实现响应式。 Reactive API 接口 export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>相关API包括readonly、createReactiveObject、shallowReadonly、isReactive、toReactive。源码运…

Eureka注册中心

文章目录一、认识服务提供者和服务调用者二、Eureka 的工作流程三、服务调用出现的问题及解决方法四、搭建 eureka-server五、注册 user-service、order-service六、在 order-service 完成服务拉取&#xff08;order 模块能访问 user 模块&#xff09;七、配置远程服务调用八、…

从入门到进阶!当下火爆的大数据技术及算法怎么还能不知道 一起来学习互联网巨头的大数据架构实践!

大数据被称为新时代的黄金和石油&#xff0c;相关技术发展迅猛,所应用的行业也非常广泛&#xff0c;从传统行业如医疗、教育、金融、旅游&#xff0c;到新兴产业如电商、计算广告、可穿戴设备、机器人等。大数据技术更是国家科技发展和智慧城市建设的基础。 当前“互联网”新业…

骨传导耳机是怎么传声的?骨传导耳机会伤害耳朵吗?

作为一个耳机发烧友&#xff0c;平时最喜欢的就是捣鼓耳机。这几年入手了几十款耳机&#xff0c;头戴式、入耳式、半入耳、有线无线都会接触一些来玩&#xff0c;其中还有骨传导耳机这个相对小众的款类。 说到骨传导耳机&#xff0c;我应该算是最早一批的用户了&#xff0c;很…

web网页设计—— 指环王:护戒使者(13页) 电影网页设计 在线电影制作 个人设计web前端大作业

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 文章目录一、网页介绍一…

数据结构-ArrayList解析和实现代码

arrayList结构的实现是数组结构&#xff0c;数组没有扩容机制&#xff0c;arrayList的扩容机制采用的是复制数组&#xff0c;了解你会发现ArrayList虽然实现比较简单&#xff0c;但是设计还是很巧妙的。咱们先来简单实现下.. 咱们看下定义的全局变量 1.默认初始化空间为10&am…

docker 安装 Jenkins

一、Jenkins 安装 增加挂载目录和权限 # 增加挂载目录和权限mkdir /workspace/jenkins_homechown -R 1000:1000 /workspace/jenkins_home/创建容器 docker run --name jenkins -d \ -p 9999:8080 \ -p 8888:8888 \ -p 50000:50000 \ -v /workspace/jenkins_home:/var/jenkins…

[附源码]java毕业设计智慧教室预约

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

java检验mp4文件完整性的一个方法:使用ffmpeg

问题引入 最近笔者在写一个多线程下载视频文件的程序&#xff0c;打算让这个程序在我的空闲服务器上运行&#xff0c;但是几轮测试之后发现&#xff0c;有时候会存在下载的视频文件不完整的情况&#xff0c;这就导致了有些文件无法正常播放 问题排查 经过一周的排查后&#…