分布式锁Lock4J 使用总结

Lok4j 简介

lock4j是一个分布式锁组件,其提供了多种不同的支持以满足不同性能和环境的需求。

立志打造一个简单但富有内涵的分布式锁组件。

特点

  • 简单易用,功能强大,扩展性强。
  • 支持redission,redisTemplate,zookeeper。可混用,支持扩展

Docker 安装Redis

请参考文章:Docker 安装Redis

Docker 安装ZooKeeper

请参考文章:Docker 安装Zookeeper

SpringBoot 集成Lock4j 

Lock4j 之Reids 版本

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">
    <parent>
        <artifactId>SpringBootCase</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>SpringBoot-Lock4J</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <mybatisplus-spring-boot-starter.version>3.4.3</mybatisplus-spring-boot-starter.version>
        <mysql-spring-boot-starter.version>8.0.19</mysql-spring-boot-starter.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatisplus-spring-boot-starter.version}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-spring-boot-starter.version}</version>
        </dependency>
        <!--添加开源分布式锁Lock4j-->
        <!--若使用redisTemplate作为分布式锁底层,则需要引入-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>lock4j-redis-template-spring-boot-starter</artifactId>
            <version>2.2.4</version>
        </dependency>
    </dependencies>

</project>

application.yml 之Redis 配置

server:
  port: 8086
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.43.10:3306/bill?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&autoReconnect=true
    username: root
    password: 123456
    hikari:
      minimum-idle: 10
      maximum-pool-size: 20
      idle-timeout: 500000
      max-lifetime: 540000
      connection-timeout: 60000
      connection-test-query: select 1
  redis:
    database: 0
    host: 192.168.43.10
    port: 6379
    jedis:
      pool:
        max-active: 200
        max-wait: -1
        max-idle: 10
        min-idle: 0
    timeout: 6000

mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: cn.zzg.mybatisplus.entity

controller 使用Lock4j 注解,实现分布式锁功能

package cn.zzg.lock.controller;

import com.baomidou.lock.annotation.Lock4j;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/lock4j")
public class Lock4JController {

    @GetMapping("/lockMethod")
    @Lock4j(keys = {"#key"}, acquireTimeout = 1000, expire = 10000)
    public String lockMethod(@RequestParam String key){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return new String(key);
    }

}

Lock4j 之Redission版本

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">
    <parent>
        <artifactId>SpringBootCase</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>SpringBoot-Lock4JRedission</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--若使用redisson作为分布式锁底层,则需要引入-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>lock4j-redisson-spring-boot-starter</artifactId>
            <version>2.2.4</version>
        </dependency>
    </dependencies>


</project>

application.yml 配置文件

server:
  port: 8089
spring:
  redis:
    database: 0
    host: 192.168.43.10
    port: 6379
    jedis:
      pool:
        max-active: 200
        max-wait: -1
        max-idle: 10
        min-idle: 0
    timeout: 6000

 controller 使用Lock4j 注解,实现分布式锁功能

package cn.zzg.lock4j.controller;

import com.baomidou.lock.annotation.Lock4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/lock4j")
public class Lock4JController {

    @GetMapping("/lockMethod")
    @Lock4j(keys = {"#key"}, acquireTimeout = 1000, expire = 10000)
    public String lockMethod(@RequestParam String key){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return new String(key);
    }

}

Lock4j 之ZooKeeper 版本

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">
    <parent>
        <artifactId>SpringBootCase</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>SpringBoot-Lock4jZookeeper</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--添加开源分布式锁Lock4j-->
        <!--若使用Zookeeper作为分布式锁底层,则需要引入-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>lock4j-zookeeper-spring-boot-starter</artifactId>
            <version>2.2.4</version>
        </dependency>
    </dependencies>

</project>

application.yml 之zookeeper配置

server:
  port: 8087
spring:
  coordinate:
    zookeeper:
      zkServers: 192.168.43.10:2181

controller 使用Lock4j 注解,实现分布式锁功能

package cn.zzg.lock.controller;

import com.baomidou.lock.annotation.Lock4j;
import com.baomidou.lock.executor.ZookeeperLockExecutor;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/lock4j")
public class Lock4JController {

    @GetMapping("/lockMethod")
    @Lock4j(keys = {"#key"}, acquireTimeout = 1000, expire = 10000, executor = ZookeeperLockExecutor.class)
    public String lockMethod(@RequestParam String key){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return new String(key);
    }

}

Lock4J 注解详解

 Lock4J 高级使用

1、配置获取锁超时时间和锁过期时间。

lock4j:
  acquire-timeout: 3000 #默认值3s,可不设置
  expire: 30000 #默认值30s,可不设置
  primary-executor: com.baomidou.lock.executor.RedisTemplateLockExecutor #默认redisson>redisTemplate>zookeeper,可不设置
  lock-key-prefix: lock4j #锁key前缀, 默认值lock4j,可不设置

acquire-timeout /排队时长,超出这个时间退出队列,并抛出超时异常。
expire 锁过期时间 。 主要是防止死锁。默认30秒是为了兼容绝大部分场景。 

2、自定义执行器。

前提条件必须继承抽象类:com.baomidou.lock.executor.AbstractLockExecutor<T> 

ZooKeeper 版本执行器之ZookeeperLockExecutor

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.baomidou.lock.executor;

import java.util.concurrent.TimeUnit;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.imps.CuratorFrameworkState;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ZookeeperLockExecutor extends AbstractLockExecutor<InterProcessMutex> {
    private static final Logger log = LoggerFactory.getLogger(ZookeeperLockExecutor.class);
    private final CuratorFramework curatorFramework;

    public InterProcessMutex acquire(String lockKey, String lockValue, long expire, long acquireTimeout) {
        if (!CuratorFrameworkState.STARTED.equals(this.curatorFramework.getState())) {
            log.warn("instance must be started before calling this method");
            return null;
        } else {
            String nodePath = "/curator/lock4j/%s";

            try {
                InterProcessMutex mutex = new InterProcessMutex(this.curatorFramework, String.format(nodePath, lockKey));
                boolean locked = mutex.acquire(acquireTimeout, TimeUnit.MILLISECONDS);
                return (InterProcessMutex)this.obtainLockInstance(locked, mutex);
            } catch (Exception var10) {
                return null;
            }
        }
    }

    public boolean releaseLock(String key, String value, InterProcessMutex lockInstance) {
        try {
            lockInstance.release();
            return true;
        } catch (Exception var5) {
            log.warn("zookeeper lock release error", var5);
            return false;
        }
    }

    public ZookeeperLockExecutor(final CuratorFramework curatorFramework) {
        this.curatorFramework = curatorFramework;
    }
}

Redis 版本执行器之RedisTemplateLockExecutor

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.baomidou.lock.executor;

import java.util.Collections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;

public class RedisTemplateLockExecutor extends AbstractLockExecutor<String> {
    private static final Logger log = LoggerFactory.getLogger(RedisTemplateLockExecutor.class);
    private static final RedisScript<String> SCRIPT_LOCK = new DefaultRedisScript("return redis.call('set',KEYS[1],ARGV[1],'NX','PX',ARGV[2])", String.class);
    private static final RedisScript<String> SCRIPT_UNLOCK = new DefaultRedisScript("if redis.call('get',KEYS[1]) == ARGV[1] then return tostring(redis.call('del', KEYS[1])==1) else return 'false' end", String.class);
    private static final String LOCK_SUCCESS = "OK";
    private final StringRedisTemplate redisTemplate;

    public String acquire(String lockKey, String lockValue, long expire, long acquireTimeout) {
        String lock = (String)this.redisTemplate.execute(SCRIPT_LOCK, this.redisTemplate.getStringSerializer(), this.redisTemplate.getStringSerializer(), Collections.singletonList(lockKey), new Object[]{lockValue, String.valueOf(expire)});
        boolean locked = "OK".equals(lock);
        return (String)this.obtainLockInstance(locked, lock);
    }

    public boolean releaseLock(String key, String value, String lockInstance) {
        String releaseResult = (String)this.redisTemplate.execute(SCRIPT_UNLOCK, this.redisTemplate.getStringSerializer(), this.redisTemplate.getStringSerializer(), Collections.singletonList(key), new Object[]{value});
        return Boolean.parseBoolean(releaseResult);
    }

    public RedisTemplateLockExecutor(final StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
}

3、自定义Key生成器

前提条件必须实现:com.baomidou.lock.LockKeyBuilder 接口

默认Key生成器:DefaultLockKeyBuilder

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.baomidou.lock;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.StringUtils;

public class DefaultLockKeyBuilder implements LockKeyBuilder {
    private static final ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
    private static final ExpressionParser PARSER = new SpelExpressionParser();
    private BeanResolver beanResolver;

    public DefaultLockKeyBuilder(BeanFactory beanFactory) {
        this.beanResolver = new BeanFactoryResolver(beanFactory);
    }

    public String buildKey(MethodInvocation invocation, String[] definitionKeys) {
        Method method = invocation.getMethod();
        return definitionKeys.length <= 1 && "".equals(definitionKeys[0]) ? "" : this.getSpelDefinitionKey(definitionKeys, method, invocation.getArguments());
    }

    protected String getSpelDefinitionKey(String[] definitionKeys, Method method, Object[] parameterValues) {
        StandardEvaluationContext context = new MethodBasedEvaluationContext((Object)null, method, parameterValues, NAME_DISCOVERER);
        context.setBeanResolver(this.beanResolver);
        List<String> definitionKeyList = new ArrayList(definitionKeys.length);
        String[] var6 = definitionKeys;
        int var7 = definitionKeys.length;

        for(int var8 = 0; var8 < var7; ++var8) {
            String definitionKey = var6[var8];
            if (definitionKey != null && !definitionKey.isEmpty()) {
                String key = (String)PARSER.parseExpression(definitionKey).getValue(context, String.class);
                definitionKeyList.add(key);
            }
        }

        return StringUtils.collectionToDelimitedString(definitionKeyList, ".", "", "");
    }
}

4、自定义锁获取失败策略

前提条件必须实现:com.baomidou.lock.LockFailureStrategy 接口

默认失败策略:DefaultLockFailureStrategy

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.baomidou.lock;

import com.baomidou.lock.exception.LockFailureException;
import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DefaultLockFailureStrategy implements LockFailureStrategy {
    private static final Logger log = LoggerFactory.getLogger(DefaultLockFailureStrategy.class);
    protected static String DEFAULT_MESSAGE = "request failed,please retry it.";

    public DefaultLockFailureStrategy() {
    }

    public void onLockFailure(String key, Method method, Object[] arguments) {
        throw new LockFailureException(DEFAULT_MESSAGE);
    }
}

5、手动获取/释放锁

通用方法:

@Service
public class CommonService {
    @Autowired
    private LockTemplate lockTemplate;

    public void commonLock(String bizId) {
        // 各种查询操作 不上锁
        // ...
        // 获取锁
        final LockInfo lockInfo = lockTemplate.lock(bizId, 30000L, 5000L, RedissonLockExecutor.class);
        if (null == lockInfo) {
            throw new RuntimeException("业务处理中,请稍后再试");
        }
        // 获取锁成功,处理业务
        try {
            System.out.println("执行普通方法 , 当前线程:" + Thread.currentThread().getName());
        } finally {
            //释放锁
            lockTemplate.releaseLock(lockInfo);
        }
        //结束
    }
}

参考资料

官网地址:Lock4J

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

互联网分布式应用之RabbitMQ

RabbitMQ Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. RabbitMQ介绍安装 2. Rabbi…

【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 概述

【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 概述-CSDN博客 【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 运行环境搭建-CSDN博客 【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 运行模式-CSDN博客 1、 Hadoop 是什么 &#xff08;1&#xff09;Hadoop是一个由Apache基…

美团后端Java实习一面面经

说一下AOP&#xff1f; 面向切面编程&#xff0c;通过预编译方式和运行期动态代理实现程序功能的统一维护的技术。可以减少程序中相同代码的编写&#xff0c;简化开发&#xff0c;使得接口更加专注于业务 相关概念 Aspect&#xff08;切面&#xff09;&#xff1a; Aspect 声…

NVIDIA 正式发布中国特供 RTX 4090D,减量不减价刀法再进化

随着中国特供 RTX 4090D 显卡发布&#xff0c;老美禁售导致的 NVIDIA 旗舰游戏显卡断供、涨价风波注定要结束了。 就在上周四&#xff0c;NVIDIA 正式发布了应对老美禁令的中国特供版 RTX 4090D 显卡。 别的不说&#xff0c;前段时间疯狂炒作、高价囤货 RTX 4090 的商贩们首先…

在机械硬盘和固态硬盘上分别打一个压缩包,时间相差几倍

机械硬盘&#xff0c;它的原理类似于光盘&#xff0c;主要结构是一个高速旋转的盘片的和在盘片上来回读写数据的磁头。而固态硬盘则是以电子存储的方式来储存数据的&#xff0c;主要由主控芯片、闪存芯片、固件算法等组成。 一般来说机械硬盘的读写速度在60-170MB/s之间&#x…

win10提示“KBDROST.DLL文件丢失,软件无法启动”,快速修复方法

KBDROST.DLL是Windows操作系统中的一个动态链接库文件&#xff0c;主要与键盘布局或键盘输入有关。在Windows系统中&#xff0c;每种语言都有一个相应的DLL文件来处理键盘输入&#xff0c;KBDROST.DLL文件主要用于处理俄语键盘布局。 所以&#xff0c;当我们使用到俄语输入相关…

Linux第12步_磁盘重新分区

解决“挂载后的U盘出现中文乱码”后&#xff0c;我们接着学习“磁盘重新分区”&#xff0c;熟悉fdisk命令。 1、删除磁盘的分区 输入“cd /回车”&#xff0c;进入根目录 输入“ls /dev/sd*回车”&#xff0c;显示dev以sd所有文件。 输入“sudo fdisk /dev/sdb1回车” 输入…

学习汽车LIN总线该如何入门?

关注菲益科公众号—>对话窗口发送 “CANoe ”或“INCA”&#xff0c;即可获得canoe入门到精通电子书和INCA软件安装包&#xff08;不带授权码&#xff09;下载地址。 目录 1. 车载LIN总线诞生背景和使用场景 2. LIN总线硬件接口 3. Lin总线协议 4. 总结 1、车载LIN总线…

北斗卫星为社区智慧管理提供精准支持

北斗卫星为社区智慧管理提供精准支持 近年来&#xff0c;随着智能科技的快速发展和智慧社区的兴起&#xff0c;北斗卫星作为一项关键技术&#xff0c;正逐渐在智慧社区中发挥着重要作用。北斗卫星定位与导航系统是我国自主研发的卫星导航定位系统&#xff0c;它不仅为智慧社区…

postgresql可视化导入csv文件

不需要在命令行copy了&#xff0c;只需简单点几下 1.在数据库下建一个schema 右击选中数据库-new schema 2.双击你创建的schema&#xff0c;出现tables 3.右击tables&#xff0c;选择import wizard 4.选择你想导入的文件格式&#xff0c;之后一直next 5.选择你的文件所在位置…

工厂如何确定设备故障的原因?

设备故障是制造业中常见的问题&#xff0c;对生产效率和运营成本产生重大影响。为了解决设备故障并提高生产效率&#xff0c;确定设备故障的准确原因至关重要。本文将介绍一些关键步骤和方法&#xff0c;帮助工厂确定设备故障的原因。 1. 收集和分析数据 要确定设备故障的原因…

HTTP和TCP代理原理及实现,主要是理解

Web 代理是一种存在于网络中间的实体&#xff0c;提供各式各样的功能。现代网络系统中&#xff0c;Web 代理无处不在。我之前有关 HTTP 的博文中&#xff0c;多次提到了代理对 HTTP 请求及响应的影响。今天这篇文章&#xff0c;我打算谈谈 HTTP 代理本身的一些原理&#xff0c;…

【自学笔记】01Java基础-07面向对象基础-02继承

记录学习Java基础中有关继承、方法重写、构造器调用的基础知识&#xff0c;学习继承之前建议学习static关键字的内容【自学笔记】01Java基础-09Java关键字详解 1 继承概述 1.1 什么是继承&#xff1f; 1.2 继承的特点 子类可以继承父类的属性和行为&#xff0c;但是子类不能…

期货跟单系统。镜像跟单系统有什么作用?功能有哪些?

期货跟单系统&#xff1a; 期货自动跟单系统&#xff0c;是一款专门用来针对特定账户的操作而进行自动跟单的软件。软件兼容目前所有的期货公司账户&#xff0c;具有稳定性&#xff0c;速度性和可靠性的优势。 补差补点&#xff0c;根据盘手实盘心理分析&#xff0c;增加模拟…

PLC三相电动机Y-▲启动控制程序示例

一、三相电动机星三角启动接法。 二、因为电动机在启动的时候启动电流非常的大&#xff0c;所以在启动时采用星型接法&#xff0c;也就是Y型接法&#xff0c;也就是图上的KM1和KM2接通&#xff0c;目的为了减小启动电流&#xff0c;采用Y型接法的启动电流是原来电流的1/3 三、启…

华为交换机怎么添加和剥除VLAN标签

知识改变命运&#xff0c;技术就是要分享&#xff0c;有问题随时联系&#xff0c;免费答疑&#xff0c;欢迎联系&#xff01; 华为交换机VLAN标签的添加和剥除处理过程 接口对收发的以太网数据帧添加或剥除VLAN标签的处理依据接口的接口类型和缺省VLAN。 由上面各类接口添加或…

Mybatis之多表查询

目录 一、简介 1、使用嵌套查询: 2、使用多个 SQL 语句&#xff1a; 3、使用关联查询&#xff1a; 4、使用自定义映射查询&#xff1a; 二、业务场景 三、示例 1、一对一查询 2、一对多查询 一、简介 MyBatis 是一个优秀的持久层框架&#xff0c;它提供了强大的支持来执…

小样本学习介绍(超详细)

小样本学习介绍 本文首先介绍了什么是小样本学习&#xff0c;其次介绍了为什么小样本学习的很多文章都采用元学习的方法。目的是通过通俗的解释更加清楚的介绍小样本学习是什么&#xff0c;适合初学者的入门。当然&#xff0c;以下更多的是自己的思考&#xff0c;欢迎交流。 …

cesium第一视角/上帝视角以及解除视角锁定

第一视角效果&#xff1a; function event1() {viewer.scene.screenSpaceCameraController.enableZoom false; //. 禁止视角缩放viewer.scene.screenSpaceCameraController.enableRotate false; //禁止左键拖动视角viewer.scene.screenSpaceCameraController.enableTilt fal…

GAMES101:作业5记录

总览 在这部分的课程中,我们将专注于使用光线追踪来渲染图像。在光线追踪中最重要的操作之一就是找到光线与物体的交点。一旦找到光线与物体的交点,就可以执行着色并返回像素颜色。在这次作业中,我们需要实现两个部分:光线的生成和光线与三角的相交。本次代码框架的工作流程为…