Spring-loC与DI

目录

1 loC控制反转思想

2 DI依赖注入

3 loC详解

3.1 存储Bean

(1)@Controller

(2)@Service

(3)@Repository

(4)@Component

(5)@Configuration

(6)@Bean

(7)Bean对象命名规范

(8)5大类注解之间的关系

3.2 获取Bean

(1)ApplicationContext

(2)三种常用的获取方式

(3)获取多个@Bean注解的Bean

(4)Bean重命名

3.3 Spring扫描路径

(1)默认路径

(2)@ComponentScan

3.4 ApplicationContext和BeanFactory区别

4 DI详解

4.1 属性注入

4.2 构造方法注入

4.3 Setter方法注入

4.4 三种方式优缺点

(1)属性注入

(2)构造方法注入

(3)Setter方法注入

4.5 @Autowired原理

(1)@Autowired原理与问题

(2)解决方法

(3)@Autowired与@Resource区别


        Spring家族包含:Spring Framework、SpringMVC、SpringBoot、Spring Cloud等等框架,而我们常说的Spring框架就是指Spring Framework。

        Spring框架(Spring Framework)的推出是为了简化Java程序的开发(快速、简单、安全)。它是包含众多工具方法的loC(控制反转)容器。即Spring是一个容器,其内部装了很多的对象,这个容器蕴含了loC思想。

1 loC控制反转思想

        建房子首先需要用各种建材盖出毛坯房,然后再对毛坯房进行装修,得到成品房,成品房再交付到客户手中。用面向对象的程序设计思想就需要三个类:Ston类表示用建材盖毛坯房、Decoration类表示对毛坯房进行装修、House类表示把成品房交付给客户。

// 建房子用的建材public class Stone {public Stone() {System.out.println("使用建材数量: " + 20 + " 建成毛坯房");}}// 毛坯房装修public class Decoration {private Stone stone;public Decoration(){stone = new Stone();System.out.println("对毛坯房进行装修");}}//成品房交付public class House {private Decoration decoration;public House(){decoration = new Decoration();System.out.println("成功交付房子");}}

        在这个流程中,House类的实例需要Decoration类的实例,Decoration类的实例需要Stone类的实例。我们称这种关系为:House实例依赖Decoration实例,Decoration实例依赖Stone实例。

        如果现在想要修改Stone类,比如添加一些属性、修改一些方法的参数时,情况就如下述:

public class Stone {private int num;public String name;public Stone(int num,String name) {this.num = num;this.name = name;System.out.println("使用建材数量: " + this.num + " 建成毛坯房: " + this.name);}}public class Decoration {private Stone stone;public String name;public Decoration(int num,String name){stone = new Stone(num,name);this.name = name;System.out.println("对毛坯房:" + this.name + "进行装修");}}public class House {private Decoration decoration;public House(int num,String name){decoration = new Decoration(num,name);System.out.println("成功交付房子:" + decoration.name);}}

        可以发现上述方案有一个很大的问题:调用链最底层的代码需要修改,整个调用链的类都需要进行修改,程序耦合度很高。

        如果改变实例创建顺序,让每个实例的创建都不由其他类控制,而通过依赖对象注入的方式,即把实例传递给每个类的构造方法,这样每个类的修改就不需要修改其他类的代码了,实现了对象的解耦。

public class Stone {private int num;public String name;public Stone(int num,String name) {this.num = num;this.name = name;System.out.println("使用建材数量: " + this.num + " 建成毛坯房: " + this.name);}}public class Decoration {private Stone stone;public String name;public Decoration(Stone stone){name = stone.name;System.out.println("对毛坯房:" + name + "进行装修");}}public class House {private Decoration decoration;public House(Decoration decoration){System.out.println("成功交付房子:" + decoration.name);}}public class Test {public static void main(String[] args) {Stone stone = new Stone(20,"花园3单元301");Decoration decoration = new Decoration(stone);House house = new House(decoration);}}

        原先对象的创建顺序是:House对象=>Decoration对象=>Stone对象,对象的创建依赖其他对象。而采用依赖对象注入的方式后,对象的创建顺序就变为:Stone对象=>Decoration对象=>House对象,对象的创建不由其他对象负责,而采用注入的方式,即每个对象的创建控制权发生了反转。这就是loC控制反转的思想。

        而Spring是loC容器,loC容器体现在上述Test类的代码,即由Spring负责创建对象并管理对象等资源。因此loC容器具有以下优点:

        1.资源集中管理:loC容器帮助我们管理一些资源,包括对象等。需要使用这些资源时,直接从容器取。

        2.耦合度降低:降低了资源之间的依赖程度,最典型的就是上述对象间的创建不再依赖其他对象的实现细节,某个对象修改时,由于是依赖对象注入的方式,不需要修改其他对象。

2 DI依赖注入

        DI依赖注入:容器运行期间,动态地为应用程序提供依赖的资源的过程,就是依赖注入。

        DI和loC是从两个角度描述同一件事,loC是思想,DI是其具体的实现,loC强调要将对象等资源交给容器来管理,那么该如何管理呢?DI就是其实现管理的方式,即依赖注入,需要时把对象从容器中取出来注入到需要使用的地方。

        Spring把对象称为Bean,Bean存放在loC容器中,因此loC容器主要提供两个功能:存和取。存就是loC容器体现的方面,取就是DI体现的方面。

3 loC详解

        如何把Bean存储到loC容器中,这就牵扯到5大类注解:@Controller、@Service、@Repository、@Component、@Configuration,1个方法注解:@Bean。

3.1 存储Bean

(1)@Controller

@Controllerpublic class UserController {public void hello(){System.out.println("hello userController");}}

        直接在要交给Spring管理的对象的类前加上@Controller,其他的5大注解类似。Spring在启动时就会扫描该路径并创建对象放到loC容器中。

(2)@Service

@Servicepublic class UserService {public void hello(){System.out.println("hello userService");}}

(3)@Repository

@Data@Repositorypublic class UserInfo {private Integer id;private String name;private Integer age;public UserInfo() {}public UserInfo(Integer id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}}

(4)@Component

@Componentpublic class UserCompeonent {public void hello(){System.out.println("hello userCompeonent");}}

(5)@Configuration

@Configurationpublic class UserConfiguration {public void hello(){System.out.println("hello userConfiguration");}}

(6)@Bean

@Componentpublic class UserCompeonent {public void hello(){System.out.println("hello userCompeonent");}@Beanpublic UserInfo getUser1(){UserInfo user1 = new UserInfo(100,"zhangsan",20);return user1;}@Beanpublic UserInfo getUser2(){UserInfo user2 = new UserInfo(101,"lisi",21);return user2;}}

        @Bean注解必须搭配类注解使用,如果要定义多个对象(类是同一个,但对象不是同一个),就需要使用多次@Bean注解。

        为什么要用到@Bean注解?上述类注解存在两个问题:1.如果外部类的对象我们也想交给Spring来管理,那么没有办法在外部类加类注解(总不能改别人的源代码吧)2.如果一个类需要注册多个对象,多个对象的属性的值不同,通过类注解没有办法实现(类注解使用了单例模式,对象全局只有一个,这点在后面获取Bean会得到印证)。而@Bean注解就可以解决上述问题。

(7)Bean对象命名规范

        在java.beans.Introspector类中的decapitalize定义了Bean的命名规范:

    public static String decapitalize(String name) {if (name == null || name.length() == 0) {return name;}if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&Character.isUpperCase(name.charAt(0))){return name;}char[] chars = name.toCharArray();chars[0] = Character.toLowerCase(chars[0]);return new String(chars);}

        默认如果类的名称前两个字母是大写的,则Bean对象名称和类名一致;如果类的名称不符合这种特殊情况,则首字母小写(小驼峰)。而方法注解@Bean所创建的对象的名称,就是方法名。

(8)5大类注解之间的关系

        观察@Controller、@Service、@Repository、@Configuration四个注解的源码发现,都含有@Component注解,说明那4个注解是@Component注解的衍生类(子类),而@Component是元注解。

        那有了@Component就可以把对象创建出来交给Spring管理,为什么还需要其他注解?这是开发模式的需要:常用的开发模式是后端分为Controller层、Service层和Dao层,Controller层用于处理请求和响应,Service层用于业务逻辑,Dao层用于和数据库交互。对Controller层使用@Controller,对Service层使用@Service,对Dao层使用@Repository,便于项目结构的清晰,这已经成为了一种开发规范。

        注意:@RestController也具有创建Bean对象并存储到loC容器中的功能,这是由于@RestController=@Controller+@ResponseBody。但是如果只对Controller层使用@Component注解和@ResponseBody,就会导致请求url分级的一些问题。

3.2 获取Bean

(1)ApplicationContext

        因为Bean对象都交给Spring管理了,所以获取Bean就需要用到Spring的上下文(它可以看做一个容器,存储了Spring运行时需要用到的环境和对象)。

        而在启动类(@SpringBootApplication)中,SpringApplication.run()方法会返回一个对象,类型是ConfigurableApplicationContext,它的父类是ApplicationContext,我们获取Bean就是通过该对象获取的。

        同时,也可以直接在在其他类中通过DI(依赖注入)注入ApplicationContext对象,使用@Autowired注解注入ApplicationContext对象。这里的注解在后面会讲。

(2)三种常用的获取方式

@SpringBootApplicationpublic class SpringmvcApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringmvcApplication.class, args);// 获取Bean对象方式1:通过类型获取UserController userController1 = context.getBean(UserController.class);userController1.hello();System.out.println(userController1);// 获取Bean对象方式2:通过对象名称获取UserController userController2 = (UserController) context.getBean("userController");userController2.hello();System.out.println(userController2);// 获取Bean对象方式3:通过类型+对象名称获取UserController userController3 =  context.getBean("userController", UserController.class);userController3.hello();System.out.println(userController3);}}

        观察结果可以发现,我们使用三种方式获得的Bean对象是同一个,这说明UserController的对象全局中只有一个,这是由于Spring对于Bean的创建遵循单例模式。

        方式1不适合获取多个Bean对象,而方式2和3都适合。

(3)获取多个@Bean注解的Bean

@SpringBootApplicationpublic class SpringmvcApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringmvcApplication.class, args);UserInfo user1 =  context.getBean("getUser1", UserInfo.class);UserInfo user2 =  context.getBean("getUser2", UserInfo.class);System.out.println(user1);System.out.println(user2);}}

        注意到,获取@Bean注解的对象,需要使用带对象名称的方式(2或3),而对象的名称就是方法名。

(4)Bean重命名

        要重命名时,直接在注解中填入要重命名的名称(类注解和方法注解都适用)。比如:

@Controller("UserController")public class UserController {public void hello(){System.out.println("hello userController");}}@SpringBootApplicationpublic class SpringmvcApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringmvcApplication.class, args);// 默认名称是userController(类的首字母小写), 重命名为UserControllerUserController userController1 = (UserController) context.getBean("UserController");userController1.hello();System.out.println(userController1);}}

        注意:Java对类名的大小写敏感,不允许通过首字母大写和小写区分不同的类,比如UserController和userController,不能表示为两个不同的类,必须是同一个类,这也是命名规范。

3.3 Spring扫描路径

(1)默认路径

        Spring默认的扫描路径是启动类所在的路径,在该同级目录下,Spring启动时都可以扫描到其中的注解,然后依次创建对象,存储在loC容器中。

(2)@ComponentScan

        如果想要Spring也扫描启动类所在路径外的路径,就需要使用@ComponentScan(“要扫描的路径(包的全名)”),将该注解放在启动类前(@SpringBootApplication所在的位置)。如果要额外扫描多个路径,就用{}把所有的路径都括起来。

@SpringBootApplication包含@ComponentScan,其默认扫描路径就是启动类所在的路径。

3.4 ApplicationContext和BeanFactory区别

        注意到,getBean()方法实际上是BeanFactory接口提供的方法,而ApplicationContext接口继承了ListableBeanFactory和HierarchicalBeanFactory,这两个接口的父类就是BeanFactory。因此:

        1.从继承角度来讲,BeanFactory提供了基础的访问容器的能力,而ApplicationContext属于BeanFactory的子类,它除了继承了BeanFactory的所有功能之外,还拥有独特的特性,还添加了对国际化支持、资源访问支持、以及事件传播等方面的支持。

        2.从性能角度来讲,ApplicationContext是一次性加载并初始化所有的Bean对象(空间换时间)。而BeanFactory是需要哪个才去加载哪个,更加轻量。

4 DI详解

        DI是依赖注入,体现在把loC容器中管理的对象动态的注入到需要的地方。有3种注入的方式:属性注入、构造方法注入和Setter方法注入。

4.1 属性注入

@Controllerpublic class UserController {@Autowiredpublic UserService userService;public void hello(){System.out.println("hello userController");userService.hello();}}@SpringBootApplicationpublic class SpringmvcApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringmvcApplication.class, args);// 依赖注入1UserController userController1 = context.getBean(UserController.class);userController1.hello();}}

        属性注入是通过在需要注入对象的属性前加上@Autowired注解,运行结果可以看到,成功的把UserService的对象注入到UserController中。

4.2 构造方法注入

        如果只有一个构造方法,只使用构造方法即可注入:

@Controllerpublic class UserController {public UserService userService;public UserController(UserService userService) {this.userService = userService;}public void hello(){System.out.println("hello userController");userService.hello();}}

        如果有多个构造方法,就必须使用@Autowired注解+构造方法指明应该使用哪个构造方法来注入属性:

@Controllerpublic class UserController {public UserService userService;public UserConfiguration userConfiguration;public UserController(UserService userService) {this.userService = userService;}@Autowiredpublic UserController(UserService userService, UserConfiguration userConfiguration) {this.userService = userService;this.userConfiguration = userConfiguration;}public void hello(){System.out.println("hello userController");userService.hello();userConfiguration.hello();}}

4.3 Setter方法注入

@Controllerpublic class UserController {public UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public void hello(){System.out.println("hello userController");userService.hello();}}

        Setter方法注入也需要搭配上@Autowired注解。

4.4 三种方式优缺点

(1)属性注入

        优点:使用简单。

        缺点:1.只能用于loC容器(Spring框架),不能用在非loC容器。2.并且只有使用时才能知道Bean是否为Null。3.不能注入final类型的属性,因为final类型的属性需要声明时就初始化/声明时不初始化但是需要在构造方法初始化(那还不如用构造方法注入)。

(2)构造方法注入

        优点:1.可以注入final类型的属性。2.一旦注入对象后不会被修改。3.依赖的对象在使用前就可以被初始化完成,因为依赖注入是在构造方法中完成的,而构造方法在类加载时期就会执行。4.通用性好,构造方法属于JDK的,更换其他框架也适用。

        缺点:注入多个对象,代码会繁琐,因为可能需要写多种构造方法。

(3)Setter方法注入

        优点:方便在类实例后,重新对对象进行配置或注入。

        缺点:1.不能注入final类型的属性。2.注入的对象有被修改的风险,因为Setter方法在运行期间可以被多次调用。

4.5 @Autowired原理

(1)@Autowired原理与问题

        @Autowired的原理是先根据对象类型获取对象,如果存在一个就注入。如果匹配到多个,再根据对象名称获取对象,此时如果获取到对象就注入,否则就报错有多个同一类型的类型。

        因此,如果通过对象类型获取对象的时候,同一个类型匹配到多个Bean,就会报错。

@Componentpublic class UserCompeonent {public void hello(){System.out.println("hello userCompeonent");}@Beanpublic UserInfo getUser1(){UserInfo user1 = new UserInfo(100,"zhangsan",20);return user1;}@Beanpublic UserInfo getUser2(){UserInfo user2 = new UserInfo(101,"lisi",21);return user2;}}

(2)解决方法

        修改属性名为对象名称不建议使用,因为通常认为变量名与程序的业务逻辑无关,即修改变量名不影响程序的运行。但是这里如果修改变量名就会报错。

        @Primary:在多个Bean的某一个前加上@Primary,表示该Bean是优先被注入的对象。

@Componentpublic class UserCompeonent {public void hello(){System.out.println("hello userCompeonent");}@Primary@Beanpublic UserInfo getUser1(){UserInfo user1 = new UserInfo(100,"zhangsan",20);return user1;}@Beanpublic UserInfo getUser2(){UserInfo user2 = new UserInfo(101,"lisi",21);return user2;}}@Controllerpublic class UserController {@Autowiredpublic UserInfo user1;public void hello(){System.out.println("hello userController");System.out.println(user1);}}

        @Qualifier:搭配@Autowired注解使用,在要注入的属性前加上@Qualifier(“对象名称”),指定要注入的对象。

@Controllerpublic class UserController {@Qualifier("getUser2")@Autowiredpublic UserInfo user;public void hello(){System.out.println("hello userController");System.out.println(user);}}

        @Resource:不使用@Autowired注解进行注入了,直接使用@Resource(name=“对象名称”)进行注入。

@Controllerpublic class UserController {@Resource(name = "getUser1")public UserInfo user;public void hello(){System.out.println("hello userController");System.out.println(user);}}

(3)@Autowired与@Resource区别

        1.从通用性角度来讲:@Autowired是Spring框架提供的注解,只适用Spring框架搭建的程序中。@Resource是JDK提供的注解,使用与Java的所有范围。

        2.从注入方式来讲:@Autowired初始按对象类型注入,没有找到对象就按对象名称注入。@Resource是对象名称注入,并且支持更多参数,最简单的就是按name参数进行按对象名称注入。

下篇文章:

Spring-AOPhttps://blog.csdn.net/sniper_fandc/article/details/148960179?fromshare=blogdetail&sharetype=blogdetail&sharerId=148960179&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link

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

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

相关文章

职业本科单片机与嵌入式技术实训室建设设想

一、引言 在当今数字化与智能化飞速发展的时代,单片机与嵌入式技术作为信息技术领域的关键支撑,广泛应用于工业控制、智能家居、物联网、汽车电子等众多行业,成为推动产业升级和创新发展的核心驱动力。职业本科教育旨在培养适应生产、建设、…

传统消防演练与 VR 消防演练的区别有哪些

演练形式:传统消防演练往往依托真实的场地,像空旷的广场、废弃的建筑物或是专门的消防训练基地等。参与者能触摸并使用实实在在的消防设备,例如干粉灭火器、二氧化碳灭火器、消防水带等。在演练时,会通过点燃模拟火源、释放烟雾等…

【零基础学AI】 第6讲:数据可视化基础

本节课你将学到 理解数据可视化在AI中的重要作用 掌握Matplotlib的基本架构和核心概念 学会创建各种类型的图表(线图、柱状图、散点图、饼图等) 掌握图表美化和自定义技巧 完成销售趋势图表制作实战项目 开始之前 什么是数据可视化? 数据可…

基于SSM+JSP 的旅游管理系统

【旅游景点管理系统】【送文档】|SSM | JSP 【运行开发环境】 jdk1.8 idea mysql maven tomcat 【技术栈】 Spring SpringMVC mybatis JSP 【项目功能】 两个角色;管理员功能有游客管理、轮播图管理、景点管理、景点类型管理;普…

系统 | 电脑重置 图文教程

背景: 换内存条,换完,声卡网卡崩盘,分析原因可能是未断电操作(什么光感自动断电 还是手动的香),网卡由于代理没关,关完即可。声卡一直没好,电脑店说是硬件问题;自行排查了…

MyBatis深度面试指南

一、MyBatis核心解析:半ORM框架的底层真相 1. 本质与工作流 半ORM定义: 对象映射:通过ResultMap将ResultSet自动转为Java对象(省去JDBC手动映射)。SQL控制:开发者需手动编写SQL,框架不自动生成(与Hibernate核心区别)。工作流四步: 解析mybatis-config.xml → 构建Sq…

使用Docker部署mysql8

1、拉取mysql8的镜像: 1 [rooti-zgn6som8 ~]# docker pull mysql:8.0 2、创建配置和数据文件夹并修改权限: 1 2 3 4 mkdir -p /data/mysql8/conf mkdir -p /data/mysql8/data chmod -R 755 /data/mysql8/ 3、配置一个自定义的配置文件my.cnf: 1 …

Vue3—插槽solt

默认插槽 父组件 <Sidebar><div>{{ strData }}</div></Sidebar> let strData ref(我是你爸爸真伟大&#xff0c;养你这么大);//定义插槽数据子组件 <slot>没有数据&#xff0c;我先默认显示一下 loading。。。。。。。</slot>父组件提供…

时间同步 gptp ptp

目录 车载以太网PTP报文分析**PTP协议基础****PTP报文类型与功能****PTP报文格式解析****时钟同步原理与计算****车载以太网PTP分析工具****典型分析场景****车载场景特殊考虑**gPTP与PTP的对比解析**1. 基本概念****2. 核心差异对比****3. 技术细节对比****报文结构****主时钟…

AWS WebRTC:通过shell实现多进程启动viewer

​ 前面总结了aws webrtc sdk-c项目中多进程启动master的shell脚本,具体参考:https://blog.csdn.net/zhang_jiamin/article/details/148616899 这次总结一下多进程启动viewer的shell脚本,以及过程中遇到的问题和解决方法。 实现说明: 1、获取 sid 和 uid(用于认证) 2、…

设计模式(策略,工厂,单例,享元,门面)+模板方法

文章目录 前提策略模式思想实现如何拓展 模板方法存在的问题思想实现如何拓展 工厂模式实现问题及解决(解耦)配置文件方式使用注解 单例模式实现方式1,懒汉式(线程不安全)2,懒汉式(线程安全)3,饿汉式4,双重校验锁机制(面)5,静态内部类6,枚举 体现 享元模式门面模式 前提 假设做…

libarchive压缩解压文件

存在中文乱码问题 官网&#xff1a; libarchive - 用于读取和写入 tar、cpio、zip、ISO 和其他存档格式的 C 库和命令行工具 GitHub GitHub源码&#xff1a;Bluewind/libarchive: Multi-format archive and compression library (github.com) 参考&#xff1a; C archive_w…

AutoGPT,自主完成复杂任务

AutoGPT是一个开源的AI Agent项目&#xff0c;它的核心目标是让AI能够自主完成复杂任务&#xff0c;而不仅仅是回答单个问题。简单来说&#xff0c;它让AI具备了"自主思考和行动"的能力。 1. AutoGPT的核心概念 什么是AI Agent&#xff1f; AI Agent&#xff08;智…

lambda、function基础/响应式编程基础

lambda表达式 只要是函数式接口&#xff08;接口内只有一个未实现的方法&#xff0c;可以有其它默认方法&#xff09;&#xff0c;就可以用lambda表达式&#xff0c;也就是快速new一个匿名内部类。 实例化接口的三种方式 继承接口&#xff0c;并实现接口 直接实现匿名内部类 …

OpenTiny 体验官实操活动 | 快速体验 TinyVue 组件库的智能化交互能力

实验简介 通过体验基于标准 MCP 协议的 Web 智能组件库——TinyVue&#xff0c;开发者可以了解 AI 智能体控制 TinyVue 智能组件的各类行为。本次实验主要是在 TinyVue 官网上&#xff0c;开发者能够通过 AI 对话框&#xff0c;以语音或文字方式与网站组件进行互动&#xff0c…

秋招Day15 - Redis - 基础

什么是Redis&#xff1f; Redis是一种基于键值对的NoSQL数据库。 主要的特点是把数据放在内存中&#xff0c;读写速度相比于磁盘会快很多。 对于性能要求很高的场景&#xff0c;比如缓存热点数据&#xff0c;防止接口爆刷&#xff0c;都会用到Redis Redis还支持持久化&…

权限提升-工作流

一、Windows 权限提升 操作阶段 对应工具 说明 系统补丁与漏洞查询 systeminfo、WindowsVulnScan、wesng 提取 KB 补丁号&#xff0c;匹配 CVE 漏洞&#xff08;如 CVE-2020-1054&#xff09; 内核漏洞提权 MSF&#xff08;local_exploit_suggester&#xff09;、CVE 对…

c++手撕线程池

C手撕线程池 #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <time.h>#define LL_ADD(item, list) do{ \item->prev NULL; \item->next list; \if…

cocos creator 3.8 - 精品源码 - 六边形消消乐(六边形叠叠乐、六边形堆叠战士)

cocos creator 3.8 - 精品源码 - 六边形消消乐 游戏介绍功能介绍免费体验下载开发环境游戏截图免费体验 游戏介绍 六边形堆叠战士(六边形消消消)是一款脱胎于2048、1010&#xff0c;基于俄罗斯方块的魔性方块达人小游戏&#xff0c;可以多方向多造型消除哦&#xff01; 功能介…

3ds Max高效运行配置核心要素

要保障3ds Max流畅运行&#xff0c;需围绕计算性能、图形处理、数据吞吐三大维度构建硬件体系。不同工作环节对硬件需求存在显著差异&#xff1a; 一、核心组件配置原则 CPU&#xff1a;线程与频率双优化 建模/视口操作&#xff1a;依赖高主频&#xff08;建议≥4.0GHz&#…