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

Spring IOC:容器管理与依赖注入秘籍

Java Spring 核心容器、IOC 


一、IOC(控制反转)核心概念

基本概念

控制反转是一种将对象的创建、依赖关系的管理和生命周期的控制权从应用程序代码转移到外部容器的设计原则。在传统编程中,对象的创建和依赖关系是由程序自身控制的,而在 IOC 模式下,控制权被反转给了一个专门的容器。这个容器负责创建对象、注入依赖,并管理对象的生命周期,使得代码更加松散耦合,提高了可维护性和可测试性。

为什么需要 IOC

降低耦合度

传统的编程方式中,一个类往往需要自己负责创建和管理它所依赖的对象。这会导致类与类之间的耦合度很高当依赖的对象发生变化时,需要修改多个地方的代码而使用 IOC 可以将对象的创建和依赖关系的管理交给容器,使得类只需要关注自身的业务逻辑,降低了类与类之间的耦合度

提高可测试性

在使用 IOC 的情况下,可以很方便地为类注入模拟对象,从而进行单元测试。因为对象的依赖是通过外部注入的,所以可以在测试时轻松替换依赖对象,使得测试更加简单和可靠。

便于代码维护和扩展

由于对象的创建和依赖关系的管理都集中在容器中,当需要修改或扩展功能时,只需要修改容器的配置,而不需要修改大量的业务代码。这使得代码的维护和扩展变得更加容易。

  • 传统方式:对象主动创建依赖(new 操作)。

  • IOC 方式容器负责创建对象并注入依赖,实现解耦


二、容器(Container)

Spring 容器是 Spring 框架的核心部分,它负责创建、管理和装配 Bean 对象,以及处理 Bean 之间的依赖关系。以下是关于 Spring 容器的详细介绍:

概念

Spring 容器是一个轻量级的反转控制(IoC)容器,也被称为依赖注入(DI)容器。它通过读取配置文件扫描注解来创建和管理对象,并将对象之间的依赖关系进行注入,从而实现了对象之间的解耦。

工作原理

  • Bean 的定义和注册:在 Spring 中,Bean 是被容器管理的对象。开发者通过配置文件(如 XML)或注解(如@Component @Service等)来定义 Bean,并将其注册到 Spring 容器中。容器会解析这些配置信息,创建相应的 BeanDefinition 对象,用于描述 Bean 的各种属性,如类名、构造函数参数、属性值等。
  • Bean 的创建和初始化:当 Spring 容器启动时,它会根据 BeanDefinition 创建 Bean 实例。对于单例模式的 Bean,容器在启动时就会创建并初始化它们;对于原型模式的 Bean,在每次请求获取 Bean 时才会创建。在创建 Bean 的过程中,容器会调用 Bean 的构造函数进行实例化,然后根据配置信息设置 Bean 的属性值,并调用 Bean 的初始化方法(如果有指定)。
  • 依赖注入Spring 容器通过依赖注入来解决 Bean 之间的依赖关系。当一个 Bean 依赖于其他 Bean 时,容器会在创建该 Bean 时,自动将其依赖的 Bean 注入到该 Bean 中。依赖注入的方式有三种:构造函数注入、Setter 方法注入和字段注入。

主要类型

  • BeanFactory:是 Spring 容器的最基本接口,提供了基本的 Bean 管理功能,如获取 Bean 实例、检查 Bean 的存在等。它是一个延迟加载的容器,只有在真正需要使用 Bean 时才会创建和初始化。
  • ApplicationContext:是 BeanFactory 的子接口,它在 BeanFactory 的基础上增加了许多企业级应用所需的功能,如国际化支持、资源加载、事件发布等。ApplicationContext 在启动时会预先实例化所有的单例 Bean,适用于大多数 Spring 应用场景。

作用

  • 解耦对象之间的依赖关系:通过 Spring 容器的依赖注入功能,对象之间的依赖关系由容器来管理,使得对象之间的耦合度大大降低。这样,当一个对象的依赖发生变化时,只需要在容器的配置中进行修改,而不需要在使用该对象的代码中进行大量的修改。
  • 提高代码的可维护性和可扩展性:Spring 容器将对象的创建和管理集中到一个地方,使得代码的结构更加清晰,易于维护。同时,当需要增加新的功能或修改现有功能时,可以通过在容器中注册新的 Bean 或修改现有 Bean 的配置来实现,而不需要对大量的业务代码进行修改,提高了代码的可扩展性。
  • 方便进行面向切面编程(AOP):Spring 容器与 AOP 框架紧密集成,可以方便地实现对 Bean 的切面编程。通过 AOP,可以在不修改业务逻辑代码的情况下,对 Bean 的方法进行增强,如添加日志记录、事务管理、权限控制等功能。

创建 Spring 容器

在 Spring 中,常见的创建容器的方式有基于ApplicationContextBeanFactory两种,这里以ApplicationContext为例,它有多个实现类,下面分别介绍基于 XML 配置和注解配置创建容器的方法。

基于 XML 配置创建容器
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class XmlBasedContainerExample {public static void main(String[] args) {// 通过加载类路径下的XML配置文件创建ApplicationContext容器ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 从容器中获取BeanObject myBean = context.getBean("myBean");System.out.println(myBean);}
}
基于注解配置创建容器
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration
@ComponentScan(basePackages = "com.example.demo")
class AppConfig {// 配置类
}public class AnnotationBasedContainerExample {public static void main(String[] args) {// 通过注解配置类创建ApplicationContext容器AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);// 从容器中获取BeanObject myBean = context.getBean("myBean");System.out.println(myBean);}
}

Spring 容器类的层次结构

Spring 容器的核心接口是BeanFactoryApplicationContext,它们的类层次结构大致如下:

  • BeanFactory:是 Spring 容器的最基础接口,提供了获取 Bean 的基本方法,如getBean等。它是一个延迟加载的容器,只有在真正需要使用 Bean 时才会创建和初始化。
  • HierarchicalBeanFactory:继承自BeanFactory,增加了对父子容器层次结构的支持,可以获取父容器。
  • ListableBeanFactory:继承自BeanFactory,提供了可以枚举容器中所有 Bean 的功能,如获取所有 Bean 的名称、根据类型获取所有 Bean 等。
  • ApplicationContext:继承自HierarchicalBeanFactoryListableBeanFactory,并扩展了许多企业级应用所需的功能,如国际化支持、资源加载、事件发布等。它在启动时会预先实例化所有的单例 Bean。
    • ClassPathXmlApplicationContext:从类路径下的 XML 配置文件中加载 Bean 定义。
    • FileSystemXmlApplicationContext:从文件系统中的 XML 配置文件中加载 Bean 定义。
    • AnnotationConfigApplicationContext:基于 Java 注解配置类来加载 Bean 定义。

BeanFactory

BeanFactory是 Spring 容器的核心接口,它是一个轻量级的容器,主要负责创建、管理和查找 Bean。以下是一个简单的BeanFactory使用示例:

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;// 注意:XmlBeanFactory在Spring 3.1中已被弃用,这里仅作示例
@SuppressWarnings("deprecation")
public class BeanFactoryExample {public static void main(String[] args) {// 加载XML配置文件Resource resource = new ClassPathResource("applicationContext.xml");// 创建BeanFactory容器BeanFactory factory = new XmlBeanFactory(resource);// 从容器中获取BeanObject myBean = factory.getBean("myBean");System.out.println(myBean);}
}

在实际开发中,由于BeanFactory功能相对基础,大多数情况下会使用功能更强大的ApplicationContext。不过,了解BeanFactory有助于理解 Spring 容器的底层实现原理。

综上所述,Spring 容器的创建方式多样,类层次结构丰富,BeanFactory是其核心基础,不同的容器和接口适用于不同的应用场景。



三、Bean 的概念

在 Spring 中,Bean 指的是由 Spring 容器管理的对象。这些对象的创建、初始化、销毁等生命周期过程都由 Spring 容器负责。Spring 容器会根据配置信息(可以是 XML 配置、注解配置或者 Java 代码配置)来创建和管理 Bean,开发者只需关注业务逻辑的实现,而无需手动管理对象的生命周期。 

1. Bean 的配置

在 Spring 里,对 Bean 进行配置主要有三种常见方式,分别是 XML 配置、注解配置和 Java 配置。

XML 配置

借助 XML 文件来定义和配置 Bean,这是早期 Spring 开发常用的手段。以下是一个简单的示例:

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 定义一个名为userService的Bean --><bean id="userService" class="com.example.service.UserService"><!-- 注入依赖 --><property name="userRepository" ref="userRepository"/></bean><!-- 定义一个名为userRepository的Bean --><bean id="userRepository" class="com.example.repository.UserRepository"/>
</beans>
注解配置

利用注解在类上直接标记 Bean,能够简化配置流程。常见的注解有@Component@Service@Repository@Controller等。

import org.springframework.stereotype.Service;@Service
public class UserService {// 业务逻辑代码
}

同时,还需要在配置类里启用组件扫描:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {// 配置类代码
}
Java 配置

运用 Java 代码来配置 Bean,这种方式更加灵活。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic UserService userService() {return new UserService();}@Beanpublic UserRepository userRepository() {return new UserRepository();}
}

2. Bean 的作用范围的配置

Spring 为 Bean 提供了多种作用范围,可通过scope属性或者@Scope注解来进行配置。

singleton(单例)

这是 Spring 默认的作用范围整个应用程序中只会创建一个 Bean 实例。

<bean id="userService" class="com.example.service.UserService" scope="singleton"/>

使用注解的方式:

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;@Service
@Scope("singleton")
public class UserService {// 业务逻辑代码
}
prototype(原型)

每次请求该 Bean 时,都会创建一个新的实例。

<bean id="userService" class="com.example.service.UserService" scope="prototype"/>

注解方式:

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;@Service
@Scope("prototype")
public class UserService {// 业务逻辑代码
}
request、session、application(仅适用于 Web 应用)
  • request:每个 HTTP 请求都会创建一个新的 Bean 实例。
  • session:每个 HTTP 会话会创建一个新的 Bean 实例。
  • application:整个 Web 应用程序中只会创建一个 Bean 实例。

3. Bean 的实例化(创建)

方式一:构造器实例化

Spring 默认会通过 Bean 类的无参构造器来创建实例。

public class UserService {public UserService() {// 构造器代码}
}
方式二:静态工厂

使用静态工厂方法来创建 Bean 实例。

public class UserServiceFactory {public static UserService createUserService() {return new UserService();}
}

XML 配置如下:

<bean id="userService" class="com.example.factory.UserServiceFactory" factory-method="createUserService"/>
方式三:实例工厂

先创建工厂类的实例,再通过该实例的方法创建 Bean。

public class UserServiceInstanceFactory {public UserService createUserService() {return new UserService();}
}

XML 配置:

<bean id="userServiceFactory" class="com.example.factory.UserServiceInstanceFactory"/>
<bean id="userService" factory-bean="userServiceFactory" factory-method="createUserService"/>
方式四:方式三的优化(重点)

使用@Bean注解在配置类中创建 Bean,这种方式结合了 Java 配置的灵活性。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic UserServiceInstanceFactory userServiceInstanceFactory() {return new UserServiceInstanceFactory();}@Beanpublic UserService userService() {return userServiceInstanceFactory().createUserService();}
}

4. Bean 的生命周期(从创建到销毁)

Bean 的生命周期包含实例化、属性赋值、初始化、使用和销毁这几个阶段。

初始化方法

可以通过实现InitializingBean接口的afterPropertiesSet方法、使用@PostConstruct注解或者在 XML 中配置init-method属性来指定初始化方法。

import javax.annotation.PostConstruct;public class UserService {@PostConstructpublic void init() {// 初始化代码}
}
销毁方法

可通过实现DisposableBean接口的destroy方法、使用@PreDestroy注解或者在 XML 中配置destroy-method属性来指定销毁方法。

解决 Destroy 方法未执行的问题

如果Destroy方法没有执行,通常是因为 JVM 虚拟机在执行该方法前关闭了。可以通过以下两种方式解决:

  • 修改ApplicationContext接口,并调用close()方法关闭容器:
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);// 使用Beanctx.close(); // 关闭容器,触发销毁方法}
}
  • 使用registerShutdownHook()方法:
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);ctx.registerShutdownHook(); // 注册关闭钩子,JVM关闭时触发销毁方法// 使用Bean}
}

在实际开发的 Web 应用中,通常不需要手动编写这些代码,因为随着 Tomcat 等服务器的关闭,Spring 容器会自动关闭,从而触发 Bean 的销毁方法。

综上所述,理解 Bean 的配置、作用范围、实例化方式以及生命周期,对于使用 Spring 框架进行开发至关重要。


四、IOC的实现方式-依赖注入(DI, Dependency Injection)

DI(Dependency Injection,依赖注入)是实现 IOC(控制反转)的关键技术,它描述了容器在创建对象时,将对象所依赖的其他对象传递给该对象的过程。以下结合你提供的图片内容进行详细讲解:

依赖注入方式

setter 注入

通过对象的 setter 方法来注入依赖。它允许在对象创建后再设置其依赖关系,较为灵活。

  • 简单类型:对于像基本数据类型(如 int、String 等 ),可以在配置文件中直接指定值。例如在 XML 配置里:
<bean id="user" class="com.example.User"><property name="name" value="张三"/>
</bean>

这里通过 property 标签,利用 User 类的 setName 方法将字符串 “张三” 注入。

  • 引用类型:针对对象类型的依赖,比如一个 UserService 依赖 UserRepository ,配置如下:
<bean id="userRepository" class="com.example.UserRepository"/>
<bean id="userService" class="com.example.UserService"><property name="userRepository" ref="userRepository"/>
</bean>

上述配置会调用 UserService 的 setUserRepository 方法,将 userRepository 实例注入。

构造器注入

在对象创建时,通过构造函数来注入依赖。构造器注入能确保依赖在对象创建时就已存在且不可变,增强了对象的稳定性。

  • 简单类型:若一个类的构造函数接收基本数据类型参数,在 XML 中配置如下:
<bean id="order" class="com.example.Order"><constructor - arg value="100"/>
</bean>

假设 Order 类有个构造函数 public Order(int amount) ,这里就会通过该构造函数将值 100 注入。

  • 引用类型:当类依赖其他对象时,例如 ProductService 依赖 ProductRepository ,且通过构造函数注入:
<bean id="productRepository" class="com.example.ProductRepository"/>
<bean id="productService" class="com.example.ProductService"><constructor - arg ref="productRepository"/>
</bean>

即调用 ProductService 合适的构造函数(如 public ProductService(ProductRepository productRepository) ) 进行注入。

依赖注入方式选择

  • 建议使用 setter 注入:因为它的灵活性高,对象创建后还能修改依赖关系,适用于依赖关系多变的场景。比如某些配置信息可能在运行时动态改变,使用 setter 注入就可以方便地重新设置。
  • 第三方技术根据情况选择:对于一些第三方类库,如果其构造函数已经被设计用于特定的初始化逻辑,可能构造器注入更合适;若第三方类库后续需要动态调整依赖,setter 注入会是更好的选择。

依赖自动装配

这是 IoC 容器自动处理依赖注入的机制,容器会根据 bean 所依赖的资源在容器中自动查找并注入到 bean 中。

  • 按类型(常用):容器在查找依赖时,会依据依赖对象的类型在容器中寻找匹配的 Bean 进行注入。例如一个类依赖 UserRepository ,容器会查找类型为 UserRepository 的 Bean 注入。如果容器中存在多个同类型的 Bean ,会出现歧义,需要额外处理(比如结合 @Primary 注解指定首选 Bean )。
  • 按名称:根据依赖对象的名称来查找匹配的 Bean 注入。在 XML 配置中可通过 autowire - by - name 开启,在注解方式中,@Resource 注解默认按名称装配(若未指定名称则按类型 )。
  • 按构造方法:容器会查找与目标类构造函数参数类型匹配的 Bean 进行注入,主要用于构造器注入场景下的自动装配。
  • 不启用自动装配:即不使用自动装配功能,开发者需完全显式地在配置文件或代码中指定依赖注入关系。

加载 properties 文件

在实际开发中,常需要从外部配置文件(.properties 文件 )读取配置信息并注入到 Bean 中,具体操作如下:

  • 开启 context 命名空间:在 XML 配置文件中,引入 Spring 的 context 命名空间,以便使用相关标签。示例如下:
<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"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd">
</beans>
  • 使用 context 命名空间,加载指定 properties 文件:通过 <context:property - placeholder> 标签加载指定的 .properties 文件,例如:
<context:property - placeholder location="jdbc.properties"/>

这会加载类路径下名为 jdbc.properties 的文件。

  • ** 使用\({}读取加载的属性值**:在配置 Bean 属性值时,可通过 `\){属性名}` 的方式读取已加载文件中的属性值,如:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driver}"/><property name="jdbcUrl" value="${jdbc.url}"/>
</bean>

此外,还可以通过不同配置实现不加载系统属性(system - properties - mode="NEVER" )、加载多个 .properties 文件(以逗号分隔文件路径 )、加载所有 .properties 文件(使用通配符 )等功能。


五、配置方式对比

1. XML 配置(传统)
<bean id="userService" class="com.example.UserService"><property name="userDao" ref="userDao"/>
</bean>

运行 HTML

  • 缺点:冗长,类型不安全,维护成本高。

2. 注解配置(现代 Spring 主流)

通过注解简化配置,结合组件扫描实现自动化管理。


六、注解配置详解(重点)

 Spring 框架里基于注解的配置,涵盖注解开发定义 Bean、Bean 管理、依赖注入、加载 properties 文件以及管理第三方 Bean 等方面。

1. 注解开发定义 Bean

在 Spring 里,@Component 注解可把一个类标记成 Spring Bean,让 Spring 容器能够对其进行管理。此外,Spring 还提供了功能和 @Component 一样的三个注解,分别是 @Repository@Service 和 @Controller。这些注解在语义上有所区别,分别用于不同的层:

  • @Repository:一般用在数据访问层(DAO 层),代表这是一个数据仓库类。
  • @Service:常用于业务逻辑层(Service 层),代表这是一个业务服务类。
  • @Controller:一般用于表现层(Controller 层),代表这是一个控制器类。

下面是示例代码:

import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Controller;// 数据访问层
@Repository
public class UserDao {public void saveUser() {System.out.println("Save user to database");}
}// 业务逻辑层
@Service
public class UserService {private UserDao userDao;public UserService(UserDao userDao) {this.userDao = userDao;}public void addUser() {userDao.saveUser();}
}// 表现层
@Controller
public class UserController {private UserService userService;public UserController(UserService userService) {this.userService = userService;}public void handleUserRequest() {userService.addUser();}
}

2. 注解开发 - Bean 管理

依赖注入

依赖注入指的是把一个 Bean 注入到另一个 Bean 里。在 Spring 中,可使用 @Autowired 注解来达成依赖注入。@Autowired 注解能用在构造函数、setter 方法或者字段上。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {private UserDao userDao;@Autowiredpublic UserService(UserDao userDao) {this.userDao = userDao;}public void addUser() {userDao.saveUser();}
}
加载 properties 文件

要加载 properties 文件,可使用 @PropertySource 注解和 @Value 注解。@PropertySource 注解用于指定 properties 文件的位置,@Value 注解用于注入 properties 文件里的属性值。

import org.springframework.context.annotation.PropertySource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
@PropertySource("classpath:config.properties")
public class AppConfig {@Value("${database.url}")private String databaseUrl;@Value("${database.username}")private String databaseUsername;@Value("${database.password}")private String databasePassword;public String getDatabaseUrl() {return databaseUrl;}public String getDatabaseUsername() {return databaseUsername;}public String getDatabasePassword() {return databasePassword;}
}
管理第三方 Bean

对于第三方库的 Bean,你可以编写一个方法来获取第三方 Bean,并且用 @Bean 注解把返回值设置成 Bean。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fasterxml.jackson.databind.ObjectMapper;@Configuration
public class AppConfig {@Beanpublic ObjectMapper objectMapper() {return new ObjectMapper();}
}

3. 纯注解开发配置类

要实现纯注解开发,你需要创建一个配置类,用 @Configuration 注解标记该类,同时用 @ComponentScan 注解开启组件扫描。

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration
@ComponentScan(basePackages = "com.example.demo")
public class AppConfig {// 配置类中的其他配置
}

4. 测试代码

以下是一个简单的测试代码,展示如何使用上述配置:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);UserController userController = context.getBean(UserController.class);userController.handleUserRequest();AppConfig appConfig = context.getBean(AppConfig.class);System.out.println("Database URL: " + appConfig.getDatabaseUrl());ObjectMapper objectMapper = context.getBean(ObjectMapper.class);System.out.println("ObjectMapper: " + objectMapper);context.close();}
}

小结

  • 运用 @Component@Repository@Service 和 @Controller 注解定义 Bean。
  • 借助 @Autowired 注解实现依赖注入。
  • 利用 @PropertySource 和 @Value 注解加载 properties 文件。
  • 使用 @Bean 注解管理第三方 Bean。
  • 采用 @Configuration 和 @ComponentScan 注解实现纯注解开发。
注解配置 vs XML 配置
特性注解配置XML 配置
可读性代码内嵌,直观外部文件,需上下文切换
灵活性强类型,编译时检查字符串配置,易出错
维护性修改代码需重新编译动态修改无需编译
适用场景现代 Spring Boot 项目遗留系统或复杂配置


总结

Spring 的 IOC 容器 通过注解配置(如 @Component@Autowired@Configuration)实现了轻量级、高内聚的依赖管理。注解配置已成为现代 Spring 开发的主流方式,兼顾灵活性和代码简洁性,是 Spring Boot 自动配置的基石。

相关文章:

Spring IOC:容器管理与依赖注入秘籍

Java Spring 核心容器、IOC 一、IOC&#xff08;控制反转&#xff09;核心概念 基本概念 控制反转是一种将对象的创建、依赖关系的管理和生命周期的控制权从应用程序代码转移到外部容器的设计原则。在传统编程中&#xff0c;对象的创建和依赖关系是由程序自身控制的&#xff0…...

Cpp网络编程Winsock API

Cpp网络编程Winsock API 作者&#xff1a;blue 时间&#xff1a;2025.3.31 文章目录 Cpp网络编程Winsock API**1.服务端**&#xff08;Server&#xff09;1.1初始化网络库1.2创建套接字对象1.3设置ip和端口1.4将套接字对象与ip和端口绑定1.5设置套接字为监听状态1.6等待客户端…...

聊聊Spring AI的Chat Model

序 本文主要研究一下Spring AI的Chat Model Model spring-ai-core/src/main/java/org/springframework/ai/model/Model.java public interface Model<TReq extends ModelRequest<?>, TRes extends ModelResponse<?>> {/*** Executes a method call to …...

VUE3+Mapbox-GL 实现鼠标绘制矩形功能的详细代码和讲解

以下是如何使用 Mapbox GL JS 实现鼠标绘制矩形功能的详细代码和讲解。Mapbox GL JS 是一个强大的 JavaScript 库&#xff0c;可以用来创建交互式地图。下面将通过监听鼠标事件并动态更新地图图层来实现这一功能。 实现步骤 初始化地图 在 HTML 文件中引入 Mapbox GL JS 库&…...

Python数据类型-list

列表(List)是Python中最常用的数据类型之一&#xff0c;它是一个有序、可变的元素集合。 1. 列表基础 创建列表 empty_list [] # 空列表 numbers [1, 2, 3, 4, 5] # 数字列表 fruits [apple, banana, orange] # 字符串列表 mixed [1, hello, 3.14, True] # 混合类型…...

【Python】Browser-Use:让 AI 替你掌控浏览器,开启智能自动化新时代!

Browser-Use&#xff1a;让 AI 替你掌控浏览器&#xff0c;开启智能自动化新时代&#xff01; Github地址: https://github.com/browser-use/browser-use/tree/main 在 AI 浪潮席卷的今天&#xff0c;我们是否想过让 AI 不仅仅是聊天、生成内容&#xff0c;而是能像人一样实际操…...

Proxmox配置显卡直通

1.查看显卡 lspci | grep VGA 2.修改grub 2.1备份grub cp /etc/default/grub /etc/default/grub.bak 2.2修改grub vi /etc/default/grub 如果是Intel的CPU GRUB_CMDLINE_LINUX_DEFAULT“quiet intel_iommuon” 如果是AMD的CPU&#xff1a; GRUB_CMDLINE_LINUX_DEFAUL…...

C# FileStream 使用详解

总目录 前言 在 C# 编程中&#xff0c;文件操作是常见的任务之一。FileStream 类是 System.IO 命名空间中的一个重要类&#xff0c;它提供了对文件的读取和写入操作的底层支持。本文将详细介绍 FileStream 的使用方法&#xff0c;包括如何创建、读取、写入文件&#xff0c;以及…...

C++编程语言:抽象机制:一个矩阵的设计(Bjarne Stroustrup)

第29章 一个矩阵的设计(A Matrix Design) 目录 29.1 引言 29.1.1 基本的 Matrix 用法 29.1.2 Matrix 的要求 29.2 一个 Matrix 模板 29.2.1 构造和赋值(Construction and Assignment) 29.2.2 下标和分片(Subscripting and Slicing) 29.3 Matrix算术运算(Matrix…...

Swift LeetCode 246 题解:中心对称数(Strobogrammatic Number)

摘要 在日常开发中&#xff0c;我们经常遇到一些关于对称性的判断&#xff0c;比如字符串回文、镜像翻转等。而 “中心对称数”&#xff08;Strobogrammatic Number&#xff09; 这个问题&#xff0c;本质上是考察一个数字在旋转 180 度后是否还是原来的样子。 这个问题看似简…...

网络安全等级保护测评

名词解释 网络安全等级保护测评 网络安全等级保护测评,是对信息系统进行的一种安全评估活动。它的目的是验证信息系统是否达到了国家网络安全等级保护制度所规定的安全保护要求。这个制度将信息系统按照重要性划分为不同的安全保护等级,每个等级都有相应的安全保护要求。 …...

项目复盘:websocket不受跨域限制的原理

主要还是因为&#xff1a; 1、WebSocket 是独立于 HTTP 的应用层协议&#xff0c;通过 HTTP 建立连接后&#xff0c;完全脱离 HTTP 语义约束。这意味着 不受 HTTP 同源策略限制 不需要预检请求 不依赖 CORS 头机制 2、建立连接时的握手请求仍使用 HTTP 格式&#xff0c;但…...

deep-sync开源程序插件导出您的 DeepSeek 与 public 聊天

一、软件介绍 文末提供下载 deep-sync开源程序插件导出您的 DeepSeek 与 public 聊天&#xff0c;这是一个浏览器扩展&#xff0c;它允许用户公开、私下分享他们的聊天对话&#xff0c;并使用密码或过期链接来增强 Deepseek Web UI。该扩展程序在 Deepseek 界面中添加了一个 “…...

AI原生应用爆发:从通用大模型到垂直场景的算力重构

2025年第一季度&#xff0c;中国AI产业迎来标志性转折点&#xff1a;DeepSeek-R1大模型月活用户突破3000万&#xff0c;通义千问QwQ-32B在医疗领域诊断准确率达三甲医院主治医师水平&#xff0c;京东AI虚拟模特单日生成商品图超200万张……这些数据的背后&#xff0c;是AI技术从…...

arcgis jsapi 4.31 调用geoserver 发布的wms服务

服务的调用我也测试了网络搜索的很多方法&#xff0c;均未奏效&#xff0c;后来还是通过对官网例子的研究&#xff0c;找到了解决方案&#xff0c;调试的过程是非常痛苦的&#xff0c;最大的问题就是调用后没有任何反应&#xff0c;也不会给你任何的错误信息&#xff0c;这是最…...

《筋斗云的K8s容器化迁移》

点击下面图片带您领略全新的嵌入式学习路线 &#x1f525;爆款热榜 88万阅读 1.6万收藏 文章目录 **第一章&#xff1a;斗战胜佛的延迟焦虑****第二章&#xff1a;微服务化的紧箍咒****第三章&#xff1a;混沌中的流量劫持****第四章&#xff1a;量子筋斗的终极形态****终章&…...

[笔记.AI]大模型训练 与 向量值 的关系

&#xff08;借助 DeepSeek-V3 辅助生成&#xff09; 大模型在训练后是否会改变向量化的值&#xff0c;取决于模型的训练阶段和使用方式。以下是详细分析&#xff1a; 1. 预训练阶段&#xff1a;向量化值必然改变 动态调整过程&#xff1a; 在预训练阶段&#xff08;如BERT、…...

【学Rust写CAD】18 定点数2D仿射变换矩阵结构体(MatrixFixedPoint结构别名)

源码 // matrix/fixed.rs use crate::fixed::Fixed; use super::generic::Matrix;/// 定点数矩阵类型别名 pub type MatrixFixedPoint Matrix<Fixed, Fixed, Fixed, Fixed, Fixed, Fixed>;代码解析 这段代码定义了一个定点数矩阵的类型别名 MatrixFixedPoint&#xff…...

Linux进程间通信:【目的】【管道】【匿名管道】【命名管道】【System V 共享内存】

目录 一.进程间通信目的 二.管道 三.匿名管道 3.1用fork来共享管理管道 3.2站在文件描述符角度-深度理解管道 3.3内核角度 3.4管道样例 3.4.1测试管道读写 3.4.2代码 解决方案1&#xff1a;倒着关闭&#xff1a; 解决方案2&#xff1a; 只让父进程一个人指向写端 四…...

Python 自动化:节省时间,更智能地工作

大家好&#xff0c;这里是架构资源栈&#xff01;点击上方关注&#xff0c;添加“星标”&#xff0c;一起学习大厂前沿架构&#xff01; 时间是你最宝贵的资产。如果你花费数小时手动执行重复性任务&#xff0c;那么当 Python 可以为你完成这些任务时&#xff0c;你就是在浪费时…...

StarRocks的执行计划和Profile

文章目录 一、执行计划和Profile相关脚本二、如何分析查询1、概念了解2、Query Plan①查看 Query Plan②分析 Query Plan 3、Query hint4、Query Profile①启用 Query Profile②查看 Query Profile③分析 Query Profile 一、执行计划和Profile相关脚本 命令功能ANALYZE PROFIL…...

【设计模式】过滤器模式

过滤器顾名思义&#xff0c;定义一些过滤规则&#xff0c;将符合要求的内容筛选&#xff0c;就比如过滤不同大小或者不同颜色的水果&#xff0c;需要颜色和大小过滤器&#xff0c;筛选条件独立为对象&#xff0c;可以通过灵活组合形成过滤链条。避免大量使用判断语句。 案例代…...

Jenkins插件安装失败如何解决

问题&#xff1a;安装Jenkins时候出现插件无法安装的情况。 测试环境&#xff1a; 操作系统&#xff1a;Windows11 Jenkins&#xff1a;2.479.3 JDK&#xff1a;17.0.14&#xff08;21也可以&#xff09; 解决办法一&#xff1a; 更换当前网络&#xff0c;局域网、移动、联通…...

GO语言杂记(文章持续更新)

1、MAIN冲突 在一个文件夹下有两个go文件同时写了main函数&#xff0c;将会报错&#xff0c;main函数只能在main包中。 实则不然&#xff0c;有些环境下并不会报错。 2、gofmt命令---自动对齐 命令作用&#xff1a;将go文件代码自动缩进。 gofmt -w escapecharprac.go...

VUE如何前端控制及动态路由详细讲解

在Vue.js中&#xff0c;前端控制通常指的是通过Vue的响应式系统、组件化、路由、状态管理等技术来实现对前端应用的控制和管理 一、前端路由控制基础 使用 vue-router 管理路由&#xff0c;通过路由守卫和动态添加路由实现权限控制。 1. 安装和配置 npm install vue-router…...

【区块链安全 | 第九篇】基于Heimdall设计的智能合约反编译项目

文章目录 背景目的安装1、安装 Rust2、克隆 heimdall-dec3、编译 heimdall-dec4、运行 heimdall-dec 使用说明1、访问 Web 界面2、输入合约信息3、查看反编译结果 实战演示1、解析普通合约2、解析代理合约 背景 在区块链安全研究中&#xff0c;智能合约的审计和分析至关重要。…...

day1_Flink基础

文章目录 Flink基础今日课程内容目标为什么要学Flink技术更新迭代市场需求 流式计算批量计算概念特点 批量计算的优势和弊端流式计算生活中流场景流式计算的概念 Flink简介Flink历史Flink介绍 Flink架构体系已学过的框架技术Flink架构 Flink集群搭建Flink的集群模式Standalone模…...

43页可编辑PPT | 大数据管理中心设计规划方案大数据中心组织架构大数据组织管理

这份文档是一份关于大数据管理中心规划设计方案的详细报告&#xff0c;涵盖了背景与需求分析、整体规划方案、关键能力实现方案以及实施方案等内容。报告强调大数据在城市治理中的重要性&#xff0c;提出通过构建统一的大数据平台&#xff0c;整合城市各部门数据资源&#xff0…...

JavaScript数据结构

目录 JavaScript数据结构 一、基础数据结构 1. 数组&#xff08;Array&#xff09; 2. 对象&#xff08;Object&#xff09; 二、ES6 高级数据结构 1. Map 2. Set 3. WeakMap 与 WeakSet 三、类型化数组&#xff08;Typed Arrays&#xff09; 四、其他数据结构实现 …...

如何使用 FastAPI 构建 MCP 服务器

哎呀&#xff0c;各位算法界的小伙伴们&#xff01;今天咱们要聊聊一个超酷的话题——MCP 协议&#xff01;你可能已经听说了&#xff0c;Anthropic 推出了这个新玩意儿&#xff0c;目的是让 AI 代理和你的应用程序之间的对话变得更顺畅、更清晰。不过别担心&#xff0c;为你的…...

Js 主线程和异步队列哪个先执行

JavaScript 主线程与异步队列执行顺序详解 JavaScript 是单线程语言&#xff0c;通过事件循环&#xff08;Event Loop&#xff09;机制来处理同步和异步任务。以下是主线程与异步队列的执行顺序解析&#xff1a; 1. 执行顺序基本原则 console.log(1. 主线程同步任务);setTim…...

C#实现HTTP服务器:处理文件上传---解析MultipartFormDataContent

完整项目托管地址&#xff1a;https://github.com/sometiny/http HTTP还有重要的一块&#xff1a;文件上传。 这篇文章将详细讲解下&#xff0c;前面实现了同一个链接处理多个请求&#xff0c;为了方便&#xff0c;我们独立写了一个HTTP基类&#xff0c;专门处理HTTP请求。 ht…...

【hadoop】远程调试环境

根据上一节&#xff0c;我们已经安装完成hadoop伪分布式环境 hadoop集群环境配置_jdk1.8 441-CSDN博客 还没安装的小伙伴可以看看这个帖子 这一节我们要实现使用vscode进行远程连接&#xff0c;并且完成java配置与测试 目录 vscode 配置远程 安装java插件 新建java项目 …...

检索增强生成(RAG):强化 AI 智能体的知识 “武装”

技术点目录 第一章、智能体(Agent)入门第二章、基于字节Coze 构建智能体(Agent)第三章、基于其他平台构建智能体&#xff08;Agent&#xff09;第四章、国内外智能体(Agent)经典案例详解第五章、大语言模型应用开发框架LangChain入门第六章、基于LangChain的大模型API接入第七章…...

使用 Provider 和 GetX 实现 Flutter 局部刷新的几个示例

1. 使用 Provider 实现局部刷新 示例 1&#xff1a;ChangeNotifier Consumer 通过 ChangeNotifier 和 Consumer 实现局部刷新。 import package:flutter/material.dart; import package:provider/provider.dart;void main() {runApp(ChangeNotifierProvider(create: (_) &g…...

notepad++ 正则表达式

注意&#xff1a;Notepad正则表达式字符串最长不能超过69个字符 \ 转义字符 如&#xff1a;要使用 “\” 本身, 则应该使用“\\” \t Tab制表符 注&#xff1a;扩展和正则表达式都支持 \r 回车符CR 注&#xff1a;扩展支持&#xff0c;正则表达式不支持 \n 换行符…...

一起学大语言模型-通过ollama搭建本地大语言模型服务

文章目录 Ollama的github地址链接安装下载需求配置更改安装目录安装更改下载的模型存储位置Ollama一些目录说明日志目录 运行一个模型测试下测试下更改服务监听地址和端口号 Ollama的github地址链接 https://github.com/ollama/ollama 安装 下载 mac安装包下载地址&#xff1…...

webpack配置详解+项目实战

webpack在vue中的配置&#xff0c;适合想重新认知webpack的你 webpack配置-初级配置 1、配置入口和出口文件 2、配置loader 3、配置eslint&#xff08;可组装js、jsx检查工具&#xff09; 4、配置babel&#xff08;将高级的js语法转换成低版本的js语法&#xff09; 5、使用 ht…...

【学习笔记】文件上传漏洞--js验证、mime验证、.user.ini、短标签、过滤、文件头

概念 文件上传漏洞 什么是文件上传漏洞&#xff1f; 文件上传漏洞是指由于程序员在对用户文件上传部分的控制不足或者处理缺陷&#xff0c;而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。 这里上传的文件可以是木马&#xff0c;病毒&#xff0c;恶意脚…...

经典卷积神经网络LeNet实现(pytorch版)

LeNet卷积神经网络 一、理论部分1.1 核心理论1.2 LeNet-5 网络结构1.3 关键细节1.4 后期改进1.6 意义与局限性二、代码实现2.1 导包2.1 数据加载和处理2.3 网络构建2.4 训练和测试函数2.4.1 训练函数2.4.2 测试函数2.5 训练和保存模型2.6 模型加载和预测一、理论部分 LeNet是一…...

【VM虚拟机ip问题】

我就是我&#xff0c;不一样的烟火。 文章目录 前言一、启动VM虚拟机1. 开启虚拟机2. 输入账号密码登录3. 依次输入指令 二、主机ping地址测试1. ping ip地址-成功 三、安装-MobaXterm_Personal_21.51. 点击Session2. 选择SSH连接3. 输入信息4. 首次进入5. 连接成功 总结 前言 …...

【计算机视觉】YOLO语义分割

一、语义分割简介 1. 定义 语义分割&#xff08;Semantic Segmentation&#xff09;是计算机视觉中的一项任务&#xff0c;其目标是对图像中的每一个像素赋予一个类别标签。与目标检测只给出目标的边界框不同&#xff0c;语义分割能够在像素级别上区分不同类别&#xff0c;从…...

【C++游戏引擎开发】《线性代数》(3):矩阵乘法的SIMD优化与转置加速

一、矩阵乘法数学原理与性能瓶颈 1.1 数学原理 矩阵乘法定义为:给定两个矩阵 A ( m n ) \mathrm{A}(mn) A(mn)和 B ( n p ) \mathrm{B}(np) B(np),它们的乘积 C = A B \mathrm{C}=AB C=AB 是一个 m p \mathrm{m}p mp 的矩阵,其中: C i , j = ∑ k = 1…...

聚焦交易能力提升!EagleTrader 模拟交易系统打造交易成长新路径

在全球市场波动加剧的背景下&#xff0c;交易者面临的挑战已不仅限于技术分析层面。许多交易者在实盘操作中常因情绪干扰导致决策变形&#xff0c;如何构建科学的交易心理与风险控制体系成为行业关注焦点。 国内自营交易考试EagleTrader运用自己研发的模拟交易系统&#xff0c…...

文件分片上传

1前端 <inputtype"file"accept".mp4"ref"videoInput"change"handleVideoChange"style"display: none;">2生成hash // 根据整个文件的文件名和大小组合的字符串生成hash值&#xff0c;大概率确定文件的唯一性fhash(f…...

C#Lambda表达式与委托关系

1. 核心关系图示 A[委托] --> B[提供方法容器] B --> C[Lambda表达式] C --> D[委托实例的语法糖] A --> E[类型安全约束] C --> F[编译器自动生成委托实例] 2. 本质联系 2.1 类型关系 ‌Lambda表达式‌是编译器生成的‌委托实例‌表达式自动匹配符合签名的…...

机器翻译和文本生成评估指标:BLEU 计算公式

&#x1f4cc; BLEU 计算公式 BLEU 主要由**n-gram精确匹配率&#xff08;Precision&#xff09;和长度惩罚&#xff08;Brevity Penalty, BP&#xff09;**组成。 1️⃣ n-gram 精确匹配率 计算不同长度的 n-gram&#xff08;1-gram, 2-gram, ..., n-gram&#xff09;在生成…...

24 python 类

在办公室里&#xff0c;类就像一个部门&#xff08;如销售部、财务部&#xff09;&#xff0c;定义了该部门员工的共同属性&#xff08;姓名、职位&#xff09;和行为&#xff08;处理客户、提交报表&#xff09;。 一、面向对象技术简介 作为一个要入门码农的牛马&#xff0…...

pycharm与python版本

python 3.6-3.9 pycharm 2021版本搭配最好 python 3.8 pycharm 2019版本搭配最好 pycharm各版本下载...

23种设计模式-结构型模式-外观

文章目录 简介问题解决方案示例代码总结 简介 也称&#xff1a;门面模式、Facade。外观是一种结构型设计模式&#xff0c;能为程序库、框架或其他复杂类提供一个简单的接口。 问题 假设你必须在代码中使用某个复杂的库或框架中的众多对象。正常情况下&#xff0c;你需要负责…...