Spring-IOC部分

Spring-IOC部分

1.SpringBean的配置详解(Bean标签)

image-20250404142237565

(1)scope

默认情况下,单纯的Spring环境Bean的作用范围有两个:Singleton和Prototype

singleton:单例,默认值,Spring容器创建的时候,就会进行Bean的实例化,并存储到容器内部的单例池中,每次getBean时都是从单例池中获取相同的Bean实例;

prototype:原型,Spring容器初始化时不会创建Bean实例,当调用getBean时才会实例化Bean,每次getBean都会创建一个新的Bean实例。生成的Bean不会存在单例池中

(2)lazy-init

当lazy-init设置为true时为延迟加载,也就是当Spring容器创建的时候,不会立即创建Bean实例,等待用到时在创建Bean实例并存储到单例池中去,后续在使用该Bean直接从单例池获取即可,本质上该Bean还是单例的

(3)init-method

可以在Bean中创建一个成员方法init,在Bean被实例化之后执行,或者实现InitializingBean 接口重写afterPropertiesSet方法

(4)Bean实例化配置

1.构造方式实例化:底层通过构造方法对Bean进行实例化

  • 无参构造

  • 有参构造

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"><constructor-arg name="name" value="haohao"/>
    </bean>
    

2.工厂方式实例化:底层通过调用自定义的工厂方法对Bean进行实例化

  • 静态工厂方法实例化Bean

    静态工厂方法实例化Bean,其实就是定义一个工厂类,提供一个静态方法用于生产Bean实例,在将该工厂类及其静态方法配置给Spring即可

    //工厂类
    public class UserDaoFactoryBean {//非静态工厂方法public static UserDao getUserDao(String name){//可以在此编写一些其他逻辑代码return new UserDaoImpl();}
    }
    
    <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean" factory-method="getUserDao"><constructor-arg name="name" value="haohao"/>
    </bean>
    
    • 静态工厂方法是一个普通的静态方法,它负责创建并返回一个对象实例。
    • 静态工厂方法本身不会被 Spring 容器管理,因为它是一个静态方法,不属于任何 Spring Bean。
  • 实例工厂方法实例化Bean

    <!-- 配置实例工厂Bean -->
    <bean id="userDaoFactoryBean2" class="com.itheima.factory.UserDaoFactoryBean2"/>
    <!-- 配置实例工厂Bean的哪个方法作为工厂方法 -->
    <bean id="userDao" factory-bean="userDaoFactoryBean2" factory-method="getUserDao"><constructor-arg name="name" value="haohao"/>
    </bean>
    
  • 实现FactoryBean规范延迟实例化Bean

    public interface FactoryBean<T> {String OBJECT_TYPE_ATTRIBUTE = “factoryBeanObjectType”;T getObject() throws Exception; //获得实例对象方法Class<?> getObjectType(); //获得实例对象类型方法default boolean isSingleton() {return true;}
    }
    
    public class UserDaoFactoryBean3 implements FactoryBean<UserDao> {public UserDao getObject() throws Exception {return new UserDaoImpl();}public Class<?> getObjectType() {return UserDao.class;}
    }
    
    <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean3"/>
    

    Spring容器创建时,FactoryBean被实例化了,并存储到了单例池singletonObjects中,但是getObject() 方法尚未被执行,UserDaoImpl也没被实例化,当首次用到UserDaoImpl时,才调用getObject() ,此工厂方式产生的Bean实例不会存储到单例池singletonObjects中,会存储到 factoryBeanObjectCache 缓存池中,并且后期每次使用到userDao都从该缓存池中返回的是同一个userDao实例。

(5)Bean的依赖注入配置

image-20250404144107704

构造器方法注入就和使用有参构造器实例化Bean的方式一样

自动装配

如果被注入的属性类型是Bean引用的话,那么可以在 标签中使用 autowire 属性去配置自动注入方式,属性值有两个:

byName:通过属性名自动装配,即去匹配 setXxx 与 id=“xxx”(name=“xxx”)是否一致;

byType:通过Bean的类型从容器中匹配,匹配出多个相同Bean类型时,报错。

<bean id="userService" class="com.itheima.service.impl.UserServiceImpl" autowire="byType">

基于注解的依赖注入

image-20250404161351686

@Value("${jdbc.username}")
private String username;
@Value("${jdbc.username}")
public void setUsername(String username){
System.out.println(username);
}//使用在属性上直接注入
@Autowired
private UserDao userDao;
//使用在方法上直接注入
@Autowired
public void setUserDao(UserDao userDao){
System.out.println(userDao);
}@Autowired
@Qualifier("userDao2")
private UserDao userDao;//@Resource注解既可以根据类型注入,也可以根据名称注入,无参就是根据类型注入,有参数就是根据名称注入 是javax包下
@Resource
private UserDao userDao;
@Resource(name = "userDao2")
public void setUserDao(UserDao userDao){
System.out.println(userDao);
}

(6)Spring其他的配置标签

Spring 的 xml 标签大体上分为两类,一种是默认标签,一种是自定义标签

  • 默认标签:就是不用额外导入其他命名空间约束的标签,例如 标签.

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    </beans>
    

    image-20250404144744969

  • 自定义标签:就是需要额外引入其他命名空间约束,并通过前缀引用的标签,例如 context:property-placeholder/ 标签

在使用注解开发中,使用@Component注解代替标签,其他标签就可以定义一个配置类来替代原有的xml配置文件

@Configuration注解标识的类为配置类,替代原有xml配置文件,该注解第一个作用是标识该类是一个配置类,第二个作用是具备@Component作用

@ComponentScan 组件扫描配置,替代原有xml文件中的<context:component-scan base-package=“”/>

@PropertySource 注解用于加载外部properties资源配置,替代原有xml中的<context:property placeholder location=“”/>配置

@Import 用于加载其他配置类,替代原有xml中的配置

(7)基于注解配置

除了使用xml进行配置,还可以使用注解配置,在Bean类上使用注解@Component注解,value属性指定当前Bean实例的beanName,也可以省略不写,不写的情况下为当前类名首字母小写。

需要在xml文件中进行配置

<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 告知Spring框架去itheima包及其子包下去扫描使用了注解的类 --><context:component-scan base-package="com.itheima"/>
</beans>
//获取方式:applicationContext.getBean("userDao");
@Component("userDao")
public class UserDaoImpl implements UserDao {
}
//获取方式:applicationContext.getBean("userDaoImpl");
@Component
public class UserDaoImpl implements UserDao {
}

xml配置和注解的对应

image-20250404161156416

为了每层Bean标识的注解语义化更加明确,@Component又衍生出如下三个注解

image-20250404161317455

(8)Spring配置其他注解

@Primary注解用于标注相同类型的Bean优先被使用权,@Primary 是Spring3.0引入的,与@Component和@Bean一起使用,标注该Bean的优先级更高,则在通过类型获取Bean或通过@Autowired根据类型进行注入时,会选用优先级更高的

注解 @Profile 标注在类或方法上,标注当前产生的Bean从属于哪个环境,只有激活了当前环境,被标注的Bean才能被注册到Spring容器里,不指定环境的Bean,任何环境下都能注册到Spring容器里

2.Spring的get方法

image-20250404144908661

3.Spring配置非自定义Bean(第三方提供的Bean)

配置非自定义的Bean需要考虑如下两个问题:

  • 被配置的Bean的实例化方式是什么?无参构造、有参构造、静态工厂方式还是实例工厂方式;
  • 被配置的Bean是否需要注入必要属性。

以MyBatis为例

原始代码

//加载mybatis核心配置文件,使用Spring静态工厂方式
InputStream in = Resources.getResourceAsStream(“mybatis-conifg.xml”);
//创建SqlSessionFactoryBuilder对象,使用Spring无参构造方式
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//调用SqlSessionFactoryBuilder的build方法,使用Spring实例工厂方式
SqlSessionFactory sqlSessionFactory = builder.build(in);

用xml配置

<!--静态工厂方式产生Bean实例-->
<bean id=“inputStream” class=“org.apache.ibatis.io.Resources” factory-method=“getResourceAsStream”><constructor-arg name=“resource” value=“mybatis-config.xml/>
</bean>
<!--无参构造方式产生Bean实例-->
<bean id="sqlSessionFactoryBuilder" class="org.apache.ibatis.session.SqlSessionFactoryBuilder"/>
<!--实例工厂方式产生Bean实例-->
<bean id="sqlSessionFactory" factory-bean="sqlSessionFactoryBuilder" factory-method="build"><constructor-arg name="inputStream" ref="inputStream"/>
</bean>

用注解配置

//将方法返回值Bean实例以@Bean注解指定的名称存储到Spring容器中
@Bean("dataSource")
public DataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");dataSource.setUsername("root");dataSource.setPassword("root");return dataSource;
}

工厂方法所在类必须要被Spring管理

如果需要注入参数的话,@Autowired可以省略

@Bean
@Autowired //根据类型匹配参数
public Object objectDemo01(UserDao userDao){System.out.println(userDao);return new Object();
}
@Bean
public Object objectDemo02(@Qualifier("userDao") UserDao userDao,
@Value("${jdbc.username}") String username){System.out.println(userDao);System.out.println(username);return new Object();
}

4.Bean实例化的基本流程

Spring容器在进行初始化时,会将xml配置的的信息封装成一个BeanDefinition对象,所有的BeanDefinition存储到一个名为beanDefinitionMap的Map集合中去,Spring框架在对该Map进行遍历,使用反射创建Bean实例对象,创建好的Bean对象存储在一个名为singletonObjects的Map集合中,当调用getBean方法时则最终从该Map集合中取出Bean实例对象返回。

image-20250404145336228

5.Spring的后处理器

Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。Spring主要有两种后处理器:

  • BeanFactoryPostProcessor:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行;

    BeanFactoryPostProcessor是一个接口规范,实现了该接口的类只要交由Spring容器(xml文件中用bean配置)管理的话,那么Spring就会回调该接口的方法,用于对BeanDefinition注册和修改的功能。

    public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);
    }
    

    可以动态修改BeanDefinition(修改class,修改初始化方法,是否懒加载)

    Spring 提供了一个BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor专门用于注册BeanDefinition操作

    public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {}@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {BeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.itheima.dao.UserDaoImpl2");beanDefinitionRegistry.registerBeanDefinition("userDao2",beanDefinition);}
    }
    

    这个对象本身也会交给spring容器管理,进入到单例池中

  • BeanPostProcessor:Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行。

    Bean被实例化后,到最终缓存到名为singletonObjects单例池之前,中间会经过Bean的初始化过程,例如:属性的填充、初始方法init的执行等,其中有一个对外进行扩展的点BeanPostProcessor,我们称为Bean后处理

    public interface BeanPostProcessor {@Nullable//在属性注入完毕,init初始化方法执行之前被回调default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullable//在初始化方法执行之后,被添加到单例池singletonObjects之前被回调default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
    }
    

    这个对象本身也会交给spring容器管理,进入到单例池中

    image-20250404150933106

image-20250404150943323

6.Spring的生命周期

Spring Bean的生命周期是从 Bean 实例化之后,即通过反射创建出对象之后,到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为Spring Bean的生命周期。Spring Bean的生命周期大体上分为三个阶段:

  • Bean的实例化阶段:Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是singleton的,是否不是延迟加载的,是否不是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化;
  • Bean的初始化阶段:Bean创建之后还仅仅是个"半成品",还需要对Bean实例的属性进行填充、执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等。该阶段是Spring最具技术含量和复杂度的阶段,Aop增强功能,后面要学习的Spring的注解功能等、spring高频面试题Bean的循环引用问题都是在这个阶段体现的;
  • Bean的完成阶段:经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去了,即完成了Spring Bean的整个生命周期。

初始化阶段主要设计以下几个过程:

  • Bean实例的属性填充
  • Aware接口属性注入
  • BeanPostProcessor的before()方法回调
  • InitializingBean接口的初始化方法回调
  • 自定义初始化方法init回调
  • BeanPostProcessor的after()方法回调

(1)Bean的实例属性填充

Spring在进行属性注入时,会分为如下几种情况:

  • 注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;

  • 注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;

  • 注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)问题,下面会详细阐述解决方案

    image-20250404151853826

三级缓存

public class DefaultSingletonBeanRegistry ... {//1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"Map<String, Object> singletonObjects = new ConcurrentHashMap(256);//2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);//3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三级缓存"Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}

UserService和UserDao循环依赖的过程结合上述三级缓存描述一下

  • UserService 实例化对象,但尚未初始化,将UserService存储到三级缓存
  • UserService 属性注入,需要UserDao,从缓存中获取,没有UserDao;
  • UserDao实例化对象,但尚未初始化,将UserDao存储到到三级缓存
  • UserDao属性注入,需要UserService,从三级缓存获取UserService,UserService从三级缓存移入二级缓存
  • UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存
  • UserService 注入UserDao;
  • UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存

(2)Aware接口

Aware接口是一种框架辅助属性注入的一种思想,其他框架中也可以看到类似的接口。框架具备高度封装性,我们接触到的一般都是业务代码,一个底层功能API不能轻易的获取到,但是这不意味着永远用不到这些对象,如果用到了,就可以使用框架提供的类似Aware的接口,让框架给我们注入该对象。

image-20250404152143059

image-20250404152209620

7.整合第三方框架(如何使用第三方功能)

(1)使用默认命名空间 beans

Spring整合MyBatis的步骤如下:

原始代码

public static void main(String[] args) throws IOException {// 加载 MyBatis 配置文件String resource = "com/example/config/mybatis-config.xml";Reader reader = Resources.getResourceAsReader(resource);// 构建 SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);// 打开 SqlSessiontry (SqlSession session = sqlSessionFactory.openSession()) {// 获取 MapperUserMapper userMapper = session.getMapper(UserMapper.class);// 查询用户User user = userMapper.selectUserById(1);System.out.println("User: " + user.getUsername() + ", Password: " + user.getPassword());// 插入用户User newUser = new User();newUser.setUsername("newuser");newUser.setPassword("newpassword");userMapper.insertUser(newUser);session.commit(); // 提交事务}}
  • 导入MyBatis整合Spring的相关坐标;

  • 编写Mapper和Mapper.xml;

  • 配置SqlSessionFactoryBean和MapperScannerConfigurer;

    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="url" value="jdbc:mysql://localhost:3306/mybatis"></property><property name="username" value="root"></property><property name="password" value="root"></property>
    </bean>
    <!--配置SqlSessionFactoryBean-->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--配置Mapper包扫描-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.itheima.dao"></property>
    </bean>
    
  • 编写测试代码

原理(对照原始代码看)

  • SqlSessionFactoryBean:实现了FactoryBean规范,用于提供SqlSessionFactory;用于创建SqlSession

  • MapperScannerConfigurer:实现了BeanDefinitionRegistryPostProcessor接口,完成注册,用于扫描指定包下的mapper注册到BeanDefinitionMap中;

  • MapperFactoryBean:实现了FactoryBean规范,它的getObject方法就是this.getSqlSession().getMapper(this.mapperInterface);

  • ClassPathMapperScanner:在mapper(接口,无法实例化成一个对象)注册到BeanDefinitionMap后,动态修改BeanDefinitionMap,对于每一个mapper的class修改成MapperFactoryBean

    definition.setAutowireMode(2) 修改了自动注入状态(根据类型),所以MapperFactoryBean中的setSqlSessionFactory会自动注入进去。

使用注解整合

@Configuration
@ComponentScan("com.itheima")
@MapperScan("com.itheima.mapper")
public class ApplicationContextConfig {@Beanpublic DataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();//省略部分代码return dataSource;}@Beanpublic SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);return sqlSessionFactoryBean;
}}

@MapperScan不是Spring提供的注解,是MyBatis为了整合Spring,在整合包org.mybatis.spring.annotation中提供的注解。这个注解上有一个元注解,@Import({MapperScannerRegistrar.class}),当@MapperScan被扫描加载时,会解析@Import注解,从而加载指定的类,此处就是加载了MapperScannerRegistrar。

MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口,Spring会自动调用registerBeanDefinitions方法,该方法中又注册MapperScannerConfigurer类,而MapperScannerConfigurer类作用是扫描Mapper,向容器中注册Mapper对应的MapperFactoryBean

@Import注解

@Import可以导入如下三种类:

  • 普通的配置类

  • 实现ImportSelector接口的类

    重写String[] selectImports(AnnotationMetadata annotationMetadata)方法,//返回要进行注册的Bean的全限定名数组

  • 实现ImportBeanDefinitionRegistrar接口的类

    重写registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry),手动注册BeanDefinition

(2)使用第三方命名空间(如何生效的)

需求:加载外部properties文件,将键值对存储在Spring容器中

jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root

引入context命名空间,在使用context命名空间的标签,使用SpEL表达式在xml或注解中根据key获得value

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:property-placeholder location="classpath:jdbc.properties" /><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean>
<beans>
  • 将自定义标签的约束 与 物理约束文件与网络约束名称的约束 以键值对形式存储到一个spring.schemas文件里,该文件存储在类加载路径的 META-INF里,Spring会自动加载到;

    http\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context.xsd
    

    在xsd文件中就定义了命令空间下有哪些子标签

  • 将自定义命名空间的名称 与 自定义命名空间的处理器映射关系 以键值对形式存在到一个叫spring.handlers文件里,该文件存储在类加载路径的 META-INF里,Spring会自动加载到;

    http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
    
  • 在ContextNamespaceHandler中,会为命名空间中的每一个标签都注册一个解析器

    public class ContextNamespaceHandler extends NamespaceHandlerSupport {public ContextNamespaceHandler() {}public void init() {this.registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());this.registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());this.registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());this.registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());this.registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());this.registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());this.registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());}
    }
    

    根据标签,找到对应的解析器进行解析

8.Spring注解的解析原理

(1)xml配置组件扫描

<context:component-scan base-package="com.itheima"/>

component-scan是一个context命名空间下的自定义标签,所以要找到对应的命名空间处理器NamespaceHandler 和 解析器.

将ComponentScanBeanDefinitionParser进行了注册

(2)配置类配置组件扫描

@Configuration
@ComponentScan("com.itheima")
public class AppConfig {
}

使用AnnotationConfigApplicationContext容器在进行创建时,内部调用了如下代码,该工具注册了几个Bean后处理器

image-20250404163740206

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

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

相关文章

人工智能爬虫导致维基共享资源带宽需求激增 50%

2025 年 4 月 1 日&#xff0c;维基媒体基金会在博文中表示&#xff0c;自 2024 年 1 月以来&#xff0c;维基共享资源下载多媒体的带宽消耗激增 50%&#xff0c;这一变化趋势主要由用于 AI 训练数据集的网络爬虫导致。以下是具体分析1&#xff1a; 爬虫流量特征与数据存储模式…

2007-2019年各省地方财政交通运输支出数据

2007-2019年各省地方财政交通运输支出数据 1、时间&#xff1a;2007-2019年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;行政区划代码、地区、年份、地方财政交通运输支出 4、范围&#xff1a;31省 5、指标说明&#xff1a;地方财政交通运输支出是指地方…

【爬虫开发】爬虫开发从0到1全知识教程第14篇:scrapy爬虫框架,介绍【附代码文档】

本教程的知识点为&#xff1a;爬虫概要 爬虫基础 爬虫概述 知识点&#xff1a; 1. 爬虫的概念 requests模块 requests模块 知识点&#xff1a; 1. requests模块介绍 1.1 requests模块的作用&#xff1a; 数据提取概要 数据提取概述 知识点 1. 响应内容的分类 知识点&#xff1a…

【CMake】《CMake构建实战:项目开发卷》笔记-Chapter8-生成器表达式

第8章 生成器表达式 生成器表达式&#xff08;generator expression&#xff09;是由CMake生成器进行解析的表达式&#xff0c;因此&#xff0c;这些表达式只有在CMake的生成阶段才被解析为具体的值。 CMake在生成阶段&#xff0c;能够根据具体选用的构建系统生成器生成特定…

Docker安装、配置Mysql5.7

1.创建必要的目录 # 创建目录 mkdir -p ~/docker/software/mysql/{conf,log,data} 2.如果没有docker-compose.yml文件的话&#xff0c;先创建docker-compose.yml 配置文件一般长这个样子 version: 3services:mysql:image: mysql:5.7.36container_name: mysqlports:- "…

【C++学习笔记】十三、速通笔记

完整的C编程教程 目录 开发环境配置C知识体系现代C特性设计模式数据结构CMake项目构建调试技巧进阶主题学习资源 1. 开发环境配置 1.1 安装编译器 sudo apt-get install g build-essential1.2 安装构建工具 sudo apt-get install cmake1.3 VS Code配置 安装C扩展配置调试…

网络运维学习笔记(DeepSeek优化版)027 OSPF外部路由计算

文章目录 OSPF外部路由计算1. 实验拓扑与基础配置2. 关键配置命令2.1 引入静态路由2.2 查看路由表 3. LSA生成与传播分析3.1 ASBR角色通告&#xff08;1类LSA&#xff09;3.2 外部路由通告&#xff08;5类LSA&#xff09;3.3 外部路由引入过程 4. 5类LSA关键字段解析5. 外部路由…

【Python使用】嘿马推荐系统全知识和项目开发教程第2篇:1.4 案例--基于协同过滤的电影推荐,1.5 推荐系统评估【附代码

教程总体简介&#xff1a;1.1 推荐系统简介 学习目标 1 推荐系统概念及产生背景 2 推荐系统的工作原理及作用 3 推荐系统和Web项目的区别 1.3 推荐算法 1 推荐模型构建流程 2 最经典的推荐算法&#xff1a;协同过滤推荐算法&#xff08;Collaborative Filtering&#xff09; 3 …

运算放大器(五)电压比较器

比较器在最常用的简单集成电路中排名第二&#xff0c;仅次于排名第一的运算放大器。 电压比较器是一种用来比较输入信号电压与参考电压大小&#xff0c;并将比较结果以高电平或低电平形式输出的一种信号处理电路&#xff0c;广泛应用于各种非正弦波的产生和变换电路中&#xf…

Java面试黄金宝典34

1. 主键索引底层的实现原理 定义 主键索引是数据库中用于唯一标识表中每一行记录的索引&#xff0c;常见的底层实现是 B 树结构。B 树是一种平衡的多路搜索树&#xff0c;由内部节点和叶子节点组成。内部节点只存储索引键和指向下一层节点的指针&#xff0c;不存储实际数据&am…

Educational Codeforces Round 177 (Rated for Div. 2)

Educational Codeforces Round 177 (Rated for Div. 2) A. Cloudberry Jam 思路&#xff1a; 1千克果子能生产2/3千克果酱&#xff0c;生产3千克果酱则需要2千克果酱&#xff0c;所以*2即可 code: void solve() { int x; cin >> x;cout << 2 * x << e…

ARM-外部中断,ADC模数转换器

根据您提供的图片&#xff0c;我们可以看到一个S3C2440微控制器的中断处理流程图。这个流程图展示了从中断请求源到CPU的整个中断处理过程。以下是流程图中各个部分与您提供的寄存器之间的关系&#xff1a; 请求源&#xff08;带sub寄存器&#xff09;&#xff1a; 这些是具体的…

23种设计模式-行为型模式-迭代器

文章目录 简介问题解决代码设计关键点&#xff1a; 总结 简介 迭代器是一种行为设计模式&#xff0c;让你能在不暴露集合底层表现形式(列表、栈和树等)的情况下遍历集合中所有的元素。 问题 集合是编程中最常使用的数据类型之一。 大部分集合使用简单列表存储元素。但有些集…

Python 布尔类型

Python 布尔类型(Boolean) 布尔类型是Python中的基本数据类型之一&#xff0c;用于表示逻辑值。它只有两个值&#xff1a; True - 表示真False - 表示假 1. 布尔值的基本使用 # 定义布尔变量 is_active True is_admin Falseprint(is_active) # 输出: True print(is_admi…

人工智能在前端开发中的应用探索

一、人工智能在前端开发中的应用场景 人工智能&#xff08;AI&#xff09;技术的快速发展为前端开发带来了新的机遇和挑战。AI在前端开发中的应用主要集中在以下几个方面&#xff1a;智能代码生成、自动化测试、个性化推荐、智能交互设计以及性能优化。这些应用场景不仅提高了…

三维扫描助力文化遗产数字化保护

当下&#xff0c;三维扫描技术以其独特的优势&#xff0c;正逐渐成为文化遗产数字化保护的重要工具&#xff0c;让珍贵的文物得以“永生”。 三维扫描在文物数字化方面的应用&#xff1a; 高精度文物存档&#xff1a;三维扫描技术能够实现对文物的快速、无损扫描&#xff0c;…

如何将生活场景转换为数据模型模型仿真?

从家到公司有31公里&#xff0c;其中有一个2车道右转立交桥汇入另外一条路&#xff0c;每次都是那个堵车&#xff0c;导致路上的行程在45分钟到70分钟左右&#xff1f;前面或后面路段都是3-4车道&#xff0c;足够通行。如何解决这个难题&#xff0c;是否可搭建数学模型实现可视…

Java学习总结-io流-练习案例

将文档的内容排序&#xff1a; public static void main(String[] args) throws IOException {File dir new File("J:\\360downloads\\wpcache\\srvsetwp\\xxx\\test.txt");BufferedReader br new BufferedReader(new FileReader(dir));//把按行读取到的内容&#…

【C++】STL库_stack_queue 的模拟实现

栈&#xff08;Stack&#xff09;、队列&#xff08;Queue&#xff09;是C STL中的经典容器适配器 容器适配器特性 不是独立容器&#xff0c;依赖底层容器&#xff08;deque/vector/list&#xff09;通过限制基础容器接口实现特定访问模式不支持迭代器操作&#xff08;无法遍历…

LangChain核心解析:掌握AI开发的“链“式思维

0. 思维导图 1. 引言 🌟 在人工智能快速发展的今天,如何有效地利用大语言模型(LLM)构建强大的应用成为众多开发者关注的焦点。前面的课程中,我们学习了正则表达式以及向量数据库的相关知识,了解了如何处理文档并将其附加给大模型。本章我们将深入探讨LangChain中的核心概…