基于xml的Spring应用-1

news2024/12/22 22:00:39

基于xml的Spring应用

Spring的get方法

方法定义返回值和参数
Object getBean (String beanName)根据beanName从容器中获取Bean实例,要求容器中Bean唯一
返回值为Object,需要强转
T getBean (Class type)根据Class类型从容器中获取Bean实例,要求容器中Bean类型唯一
返回值为Class类型实例,无需强转
T getBean (String beanName,Class type)根据beanName从容器中获得Bean实例,返回值为Class类型实例,无需强转
//根据beanName获取容器中的Bean实例,需要手动强转
UserService userservice = (UserService) applicationContext.getBean( "userService");
//根据Bean类型去容器中匹配对应的Bean实例,如存在多个匹配Bean则报错
UserService userService2 = applicationContext.getBean(UserService.class);
//根据beanName获取容器中的Bean实例,指定Bean的Type类型
UserService userService3 = applicationContext.getBean ( "userService",UserService.class) ;

Spring配置非自定义Bean

在实际开发中有些功能类并不是我们自己定义的,而是使用的第三方jar包中的,那么,这些Bean要想让Spring进行管理,也需要对其进行配置,配置非自定义的Bean需要考虑如下两个问题:

  1. 配置的Bean的实例化方式是什么?是通过无参构造函数实例化还是有参构造函数、静态工厂方法或实例工厂方法实例化?
  2. 被配置的Bean是否需要注入必要的属性?如果是,则需要在配置文件中为该Bean设置属性值或通过其他方式进行注入。
示例1:配置Druid数据源交由Spring管理——存在构造函数
导入坐标
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid</artifactId>
	<version>1.0.28</version>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.38</version>
</dependency>
找到对应jar报的class的位置,然后通过set的方式注入bean
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
	<property name="keepAlive" value="true"></property>
	<property name="name" value="com.mysql.jdbc.Driver"></property>
</bean>
2)配置Connection交由Spring管理——不存在构造函数的
Connection的产生是通过DriverManager的静态方法getConnection获取的,所以我们要用静态工厂方式配置
Class.forName("com.mysql.jdbc.Drive")
Connection connection = DriverManager.getConnection( url:"",user: "",password:"");


<bean class="java.lang.class" factory-method="forName">
	<constructor-arg name="className" value="com.mysql.jdbc.Driver" />
</bean>
<bean id="connection" class="java.sql.DriverManager" factory-method="getConnection"scope="prototype">
	<constructor-arg name="url" value="jdbc:mysql:///mybatis"/>
	<constructor-arg name="user" value="root"/>
	<constructor-arg name="password" value="root"/>
</bean>
3)配置日期对象交由Spring实现——工厂Bean实现
指定产生一个日期格式的对象,源码如下
String currentTimeStr = "2023-08-27 07:20:00";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat ("yyvy-MM-dd HH:mm:ss");
Date date = simpleDateFormat.parse (currentTimeStr);
Spring配置的方式产生
<bean id="dateFormat" class="java.text.SimpleDateFormat">
	<constructor-arg name="pattern" value="yyyy-MM-dd HH:mm:ss"></constructor-arg>
</bean>
<bean id="date" class="java.util.Date" factory-bean="dateFormat" factory-method="parse">
	<constructor-arg name="source" value="2023-08-27 07:20:00"></constructor-arg>
</bean>
4)配置MyBatis的SqlSessionFactory交由Spring管理
// 配置静态
InputStream in = Resources.getResourceAsStream("mybaits-config.xml");
// 无参构造
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 实例工厂
SqlSessionFactory sqlSessionFactory = builder.build(in);

<bean id="resources" class="org.apache.ibatis.io.Resources" factory-method="getResourceAsStream">
	<constructor-arg name="resource" value="mybaits-config.xml" ></constructor-arg>
</bean>
<bean class="org.apache.ibatis.session.SqlSessionFactoryBuilder" id="factoryBuilder">
</bean>
<bean class="org.apache.ibatis.session.SqlSessionFactory" id="sessionFactory" factory-bean="factoryBuilder" factory-method="build">
	<constructor-arg name="inputStream" ref="resources"></constructor-arg>
</bean>

Bean实例化的基本流程

在Spring框架中,<bean>标签对应着一个BeanDefinition对象。这个对象中封装了该bean的信息,包括bean的类名、构造函数、属性、依赖关系等等。这个过程是在Spring容器初始化的时候进行的。

在初始化过程中,Spring会将所有的BeanDefinition对象存储到一个名为beanDefinitionMap的Map集合中。然后,Spring会遍历beanDefinitionMap集合,使用反射创建Bean实例对象。这个实例对象创建完毕后,Spring会将这个对象存储到一个名为singletonObjects的Map集合中

当调用getBean方法时,Spring会从singletonObjects集合中查找对应的Bean实例对象,如果存在则直接返回。如果不存在,则会根据BeanDefinition中封装的信息创建一个新的Bean实例对象,并存储到singletonObjects集合中。最终,getBean方法会返回这个Bean实例对象

值得注意的是,singletonObjects集合中存储的都是单例Bean,也就是说,如果一个Bean被配置为单例,那么无论调用多少次getBean方法,都会返回同一个实例对象。而如果一个Bean被配置为非单例,那么每次调用getBean方法都会创建一个新的实例对象返回。这个区别是由BeanDefinition中的scope属性控制的

image-20230504214732920

Bean实例化的流程

  1. 加载xml配置文件,解析获取每个<bean>的信息,封装成BeanDefinition对象
  2. 将BeanDefinition对象存储在beanDefinitionMap中,以便后续使用
  3. ApplicationContext底层遍历beanDefinitionMap,使用反射创建Bean实例对象,这个过程中需要考虑Bean实例化的方式(无参构造、有参构造、工厂方法等)和需要注入的属性
  4. 创建好的Bean实例对象被存储到singletonObjects中,以便后续获取
  5. 当执行getBean方法时,从singletonObjects中匹配Bean实例对象并返回

在整个流程中,Bean实例化的过程是由Spring容器进行管理和调用的,开发者无需手动创建Bean实例对象。

Spring的后处理器

当Spring容器初始化时,它会加载所有的Bean定义,并将它们存储在一个Map中。这些Bean定义可以在XML配置文件中声明,也可以通过Java配置进行编程式声明

BeanFactoryPostProcessor是一个特殊类型的Bean后处理器。它允许我们在容器实例化任何其他Bean之前对Bean定义进行更改或者添加新的Bean定义。可以用它来实现自定义逻辑,例如动态修改Bean定义、动态注册Bean定义等等。

BeanFactoryPostProcessor的典型用途是为某个BeanFactory进行自定义配置,例如设置属性值或者更改BeanDefinition属性。在BeanFactoryPostProcessor执行过程中,可以修改beanDefinitionMap中的BeanDefinition,包括Bean的作用域、依赖关系等等。而且,BeanFactoryPostProcessor也可以添加新的BeanDefinition,以及删除不需要的BeanDefinition。

BeanPostProcessor是另一种类型的Bean后处理器,它允许在Bean实例化时进行拦截。BeanPostProcessor通常用于执行一些自定义逻辑,例如修改Bean属性或者调用Bean方法。例如,Spring AOP就是基于BeanPostProcessor来实现的。

总体来说,后处理器是Spring框架提供的非常重要的扩展点。通过使用后处理器,我们可以修改Bean的定义和行为,以适应特定的业务需求。

BeanFactoryPostProcessor

BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的一个子接口,它在BeanFactoryPostProcessor的基础上提供了一个额外的方法postProcessBeanDefinitionRegistry,用于在BeanDefinition被注册到BeanFactory之前,对BeanDefinition进行更复杂的修改或者注册。可以使用该接口实现自定义的BeanDefinition注册逻辑,例如通过读取配置文件、数据库、网络等方式动态地注册BeanDefinition

这段代码主要实现了动态修改和注册Bean的功能。具体来说,这段代码通过以下几个部分实现:

  1. 定义了一个XML配置文件(beans.xml),其中定义了两个Bean:userService和userDao。

    <bean id="userService" class="com.congyun.service.impl.UserServiceImpl" autowire="byName">
    </bean>
    <bean id="userDao" class="com.congyun.dao.impl.UserDaoImpl" scope="prototype">
    </bean>
    
  2. 定义了一个后处理器类(myBeanProcesser),该类实现了BeanFactoryPostProcessor接口,重写了postProcessBeanFactory方法。在该方法中,通过修改Bean定义信息和注册新的Bean实例实现动态修改和并注册了一个新的Bean实例personDao的效果

    public class myBeanProcesser implements BeanFactoryPostProcessor {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
            // 修改configurableListableBeanFactory
            BeanDefinition date = configurableListableBeanFactory.getBeanDefinition("userService");
            date.setBeanClassName("com.congyun.dao.impl.UserDaoImpl");
    
            // 通过代码注册Bean
            BeanDefinition PersonDao = new RootBeanDefinition();
            PersonDao.setBeanClassName("com.congyun.dao.impl.PersonDaoImpl");
            DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
            defaultListableBeanFactory.registerBeanDefinition("personDao",PersonDao);
        }
    }
    
  3. 在测试方法中,创建了一个ApplicationContext对象,该对象读取了classpath下的beans.xml配置文件,并根据配置文件中的信息创建相应的Bean实例。同时,也获取了通过后处理器修改和注册后的Bean实例

    @Test
    public void ListTest() throws Exception{
        ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
        Object userService = app.getBean("userService");
        PersonDao personDao = (PersonDao) app.getBean("personDao");
        System.out.println(personDao);
        System.out.println(userService);
    }
    
  4. 综上,这段代码的主要作用是实现了动态修改和注册Bean的功能,并通过测试方法验证了修改和注册的效果。

BeanFactoryPostProcessor是一个接口规范,它定义了一个方法postProcessBeanFactory(),用于在BeanFactory加载Bean定义信息后、Bean实例化前被执行。实现了该接口的类只要交由Spring容器管理,那么Spring就会回调该接口的方法,在该方法中可以对BeanDefinition进行注册和修改等操作。这个接口在Spring中的作用非常重要,可以实现很多高级的功能,比如动态注入Bean等

示例

首先,在测试类中创建了一个ApplicationContext对象,该对象会读取classpath下的beans.xml配置文件,并根据配置文件中的信息创建相应的Bean实例。这个步骤是Spring IoC容器启动的过程,根据XML配置文件中的信息实例化相应的Bean。

ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");

然后,在测试类中配置了一个实现了BeanDefinitionRegistryPostProcessor接口的testBeanFactoryPostProcessor类,并将其声明为一个Bean,用于注册新的BeanDefinition信息。BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口,它允许我们在Spring容器创建Bean之前修改Bean的定义信息,从而达到动态注册Bean的目的。

<bean class="com.congyun.processer.testBeanFactoryPostProcessor"></bean>

接下来,实现BeanDefinitionRegistryPostProcessor接口的testBeanFactoryPostProcessor类中重写了postProcessBeanDefinitionRegistry方法,在该方法中注册了一个新的BeanDefinition,其Bean的实现类为PersonDaoImpl。

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
    // 先执行-子类方法
    // 注册新的Bean
    System.out.println("testBeanFactoryPostProcessor的postProcessBeanDefinitionRegistry方法");
    BeanDefinition PersonDao = new RootBeanDefinition("com.congyun.dao.impl.PersonDaoImpl");
    beanDefinitionRegistry.registerBeanDefinition("personDao",PersonDao);
}

最后,在测试方法中通过ApplicationContext对象获取该新注册的Bean实例并输出。

PersonDao personDao = (PersonDao) app.getBean("personDao");
System.out.println(personDao);

在这个过程中,Spring容器在初始化时会调用所有实现了BeanFactoryPostProcessor接口的类,并按照特定的顺序调用它们的postProcessBeanFactory方法。而在BeanFactoryPostProcessor中,又有BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法在postProcessBeanFactory方法之前被调用,因此实现了BeanDefinitionRegistryPostProcessor接口的类可以在BeanFactoryPostProcessor之前注册Bean定义信息,实现动态注册Bean的效果。

综上所述,这段代码演示了如何使用实现了BeanDefinitionRegistryPostProcessor接口的类实现动态注册Bean的操作,提供了更多的灵活性。

这里还有通过注解配置Bean的,但是我现在还不太了解注解,之后学习完注解以后补上

BeanPostProcessor

BeanPostProcessor是一个在Bean实例化和依赖注入之后,初始化方法执行之前和之后提供扩展点的接口,它允许开发者在Bean的初始化过程中进行自定义操作。BeanPostProcessor接口定义了两个回调方法:

public interface BeanPostProcessor {
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
**@Nullable**是一个注解,它可以用于表示一个元素(如方法参数、方法返回值、域、局部变量等)可以为 null。在 Java 中,null 值表示缺失或未初始化的值。当一个元素被标注为 `@Nullable` 时,这意味着它的值可以为 null,使用该元素的代码需要注意 null 值的情况,以避免出现 NullPointerException 异常。

在 Spring 框架中,`@Nullable` 注解通常用于方法参数或方法返回值上,用于提供额外的类型安全性和可读性。例如,当一个方法参数被标注为 `@Nullable` 时,调用该方法的代码就需要考虑到该参数值可能为 null 的情况,并且在代码中进行相应的处理,以避免可能的异常情况。

postProcessBeforeInitialization 方法在 Bean 的初始化方法被调用之前被执行,可以在此方法中对 Bean 进行一些操作,可以实现 BeanPostProcessor 接口,并重写 postProcessBeforeInitialization 方法,下面是一些例子:

  1. 为 Bean 设置默认属性值:假设有一个名为 User 的 Bean,我们可以通过实现 BeanPostProcessor 接口,在 postProcessBeforeInitialization 方法中判断 User 的某个属性是否为空,如果为空则设置默认值。

    public class UserDefaultValueProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof User) {
                User user = (User) bean;
                if (user.getAge() == null) {
                    user.setAge(18);
                }
                if (user.getName() == null) {
                    user.setName("Unknown");
                }
            }
            return bean;
        }
    }
    
  2. 实现日志记录:我们可以使用 BeanPostProcessor 在 Bean 初始化之前和之后记录日志

    public class LoggingBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            //记录初始化前的日志
            System.out.println("Initializing bean " + beanName + " : " + bean.getClass());
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            //记录初始化后的日志
            System.out.println("Bean " + beanName + " initialized successfully.");
            return bean;
        }
    }
    
  3. 实现安全检查:我们可以使用 BeanPostProcessor 在 Bean 初始化之前和之后执行安全检查

    public class SecurityCheckBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof UserService) {
                if (SecurityUtils.hasAccess("user:add")) {
                    return bean;
                } else {
                    throw new SecurityException("Access denied.");
                }
            }
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    }
    

postProcessAfterInitialization 方法在 Bean 的初始化方法被调用之后被执行,同样可以在此方法中对 Bean 进行一些操作,例如添加一些功能性的处理,当我们需要在Bean的初始化前后执行一些逻辑时,就可以使用Bean后处理器。下面是一些使用Bean后处理器可以实现的功能性处理例子:

  1. 属性值的加密和解密:我们可以使用Bean后处理器,在Bean的初始化前后对属性值进行加密和解密操作,增强数据安全性。
  2. 类型转换:Bean后处理器可以在Bean初始化之前对属性进行类型转换,避免在属性注入时出现类型错误。
  3. 自定义日志输出:我们可以在Bean后处理器中添加自定义的日志输出逻辑,记录Bean的初始化过程,便于排查错误。
  4. 检查Bean是否实现了指定接口:我们可以在Bean后处理器中检查Bean是否实现了指定的接口,如果没有实现则抛出异常或者进行其他处理。
  5. 对象实例的包装:在Bean后处理器中,我们可以对Bean进行包装,比如将Bean包装成一个代理对象,以增加Bean的功能。

这些例子只是说明了Bean后处理器可以实现的功能,实际使用时可能还有更多的应用场景。

下面给出一个例子,展示如何使用Bean后处理器对属性进行加密和解密。

public class EncryptionBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof Encryptable) {
            Encryptable encryptable = (Encryptable) bean;
            String encryptedValue = encryptable.getEncryptedValue();
            String decryptedValue = decrypt(encryptedValue);
            encryptable.setDecryptedValue(decryptedValue);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof Encryptable) {
            Encryptable encryptable = (Encryptable) bean;
            String decryptedValue = encryptable.getDecryptedValue();
            String encryptedValue = encrypt(decryptedValue);
            encryptable.setEncryptedValue(encryptedValue);
        }
        return bean;
    }

    private String decrypt(String encryptedValue) {
        // decryption logic
        return decryptedValue;
    }

    private String encrypt(String decryptedValue) {
        // encryption logic
        return encryptedValue;
    }
}

这两段代码是一个示例的Bean后处理器,用于对实现了Encryptable接口的Bean对象进行加密和解密操作。

postProcessBeforeInitialization方法在Bean的初始化方法被调用之前被执行,该方法首先判断当前传入的bean是否实现了Encryptable接口,如果是,则将其转换为Encryptable类型,并获取其加密后的值,进行解密操作,最后将解密后的值设置到Encryptable对象中,以便在初始化时能够获取到解密后的值

postProcessAfterInitialization方法在Bean的初始化方法被调用之后被执行,该方法同样判断当前传入的bean是否实现了Encryptable接口,如果是,则将其转换为Encryptable类型,并获取其解密后的值,进行加密操作,最后将加密后的值设置到Encryptable对象中,以保证在Bean对象被使用时能够获取到加密后的值

在 Bean 后处理器中, postProcessBeforeInitializationpostProcessAfterInitialization 这两个方法的返回值是经过处理后的 Bean 对象。如果返回 null,那么处理后的 Bean 对象就会变成 null。

postProcessBeforeInitialization 方法中,如果返回 null,那么原始的 Bean 对象将不会被处理,直接跳过后续的处理过程,直接返回原始的 Bean 对象

postProcessAfterInitialization 方法中,如果返回 null,那么处理后的 Bean 对象就会变成 null。在这种情况下,调用方将无法得到已处理的 Bean 对象,而是得到一个 null 对象

所以,一般情况下我们会在 Bean 后处理器的实现中返回处理后的 Bean 对象,这样可以确保处理的连续性和完整性,避免因为返回 null 导致的不必要问题

ps

原始的 Bean 对象指的是容器实例化的、尚未被修改或增强的 Bean 对象。在 Bean 后处理器的 postProcessBeforeInitialization() 方法中,传入的第一个参数 bean 就是原始的 Bean 对象。在该方法中,我们可以对该对象进行各种修改和增强操作,比如修改其属性、检查其实现的接口等等。而在 postProcessAfterInitialization() 方法中,同样需要返回一个修改或增强后的 Bean 对象,此时传入的 bean 参数就是经过前一个方法修改后的对象。

需要注意的是,在 postProcessBeforeInitialization() 方法中对原始的 Bean 对象进行修改,会影响后续 postProcessAfterInitialization() 方法中对 Bean 的处理。因此,在实现 Bean 后处理器时,应该谨慎地考虑对 Bean 对象的修改,确保不会破坏 Bean 的正确性。

postProcessAfterInitializationpostProcessBeforeInitialization方法是针对所有单例池中的bean对象的。当Spring容器创建一个单例bean时,它会首先调用postProcessBeforeInitialization方法,然后调用bean的初始化方法(如果有的话),最后再调用postProcessAfterInitialization方法。这些方法可以让开发人员在Bean被初始化前后添加额外的逻辑处理,以满足各种定制化需求。值得注意的是,这些方法只适用于单例bean。对于非单例bean,Spring只会在创建Bean实例时调用它们

Bean 对象的修改,确保不会破坏 Bean 的正确性。

postProcessAfterInitializationpostProcessBeforeInitialization方法是针对所有单例池中的bean对象的。当Spring容器创建一个单例bean时,它会首先调用postProcessBeforeInitialization方法,然后调用bean的初始化方法(如果有的话),最后再调用postProcessAfterInitialization方法。这些方法可以让开发人员在Bean被初始化前后添加额外的逻辑处理,以满足各种定制化需求。值得注意的是,这些方法只适用于单例bean。对于非单例bean,Spring只会在创建Bean实例时调用它们

image-20230505221849999

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

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

相关文章

SpringBoot 创建 WebService

开发环境: IDEA 2022.1.4 目录 1. 概述 2. 实现步骤 2.1 POM现加依赖 2.2 定义接口 IWebService 2.3 创建类 IWebServiceImpl 并实现接口 IWebService 2.4 配置类 CxfConfig 2.5 启动服务 2.6 测试 1. 概述 虽然webservice这块使用很少&#xff0c;但在局域网作服务还是相…

自动化测试之 selenium 的安装以及 selenium IDE 录制自动化脚本的用法

文章目录 1. 什么是自动化测试1&#xff09;单元测试2&#xff09;接口自动化3&#xff09;UI 自动化 2. Selenium 介绍1&#xff09;Selenium IDE2&#xff09;Webdriver3&#xff09;Selenium Grid 3. 如何使用 Selenium IDE 录制脚本4. 在 python 环境中安装 Selenium 框架 …

RSA--维纳攻击--代码和题目分析

文章目录 维纳攻击原理&#xff1a;维纳攻击脚本[羊城杯 2020]RRRRRRRSA 1题目描述&#xff1a;题目分析&#xff1a; 收获与体会&#xff1a; 维纳攻击原理&#xff1a; 两位大佬讲得非常清楚&#xff08;搬运工就是我&#xff09;&#xff1a;https://zhuanlan.zhihu.com/p/…

代码随想录算法训练营第五十二天| 300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组

文章目录 300.最长递增子序列674. 最长连续递增序列718. 最长重复子数组 300.最长递增子序列 想清楚如何推导dp数组是关键 两层for循环&#xff0c;因为递增序列不是连续的 题目链接&#xff1a;代码随想录 解题思路&#xff1a; 1.dp[i]表示i之前包括i的以nums[i]结尾的最长递…

SpringBoot整合Mybatis-Plus实现浏览数据新增、Redis进行热度排名

在开发Web项目时&#xff0c;常用到的技术就是SpringBoot和Mybatis-Plus。本文将介绍如何使用SpringBoot整合Mybatis-Plus实现一个浏览数据新增功能&#xff0c;以及如何用Redis进行热度排名统计&#xff0c;最后用Vue进行数据渲染。 一、SpringBoot整合Mybatis-Plus 1. 新建…

0 基础 Java 自学之路(2023年最新版)

目录 一、语言的选择二、Java学习路线三、学习资料哪里找&#xff1f;1、Java经典书籍推荐2、Java经典视频推荐3、经典博客推荐 四、如何规划时间&#xff1f;五、是否要报培训班&#xff1f; 写了10多年的代码&#xff0c;之前做过某东的高级架构师&#xff0c;在技术这条路上…

BIOS主板(非UEFI)安装fedora36的方法

BIOS主板(非UEFI)安装fedora36的方法 现实困难&#xff1a;将Fedora-Workstation-Live-x86_64-38-1.6.iso写入U盘制作成可启动U盘启动fedora38安装时报错如下内容&#xff1a; Failed to find a suitable stage1 device: EFI System Partition cannot be of type ntfs: EFI Sys…

携创教育:自考、成考、开放大学几年能够毕业拿证?

目前&#xff0c;国家承认的成人学历提升的形式只有3种&#xff0c;分别是自考&#xff0c;成考&#xff0c;开放大学。 ▼各学历形式拿证时间▼ ★自学考试 自考没有入学考试&#xff0c;只需要参加相应的课程考试&#xff0c;所有课程考试合格后&#xff0c;符合毕业条件即可…

【论文简述】Cross-Attentional Flow Transformer for Robust Optical Flow(CVPR 2022)

一、论文简述 1. 第一作者&#xff1a;Xiuchao Sui、Shaohua Li 2. 发表年份&#xff1a;2021 3. 发表期刊&#xff1a;arxiv 4. 关键词&#xff1a;光流、Transformer、自注意力、交叉注意力、相关体 5. 探索动机&#xff1a;由于卷积的局部性和刚性权重&#xff0c;有限…

Flutter 中使用 Widgetbook 管理你的组件

Flutter 中使用 Widgetbook 管理你的组件 前言 Flutter 界面开发中我们有几个痛点 &#xff1a; 与设计师协作复用一套设计规范&#xff08;figma&#xff09; 可视化的管理你的组件代码&#xff08;基础组件、业务组件&#xff09; 不同设备尺寸测试你的组件 实时修改你的测试…

【事务】在spring中事务不生效的场景总结

在开发过程中会遇到事务失效的问题&#xff0c;所以在开发中要特别注意&#xff0c;下面我自己总结了事务不生效的场景&#xff0c;提醒自己。 一般出现问题分为几大类&#xff1a; 配置问题spring aop代理问题底层数据库不支持事务问题Transactional 配置错误开发过程中使用错…

Go有序map:orderedmap

有序映射 与传统的无序映射&#xff08;Map&#xff09;不同&#xff0c;orderedmap包中的有序映射&#xff08;OrderedMap&#xff09;可以记录键值对的插入顺序。orderedmap提供了一些有用的API&#xff0c;用来存储、删除、查询和遍历键值对。 获取OrderedMap 你可以通过Ord…

地面分割--Fast Segmentation of 3D Point Clouds for Ground Vehicles论文阅读与源码分析

文章目录 1写在前面的话2点云投影分块3地面点云分割4核心代码阅读投影分块直线拟合代码分割地面点云 5实验效果参考 1写在前面的话 这篇文章属于地面分割领域非常经典的一篇论文&#xff0c;论文具有速度快&#xff0c;在一定程度能适应有坡度的地形&#xff0c;文章主要分为两…

学习使用ansible自动化运维工具

目录 一、虚拟机环境 二、yum方式部署 三、ansible使用 &#xff08;一&#xff09;将ansible服务器上文件分发给各节点 1. 创建一个要复制的文件&#xff0c;并复制到Ansible管理主机上 2.编辑Ansible的playbook文件&#xff0c;将copy模块添加到任务列表中 3. 运行play…

【c++迭代器模拟实现】

目录&#xff1a; 前言一、STL初始二、六大组件之迭代器迭代器初始迭代器的模拟实现&#xff08;1&#xff09;victor正向迭代器反向迭代器1反向迭代器2反向迭代器3 &#xff08;2&#xff09;list正向迭代器反向迭代器 总结 前言 打怪升级&#xff1a;第52天 一、STL初始 什…

和chatgpt一样的大模型LLaMA可以运行在pc上?

未来已来,大模型依据压缩模型的方式,可以在普通的PC上运行. LLaMA Facebook的LLaMA 模型和Georgi Gerganov 的llama.cpp的结合。 LLaMA&#xff0c;这是一组包含 7B 到 65B 参数的基础语言模型。我们在数万亿个令牌上训练我们的模型&#xff0c;并表明可以仅使用公开可用的数…

【Android入门到项目实战-- 9.1】—— 传感器的使用教程

目录 传感器的定义 三大类型传感器 1、运动传感器 2、环境传感器 3、位置传感器 传感器开发框架 1、SensorManager 2、Sensor 3、SensorEvent 4、SensorEventListener 一、使用传感器开发步骤 1、获取传感器信息 1)、获取传感器管理器 2)、获取设备的传感器对象列…

Java红黑树

概述 红黑树是一种自平衡的二叉查找树&#xff0c;是计算机科学中用到的一种数据结构。1972年出现的&#xff0c;当时被称之为平衡二叉B树。在1978年被修改为红黑树。红黑树是一种特殊的二叉查找树&#xff0c;红黑树上的每一个节点都有存储位表示节点的颜色。每一个节点可以是…

Java枚举:为什么它是单例模式的最佳选择?

前言 单例模式&#xff0c;是工作中比较常见的一种设计模式&#xff0c;通常有两种实现方式&#xff0c;懒汉式和饿汉式。但是这两种实现方式存在一些问题。懒汉式需要在多线程环境下使用同步锁机制来保证只有一个实例被创建&#xff0c;这会影响程序的性能。而饿汉式在类加载时…

《发展心理学——儿童与青少年》读书笔记

这是我读的第一本关于育儿教育类的书&#xff0c;该书的作者是David R. Shaffer&#xff0c;由北京师范大学博士生导师邹泓审校&#xff0c;由其底下的博士生们翻译。我看的是中文第九版。下面是我在阅读此书时做的关键摘录和部分感想&#xff1a; 第1章 导论:发展心理学及其研…