【后端开发】初识Spring IoC与SpringDI、图书管理系统
文章目录
- 图书管理系统
- 用户登录
- 需求分析
- 接口定义
- 前端页面代码
- 服务器代码
- 图书列表展示
- 需求分析
- 接口定义
- 前端页面部分代码
- 服务器代码
- Controller层
- service层
- Dao层
- modle层
- Spring IoC
- 定义
- 传统程序开发
- 解决方案
- IoC优势
- Spring DI
- IoC &DI使用
- 主要注解
- Spring IoC详解
- bean的存储
- 五大注解
- @Controller(控制器存储)
- getBean()方法
- 面试:ApplicationContext VS BeanFactory
- 为什么要这么多类注解
- 五大注解是否可以混用
- 程序被Spring管理的条件
- 方法注解--@Bean
- 扫描路径
- Spring DI详解
- 属性注入
- 构造方法注入
- Setter注入
- 优缺点
- @Autowired存在的问题
- @Primary
- @Qualifier
- @Resource
- 面试--@Autowird 与 @Resource的区别
图书管理系统
用户登录
需求分析
账号密码校验接口:根据输入用户名和密码校验登录是否通过。
接口定义
- url:/user/login
- type:post
- 请求参数:name=admin&password=admin
- 返回:true //账号密码验证成功,false//账号密码验证失败
前端页面代码
<body><div class="container-login"><div class="container-pic"><img src="pic/computer.png" width="350px"></div><div class="login-dialog"><h3>登陆</h3><div class="row"><span>用户名</span><input type="text" name="userName" id="userName" class="form-control"></div><div class="row"><span>密码</span><input type="password" name="password" id="password" class="form-control"></div><div class="row"><button type="button" class="btn btn-info btn-lg" onclick="login()">登录</button></div></div></div><script src="js/jquery.min.js"></script><script>function login() {$.ajax({url: "/user/login",type: "post",data: {userName: $("#userName").val(),password: $("#password").val()},success: function (result) {if (result == "") {location.href = "book_list.html";} else {alert(result)}}})}</script>
</body>
服务器代码
@RequestMapping("/user")
@RestController
public class UserController {@RequestMapping("/login")public String login(String userName, String password, HttpSession session) {//1.校验参数//2.验证密码是否正确//3.返回结果if (!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)) {return "用户名或密码为空";}//理论上应该从数据库中读取,暂时先不用//一般正确情况下,会有后续的操作,因此建议将后续操作比较多的情况下放在括号外面if (!"admin".equals(userName) || !"admin".equals(password)) {return "密码错误";}session.setAttribute("userName", userName);return "";}
}
图书列表展示
需求分析
图书列表:提供图书列表信息
接口定义
- url:/user/login
- type:post
- 请求参数:无
- 返回:
[{“id”: 1,
“bookName”:“book1”,
“author” :“author1”,
“count”:270,
“price”: 20”,
publish":“publish1”,
“status”: 1,
“statusCN”:“可借阅”}…]
前端页面部分代码
<script>//这里需要直接访问到后端的图书列表信息,直接需要访问到后端,所以直接开始就使用ajax,但是为了代码的可读性,将其封装到一个方法里面先getBookList();function getBookList() {$.ajax({url:"/book/getBookList",type:"get",success:function(books){var finalHtml = "";//下面使用单引号的原因是因为html中也有双引号,可能会造成出错for(var book of books){finalHtml += '<tr>';finalHtml += '<td><input type="checkbox" name="selectBook" value="'+book.id+'" id="selectBook" class="book-select"></td>';finalHtml += '<td>'+book.id+'</td>';finalHtml += '<td>'+book.bookName+'</td>';finalHtml += '<td>'+book.author+'</td>';finalHtml += '<td>'+book.num+'</td>';finalHtml += '<td>'+book.price+'</td>';finalHtml += '<td>'+book.publishName+'</td>';finalHtml += '<td>'+book.statusCN+'</td>';finalHtml += '<td>';finalHtml += ' <div class="op">';finalHtml += '<a href="book_update.html?bookId='+book.id+'">修改</a>';finalHtml += '<a href="javascript:void(0)" onclick="deleteBook('+book.id+')">删除</a>';finalHtml += '</div></td></tr>';}$("tbody").html(finalHtml);}})}
服务器代码
Controller层
@RequestMapping("/book")
@RestController
public class BookController {@Autowiredprivate BookService bookService;@RequestMapping("/getBookList")public List<BookInfo> getBookList() {
// BookService bookService = new BookService();return bookService.getBookList();}
}
service层
@Component
public class BookService {@Autowiredprivate BookDao bookDao;public List<BookInfo> getBookList(){
// BookDao bookDao = new BookDao();List<BookInfo> bookInfos = bookDao.mockData();for (BookInfo bookInfo : bookInfos) {if (bookInfo.getStatus() == 2){bookInfo.setStatusCN("不可借阅");}else {bookInfo.setStatusCN("可借阅");}}return bookInfos;}
}
Dao层
@Component
public class BookDao {//理论上该方法应该从数据库中获取,当前采用mock方式public List<BookInfo> mockData(){List<BookInfo> bookInfos = new ArrayList<BookInfo>();//mock数据,也就是测试时候所有的模拟数据for (int i = 1; i <= 15; i++) {BookInfo bookInfo = new BookInfo();bookInfo.setId(i);bookInfo.setAuthor("作者" + i);bookInfo.setBookName("图书" + i);bookInfo.setNum(i * 2 + 1);bookInfo.setPrice(new BigDecimal(i*3));bookInfo.setPublishName("出版社" + i);if (i % 5 == 0){bookInfo.setStatus(2);
// bookInfo.setStatusCN("不可借阅");}else {bookInfo.setStatus(1);
// bookInfo.setStatusCN("可借阅");}bookInfos.add(bookInfo);}return bookInfos;}
}
modle层
@Data
public class BookInfo {private Integer id;private String bookName;private String author;private Integer num;private BigDecimal price;private String publishName;private Integer status;//1-可借阅 0-不可借阅 这里的数据都是要存放到数据库中的,尽量减少往数据库中存放文字信息private String statusCN;//这个字段不用网数据库中存储,仅是为了与status进行文字与数字的转换
}
Spring IoC
Spring的抽象概念:Spring是包含了众多⼯具⽅法的IoC容器。
定义
IoC 是Spring的核心思想,之前项目在类上添加 @Restcontroller 和@Controller 注解,就是把这个对象交给Spring管理,Spring框架启动时就会加载该类,把对象交给Spring管理,就是loC思想。
loC:Inversion of Control(控制反转),也就是说 Spring是一个"控制反转"的容器。
什么是控制反转呢?也就是控制权反转,什么的控制权发生了反转?
获得依赖对象的过程被反转了也就是说,当需要某个对象时,传统开发模式中需要自己通过 new 创建对象,现在不需要再进行创建,把创建对象的任务交给容器,程序中只需要依赖注入(DependencyInjection, Dl)就可以了这个容器称为:loC容器,Spring是一个loC容器,所以有时Spring 也称为Spring 容器。
传统程序开发
比如开发一个汽车,传统的设计思路为:
先设计轮子(Tire),然后根据轮子的大小设计底盘(Bottom),接着根据底盘设计车身(Framework),后根据车身设计好整个汽车(Car)。
这里就出现了一个"依赖"关系:汽车依赖车身,车身依赖底盘,底盘依赖轮子。
也就是Car类依赖Framework类,Framework类依赖Bottom类,Bottom类依赖Tire类。
这样的设计看起来没问题,但是可维护性却很低,接下来需求有了变更:随着对的车的需求量越来越大,个性化需求也会越来越多,我们需要加工多种尺寸的轮胎。
此时,开发一个汽车需要依赖再依赖,直至依赖到轮胎的尺寸,也就是下面的改法。
public static void main(String[] args) {public static void main(String[] args) {Car car = new Car(20);car.run();}}public class Car {private Framework framework;public Car(int size) {framework = new Framework(size);System.out.println("Car init....");}public void run() {System.out.println("Car run...");}
}public class Framework {private Bottom bottom;public Framework(int size) {bottom = new Bottom(size);System.out.println("Framework init...");}
}public class Bottom {private Tire tire;public Bottom(int size) {this.tire = new Tire(size);System.out.println("Bottom init...");}
}public class Tire {private int size;public Tire(int size) {this.size = size;System.out.println("轮胎尺⼨: " + size);}
}
以上代码可以看出,以上程序的问题是:当最底层代码改动之后,整个调用链上的所有代码都需要修改,程序的耦合度非常高(修改一处代码,影响其他处的代码修改)。
解决方案
我们尝试换一种思路,先设计汽车的大概样子,然后根据汽车的样子来设计车身,根据车身来设计底盘,最后根据底盘来设计轮子。这时候,依赖关系就倒置过来了:轮子依赖底盘,底盘依赖车身,车身依赖汽车。

可以尝试不在每个类中创建下级类,如果创建下级类就会出现当下级类发生改变操作,自己也要跟着修改。
此时,只需要将原来由自己创建的下级类,改为传递的方式(也就是注入的方式),因为我们不需要在当前类中创建下级类了,所以下级类即使发生变化(创建或减少参数),当前类本身也无需修改任何代码,这样就完成了程序的解耦。
public class Main {public static void main(String[] args) {Tire tire = new Tire(20);Bottom bottom = new Bottom(tire);Framework framework = new Framework(bottom);Car car = new Car(framework);car.run();}
}public class Car {private Framework framework;public Car(Framework framework) {this.framework = framework;System.out.println("Car init....");}public void run() {System.out.println("Car run...");}
}public class Car {private Framework framework;public Car(Framework framework) {this.framework = framework;System.out.println("Car init....");}public void run() {System.out.println("Car run...");}
}public class Framework {private Bottom bottom;public Framework(Bottom bottom) {this.bottom = bottom;System.out.println("Framework init...");}
}public class Bottom {private Tire tire;public Bottom(Tire tire) {this.tire = tire;System.out.println("Bottom init...");}
}public class Tire {private int size;public Tire(int size) {this.size = size;System.out.println("轮胎尺⼨: " + size);}
}
代码经过以上调整,无论底层类如何变化,整个调用链是不用做任何改变的,这样就完成了代码之间的解耦,从而实现了更加灵活、通用的程序设计了。
IoC优势
在传统的代码中对象创建顺序是:Car>Framework->Bottom->Tire
改进之后解耦的代码的对象创建顺序是:Tire->Bottom->Framework ->Car
改进之后的控制权发生的反转,不再是使用方对象创建并控制依赖对象了,而是把依赖对象注入将当前对象中,依赖对象的控制权不再由当前类控制了。
这样的话,即使依赖类发生任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是IoC的实现思想。
loC容器具备以下优点
- 资源集中管理:loC容器会帮助管理一些资源(对象等),需要使用时,只需要从loC容器中去取就可以了。
- 解耦合:在创建实例的时候不需要了解其中的细节,降低了使用资源双方的依赖程度,也就是耦合度。
Spring 就是一种loC容器,帮助我们来做了这些资源管理。
Spring DI
Dl:DependencyInjection(依赖注入),容器在运行期间,动态的为应用程序提供运行时所依赖的资源,称之为依赖注入。
程序运行时需要某个资源,此时容器就为其提供这个资源。
从这点来看,依赖注入(DI)和控制反转(l0C)是从不同的角度的描述的同一件事情,就是指通过引入loC容器,利用依赖关系注入的方式,实现对象之间的解耦。
上述代码通过构造函数的方式,把依赖对象注入到需要使用的对象中。
IoC是一种思想,也是"目标",而思想只是一种指导原则,最终还是要有可行的落地方案,而 DI 就属于具体的实现。
所以也可以说,DI是loC的一种实现。
IoC &DI使用
既然 Spring 是一个 loC(控制反转)容器,作为容器,那么它就具备两个最基础的功能:存、取。
Spring 容器管理的主要是对象,这些对象,我们称之为"Bean"。把这些对象交由Spring管理,由Spring来负责对象的创建和销毁,程序只需要告诉Spring,哪些需要存,以及如何从Spring中取出对象。
主要注解
@Component:交给Spring管理
@Autowired:注入运行时依赖的对象
@Component
public class BookService {@Autowiredprivate BookDao bookDao;public List<BookInfo> getBookList(){
// BookDao bookDao = new BookDao();List<BookInfo> bookInfos = bookDao.mockData();for (BookInfo bookInfo : bookInfos) {if (bookInfo.getStatus() == 2){bookInfo.setStatusCN("不可借阅");}else {bookInfo.setStatusCN("可借阅");}}return bookInfos;}
}
Spring IoC详解
前⾯提到IoC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象,也就是bean的存储。
bean的存储
五大注解
- 五大类注解:@Controller、@Service、@Repository、@Component、@Configuration 。
- bean对象:在spring容器中存放的对象。
- ApplicationContext: 翻译为Spring上下文,指的就是当前的运行环境,也可以看作是⼀个容器。故ApplicationContext的对象中存放了所有与当前的运行环境有关的内容,比如 spring容器中存放的bean对象。
@Controller(控制器存储)
这里仅展示@Controller,其他四个注解与@Controller类似。
将UserControllerTest类用@Controller注解存放到IoC容器中。
@Controller
public class UserControllerTest {public void say(){System.out.println("hello, UserControllerTest");}
}
getBean()方法
这里分别使用三种getBean()方法来获取UserController对象,进行打印测试

@SpringBootApplication
public class LibraryApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(LibraryApplication.class, args);UserControllerTest bean = context.getBean(UserControllerTest.class);bean.say();System.out.println(bean);UserControllerTest userControllerTest = (UserControllerTest) context.getBean("userControllerTest");userControllerTest.say();System.out.println(userControllerTest);UserControllerTest userControllerTest1 = context.getBean("userControllerTest", UserControllerTest.class);userControllerTest1.say();System.out.println(userControllerTest1);}
}

结果成功输出也就是获取到了UserControllerTest对象,并且地址一样,说明是一个对象。
获取对象的功能是Application的父类BeanFactory的功能。
面试:ApplicationContext VS BeanFactory
继承关系和功能方面来说:Spring 容器有两个顶级的接口BeanFactory和ApplicationContext。
其中 BeanFactory 提供了基础的访问容器的能力,而ApplicationContext 属于 BeanFactony 的子类,它除了继承了 BeanFactory 的所有功能之外,它还拥有独特的特性,还添加了环境管理支持、资源访问支持、以及事件传播等方面的支持。
从性能方面来说:ApplicationContext 是一次性加载并初始化所有的 Bean 对象,而BeanFactory 是需要那个才去加载那个,因此更加轻量(空间换时间)。
为什么要这么多类注解
与应用分层呼应,让程序员看到类注解之后,就能直接了解当前类的用途。
- @Controller:控制层,接收请求,对请求进行处理,并进行响应
- @Servie:业务逻辑层,处理具体的业务逻辑
- @Repository:数据访问层,也称为持久层,负责数据访问操作
- @Configuration:配置层,处理项目中的一些配置信息
- @Component:是一个元注解,也就是说可以注解其他类注解@Controller,@Service,@Repository,@Confiquraion,这些注解被称为@Component 的行生注解,因为这些注解源代码里面都有一个注解@Component。
五大注解是否可以混用
功能上:@Service @Repository @Configuration @Component 可以完全混用,@Controller有自己的特殊性。
规范上:不可以混用。因为我们想要与应用分层呼应。

程序被Spring管理的条件
- 程序要被spring扫描到(默认路径是启动类所在的目录以及子目录),手动设置:@ComponentScan(basePackages = “~”)
- 程序需要配置五大注解和@Bean
方法注解–@Bean
@Bean要搭配类注解使用
类注解是添加到某个类上的,但是存在两个问题:
- 使用外部包里的类,没办法添加类注解
- 一个类,需要多个对象,比如多个数据源
示例1,@Bean要搭配类注解使用
@Configuration
public class UserConfig {public void say(){System.out.println("hi,UserConfig");}@Beanpublic User user(){return new User("张三");}
}
示例2:定义多个对象,使用类的类型扫描
@Service
public class UserService {public void say(){System.out.println("hello, UserService");}@Beanpublic BookInfo user(){return new BookInfo();}@Beanpublic BookInfo user1(){return new BookInfo();}
}@SpringBootApplication
public class LibraryApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(LibraryApplication.class, args);BookInfo bean = context.getBean(BookInfo.class);System.out.println(bean);}
}
通过类的类型扫描,这里出现了报错,通过类的类型扫描,此时容器中有两个User对象,根据类型获取对象,此时Spring不知道要获取哪个对象,所以报错了。

解决办法:用类的名字扫描。
@SpringBootApplication
public class LibraryApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(LibraryApplication.class, args);BookInfo bean1 = (BookInfo) context.getBean("user");System.out.println(bean1);BookInfo bean2 = (BookInfo) context.getBean("user1");System.out.println(bean2);}
}

扫描路径
把启动类放到其他的目录下面,再次启动程序,会出错。

就是因为没有找到对应的bean对象,使用五大注解声明的bean,要想生效,还需要配置扫描路径,让Spring扫描到这些注解也就是通过 @ComponentScan 来配置扫描路径。
@ComponentScan({"com.example.library"})
@SpringBootApplication
public class LibraryApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(LibraryApplication.class, args);}
}
Spring DI详解
DI(依赖注入):依赖注入是一个过程,是指loC容器在创建Bean时,去提供运行时所依赖的资源,而资源指的就是对象在上面程序案例中,我们使用了 @Autowired 这个注解,完成了依赖注入的操作简单来说,就是把对象取出来放到某个类的属性中。
在一些文章中,依赖注入也被称之为"对象注入”、"属性装配”,具体含义需要结合文章的上下文来理解。
关于依赖注入, Spring也给我们提供了三种方式:
属性注入(Field Injection)
构造⽅法注入(Constructor Injection)
Setter 注入(Setter Injection)
属性注入
@Controller
public class UserControllerTest {@Autowiredprivate UserService userService;//属性注入public void say(){System.out.println("hello, UserControllerTest");}
}
构造方法注入
只有一个构造方法的时候即使不加@Autowired也可以获取数据,但是要是加一个空的构造方法,会报出空指针异常。
因为程序启动的时候会首先调用无参数的构造方法,如果没有会调用我们写的,但是两个都有的话就会调用无参数的,此时并没有真正new对象,去调用say()方法就会出现空指针异常。
解决办法:就是在想要注入的构造方法中添加@Autowired注解
@Controller
public class UserControllerTest {private UserService userService;@Autowiredpublic UserService(UserService service){this.userService = service;}public void say(){System.out.println("hello, UserControllerTest");}
}
Setter注入
@Controller
public class UserControllerTest {private UserService userService;@Autowiredpublic void setUserService(UserService service){this.userService = service;}public void say(){System.out.println("hello, UserControllerTest");}
}
优缺点
- 属性注入
优点:简洁,使用方便
缺点:只能用于 loC 容器,如果是非 loC 容器不可用,并且只有在使用的时候才会出现 NPE(空指针异常);不能注入一个Final修饰的属性。 - 构造函数注入(Spring4.x推荐)
优点:可以注入final修饰的属性;注入的对象不会被修改依赖对象;在使用前一定会被完全初始化,因为依赖是在类的构造方法中执行的,而构造方法是在类加载阶段就会执行的方法;通用性好,构造方法是JDK支持的,所以更换任何框架都是适用的。
缺点:注入多个对象时,代码会比较繁琐。 - Setter注入
优点:方便在类实例之后,重新对该对象进行配置或者注入。
缺点:不能注入一个Final修饰的属性;注入对象可能会被改变,因为setter方法可能会被多次调用,就有被修改的风险。
@Autowired存在的问题
Student 实体类
@Data
public class Student {private String name;private Integer id;public Student() {}public Student(String name) {this.name = name;}public Student(String name, Integer id) {this.name = name;this.id = id;}
BeanConfig类
@Configuration
public class BeanConfig {@Beanpublic Student StudentInfo() {return new Student("wh",01);}@Beanpublic Student StudentInfo2() {return new Student("Bob",02);}
}
DomeController类
@Controller
public class DomeController {@Autowiredprivate Student student;public void say(){System.out.println(student);}
}
启动类
@SpringBootApplication
public class SpringIocApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(SpringIocApplication.class, args);DomeController bean = context.getBean(DomeController.class);bean.say();}
}
运行

报错的原因是,非唯一的 Bean 对象
解释:@Autowired是先按照类型去注入,匹配到多个对象时,再按照名称去注入。
如果明确注入对象的名称,则可以正确打印该学生信息。
@Controller
public class DomeController {@Autowiredprivate Student StudentInfo2;public void say(){System.out.println(StudentInfo2);}
}
那当没有明确注入对象的名称,又想得到正确结果我们可以怎么做?
有以下几种解决方案:
@Primary
@Qualifier
@Resource
@Primary
使用@Primary注解:当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现。
直接加到Bean注入的方法上。
@Primary
@Bean
public Student StudentInfo() {return new Student("wh", 01);
}
@Qualifier
使⽤@Qualifier注解:指定当前要注⼊的bean对象。 在@Qualifier的value属性中,指定注⼊的bean 的名称。
@Qualifier注解不能单独使⽤,必须配合@Autowired使用。
@Controller
public class DomeController {@Qualifier("StudentInfo2")@Autowiredprivate Student student;public void say(){System.out.println(student);}
}
@Resource
本身就是依赖注入注解,是按照bean的名称进行注入。
@Controller
public class DomeController {@Resource(name = "StudentInfo")private Student student;public void say(){System.out.println(student);}
}
面试–@Autowird 与 @Resource的区别
- @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解。
- @Autowired 默认是按照类型注入,而@Resource是按照名称注入,相比于 @Autowired 来说, @Resource ⽀持更多的参数设置,例如 name 设置,根据名称获取 Bean。
相关文章:
【后端开发】初识Spring IoC与SpringDI、图书管理系统
文章目录 图书管理系统用户登录需求分析接口定义前端页面代码服务器代码 图书列表展示需求分析接口定义前端页面部分代码服务器代码Controller层service层Dao层modle层 Spring IoC定义传统程序开发解决方案IoC优势 Spring DIIoC &DI使用主要注解 Spring IoC详解bean的存储五…...
Vim 编辑器的常用快捷键介绍
以下是 Vim 编辑器的常用快捷键分类介绍,帮助你快速掌握高效编辑技巧: 一、基础模式切换 Vim 的核心是 模式化操作,常用模式包括: 普通模式(默认):导航、命令输入。插入模式:输入/…...
git在IDEA中使用技巧
git在IDEA中使用技巧 merge和rebase 参考:IDEA小技巧-Git的使用 git回滚、强推、代码找回 参考:https://www.bilibili.com/video/BV1Wa411a7Ek?spm_id_from333.788.videopod.sections&vd_source2f73252e51731cad48853e9c70337d8e cherry pick …...
榕壹云无人共享系统:基于SpringBoot+MySQL+UniApp的物联网共享解决方案
无人共享经济下的技术革新 随着无人值守经济模式的快速发展,传统共享设备面临管理成本高、效率低下等问题。榕壹云无人共享系统依托SpringBootMySQLUniApp技术栈,结合物联网与移动互联网技术,为商家提供低成本、高可用的无人化运营解决方案。…...
ARCGIS PRO DSK 利用两期地表DEM数据计算工程土方量
利用两期地表DEM数据计算工程土方量需要准许以下数据: 当前地图有3个图层,两个栅格图层和一个矢量图层 两个栅格图层:beforeDem为工程施工前的地表DEM模型 afterDem为工程施工后的地表DEM模型 一个矢量图层…...
考研408参考用书:计算机组成原理(唐朔飞)介绍,附pdf
我用夸克网盘分享了「《计算机组成原理》第2,3版 唐朔飞」, 链接:https://pan.quark.cn/s/6a87d10274a3 1. 书籍定位与适用对象 定位:计算机组成原理是计算机科学与技术、软件工程等专业的核心基础课程,涉及计算机硬件的底层工作原…...
大数据(7.2)Kafka万亿级数据洪流下的架构优化实战:从参数调优到集群治理
目录 一、海量数据场景下的性能之殇1.1 互联网企业的数据增长曲线1.2 典型性能瓶颈分析 二、生产者端极致优化2.1 批量发送黄金法则2.1.1 分区选择算法对比 2.2 序列化性能突破 三、消费者端并发艺术3.1 多线程消费模式演进3.1.1 消费组Rebalance优化 3.2 位移管理高阶技巧 四、…...
国网B接口云镜控制接口流程详解以及检索失败原因(电网B接口)
文章目录 一、B接口协议云镜控制接口介绍B.8.1 接口描述B.8.2 接口流程B.8.3 接口参数B.8.3.1 SIP头字段B.8.3.2 SIP响应码B.8.3.3 XML Schema参数定义 B.8.4 消息示例B.8.4.1 云镜控制请求B.8.4.2 云镜控制请求响应 二、B接口云镜控制失败常见问题(一)网…...
vue3使用keep-alive缓存组件与踩坑日记
目录 一.了解一下KeepAlive 二.使用keep-alive标签缓存组件 1.声明Home页面名称 三.在路由出口使用keep-alive标签 四.踩坑点1:可能需要配置路由(第三点完成后有效可忽略) 五.踩坑点2:没有找到正确的路由出口 一.了解一下Kee…...
gpt2 本地调用调用及其调用配置说明
gpt2 本地调用调用及其调用配置说明 环境依赖安装,模型下载 在大模型应用开发中,需要学会本地调用模型, 要在本地环境调用gpt2 模型需要将模型下载到本地,这里记录本地调用流程: 在huggingface 模型库中查找到需要使…...
【Abstract Thought】【Design Patterns】python实现所有个设计模式【下】
前言 彼岸花开一千年,花开花落不相见。 若问花开叶落故,彼岸缘起缘又灭——《我欲封天》 \;\\\;\\\; 目录 前言简单的设计模式复杂的设计模式13责任链14迭代器15备忘录16状态机17模板方法18访问者19观察者20命令Shell21策略22调解23解释器 简单的设计模…...
【物联网】PWM控制蜂鸣器
文章目录 一、PWM介绍1.PWM的频率2.PWM的周期 二、PWM工作原理分析三、I.MX6ull PWM介绍1.时钟信号2.工作原理3.FIFO 四、PWM重点寄存器介绍1.PWM Control Register (PWMx_PWMCR)2.PWM Counter Register (PWMx_PWMCNR)3.PWM Period Register (PWMx_PWMPR)4.PWM Sample Register…...
Python----机器学习(基于PyTorch的乳腺癌逻辑回归)
Logistic Regression(逻辑回归)是一种用于处理二分类问题的统计学习方法。它基于线性回归 模型,通过Sigmoid函数将输出映射到[0, 1]范围内,表示概率。逻辑回归常被用于预测某个实 例属于正类别的概率。 一、数据集介绍 在本例中&…...
5分钟学会接口自动化测试框架
今天,我们来聊聊接口自动化测试。 接口自动化测试是什么?如何开始?接口自动化测试框架如何搭建? 自动化测试 自动化测试,这几年行业内的热词,也是测试人员进阶的必备技能,更是软件测试未来发…...
基于FreeRTOS和LVGL的多功能低功耗智能手表(APP篇)
目录 一、简介 二、软件框架 2.1 MDK工程架构 2.2 CubeMX框架 2.3 板载驱动BSP 1、LCD驱动 2、各个I2C传感器驱动 3、硬件看门狗驱动 4、按键驱动 5、KT6328蓝牙驱动 2.4 管理函数 2.4.1 StrCalculate.c 计算器管理函数 2.4.2 硬件访问机制-HWDataAccess 2.4.3 …...
visual studio 常用的快捷键(已经熟悉的就不记录了)
以下是 Visual Studio 中最常用的快捷键分类整理,涵盖代码编辑、调试、导航等核心场景: 一、生成与编译 生成解决方案 Ctrl Shift B 一键编译整个解决方案,检查编译错误(最核心的生成操作)编译当前文件 Ctrl F…...
学习记录-接口自动化python数据类型
1.字符串 str "字符串" str_1 字符串1 2.列表[ ] list [1,2,3,4,5,6] list_1 ["boy","girl"] 3.字典{ } key:value 键值对 dict {"name":"小林","age":20} 4.元组( ) tuple …...
大语言模型深度思考与交互增强
总则:深度智能交互的全面升级 在主流大语言模型(LLM)与用户的每一次交互中,模型需于回应或调用工具前,展开深度、自然且无过滤的思考进程。当模型判断思考有助于提升回复质量时,必须即时进行全方位的思考与…...
<C#> 详细介绍.NET 依赖注入
在 .NET 开发中,依赖注入(Dependency Injection,简称 DI)是一种设计模式,它可以增强代码的可测试性、可维护性和可扩展性。以下是对 .NET 依赖注入的详细介绍: 1. 什么是依赖注入 在软件开发里࿰…...
布局决定终局:基于开源AI大模型、AI智能名片与S2B2C商城小程序的战略反推思维
摘要:在商业竞争日益激烈的当下,布局与终局预判成为企业成功的关键要素。本文探讨了布局与终局预判的智慧性,强调其虽无法做到百分之百准确,但能显著提升思考能力。终局思维作为重要战略工具,并非一步到位的战略部署&a…...
构建面向大模型训练与部署的一体化架构:从文档解析到智能调度
作者:汪玉珠|算法架构师 标签:大模型训练、数据集构建、GRPO、自监督聚类、指令调度系统、Qwen、LLaMA3 🧭 背景与挑战 随着 Qwen、LLaMA3 等开源大模型不断进化,行业逐渐从“能跑通”迈向“如何高效训练与部署”的阶…...
告别循环!用Stream优雅处理集合
什么是stream? 也叫Stream流,是jdk8新增的一套API(java.util.stream.*)可以用于操作集合或者数组的数据。 优势:Stream流大量的结合了Lambda语法的风格编程,提供了一种更加强大,更加简单的方式…...
Linux电源管理、功耗管理 和 发热管理 (CPUFreq、CPUIdle、RPM、thermal、睡眠 和 唤醒)
1 架构图 1.1 Linux内核电源管理的整体架构 《Linux设备驱动开发详解:基于最新的Linux4.0内核》图19.1 1.2 通用的低功耗软件栈 《SoC底层软件低功耗系统设计与实现》 1.3 低功耗系统的架构设计;图1-3 2 系统级睡眠和唤醒管理 Linux系统的待机、睡眠…...
OSCP - Proving Grounds -FunboxEasy
主要知识点 弱密码路径枚举文件上传 具体步骤 首先是nmap扫描一下,虽然只有22,80和3306端口,但是事情没那么简单 Nmap scan report for 192.168.125.111 Host is up (0.45s latency). Not shown: 65532 closed tcp ports (reset) PORT …...
探索 Go 与 Python:性能、适用场景与开发效率对比
1 性能对比:执行速度与资源占用 1.1 Go 的性能优势 Go 语言被设计为具有高效的执行速度和低资源占用。它编译后生成的是机器码,能够直接在硬件上运行,避免了 Python 解释执行的开销。 以下是一个用 Go 实现的简单循环计算代码: …...
c++:构造函数(Constructor)与析构函数(Destructor)
目录 为什么我们需要构造函数? 什么是构造函数? 🧬 本质:构造函数是“创建对象的一部分” 为什么 需要析构函数? 什么是析构函数? 析构函数的核心作用 ❗注意点 为什么我们需要构造函数?…...
三周年创作纪念日
文章目录 回顾与收获三年收获的五个维度未来的展望致谢与呼唤 亲爱的社区朋友们,大家好! 今天是 2025 年 4 月 14 日,距离我在 2022 年 4 月 14 日发布第一篇技术博客《SonarQube 部署》整整 1,095 天。在这条创作之路上,我既感慨…...
Vue 3 国际化实战:支持 Element Plus 组件和语言持久化
目录 Vue 3 国际化实战:支持 Element Plus 组件和语言持久化实现效果:效果一、中英文切换效果二、本地持久化存储效果三、element Plus国际化 vue3项目国际化实现步骤第一步、安装i18n第二步、配置i18n的en和zh第三步:使用 vue-i18n 库来实现…...
1.阿里云快速部署Dify智能应用
一、宝塔面板 宝塔面板是一款功能强大且易于使用的服务器管理软件,支持Linux和Windows系统,通过web端可视化操作,优化了建站流程,提供安全管理、计划任务、文件管理以及软件管理等功能。 1.1 宝塔面板的特点与优势 易用性 宝塔面…...
Ubuntu与windows时间同步
由于ubuntu每次重启后时间老是不对,所以使用ntp服务,让ubuntu作为客户端,去同步windows时间。 一、windows服务端配置 1、启用ntp服务 # 启动W32Time服务(若未启动) net start w32time # 配置服务为NTP模式 w32tm /…...

