Spring学习笔记(2)

Spring学习笔记(2)

  • 一、Spring配置非定义Bean
    • 1.1 DruidDataSource
    • 1.2、Connection
    • 1.3、Date
    • 1.4、SqlSessionFactory
  • 二、Bean实例化的基本流程
    • 2.1 BeanDefinition
    • 2.2 单例池和流程总结
  • 三、Spring的bean工厂后处理器
    • 3.1 bean工厂后处理器入门
    • 3.2、注册BeanDefinition
    • 3.3、BeanDefinitionRegistryPostProcessor
    • 3.4 完善实例化流程图
    • 3.5、自定义@Component
  • 四、Spring的Bean后处理器
    • 4.1 概念和入门
    • 4.2 当中的一些调用方法的顺序
    • 4.3 更加详细的实例化基本操作
  • 五、Spring的生命周期
    • 5.1 概述
    • 5.2 初始化阶段执行的步骤
    • 5.3 初始化阶段注入属性信息封装
    • 5.4、属性注入的三种情况
      • 5.4.1 单项注入的代码验证
      • 5.4.2 循环依赖概念及解决方案
      • 5.4.3 三级缓存的设计原理
    • 5.5 循环依赖源码流程剖析
    • 5.6 Aware接口
  • 六、IoC容器实例化Bean完整流程图展示
  • 七、Spring xml方式整和第三方框架
    • 7.1 Mybatis整合Spring实现
    • 7.2、MyBatis整合Spring源码解析
    • 7.3 加载外部properties文件
    • 7.4、自定义空间步骤

一、Spring配置非定义Bean

以上在xml中配置的Bean都是自己定义的,例如: UserDaolmpl,UserServicelmpl。但是,在实际开发中有些功能类并不是我们自己定义的,而是使用的第三方jar包中的,那么,这些Bean要想让Spring进行管理,也需要对其进行配置

  • 配置非自定义的Bean需要考虑如下两个问题:
    • 被配置的Bean的实例化方式是什么?无参构造、有参构造、静态工厂方式还是实例化工厂方式;
    • 被配置的Bean是否需要注入必要属性

1.1 DruidDataSource

配置Druid数据源交由Spring管理
导入Druid坐标

<!--mysql驱动-->
<dependency><groupId>mysql</groupid><artifactId>mysql-connector-java</artifactId><version>5.1.49</version>
</dependency>
<!-- druid数据源-->
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.23</version>
</dependency> 

配置文件xml

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://localhost:3306/mybatis"></property><property name="username" value="root"></property><property name="password" value="123456"></property>
</bean> 

1.2、Connection

Connection的产生是通过DriverManager的静态方法getConnection获取的,所以我们要用静态工厂方式配置

<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="123456"/>
</bean> 

1.3、Date

产生一个指定日期格式的对象,原始代码如下

String currentTimeStr = "2023-08-27 07:20:00" ;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = simpleDateFormat.parse(currentTimeStr);

可以看成是实例工厂方式,使用Spring配置方式产生Date实例

<bean id="simpleDateFormat" class="java.text.SimpleDateFormat"><constructor-arg name="pattern" value="yyyy-MM-dd HH:mm:ss" />
</bean>
<bean id="date" factory-bean="simpleDateFormat" factory-method="parse"><constructor-arg name="source" value="2023-08-27 07:20:00"/>
</bean> 

1.4、SqlSessionFactory

配置SqlSessionFactory交由Spring管理
导入Mybatis相关坐标

<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.10</version>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version>
</dependency>
<!--静态工厂方法-->
<bean id="inputStream" class="org.apache.ibatis.io.Resources" factory-method="getResourceAsStream"><constructor-arg name="resource" value="mybatis-config.xml"></constructor-arg>
</bean>
<!--无参构造实例化-->
<bean id="builder" class="org.apache.ibatis.session.SqlSessionFactoryBuilder"></bean>
<!--实例化工厂-->
<bean id="factory" factory-bean="builder" factory-method="build"><constructor-arg name="inputStream" ref="inputStream"></constructor-arg>
</bean> 

二、Bean实例化的基本流程

2.1 BeanDefinition

  1. Spring容器在进行初始化的时候,会将xml配置的<bean>信息封装成一个BeanDefinition对象
  2. 所有的BeanDefinition对象会集中存储在BeanDefinitionMap集合当中
  3. Spring框架会调用读取器读取BeanDdfinitionMap当中的每一个信息,通过反射创建出bean对象,然后再进行初始化操作,最后将所有的数据全部存储到singletonObjects集合当中
  4. 最后通过getBean方法在singletonObjects集合当中找到创建的Bean对象

在这里插入图片描述
DefaultListableBeanFactory对象内部维护着一个Map用于存储封装好的BeanDefinitionMap

public class DefaultListableBeanFactory extends ... implements ... {//存储<bean>标签对应的BeanDefinition对象//key:是Bean的beanName,value:是Bean定义对象BeanDefinitionprivate final Map<String,BeanDefinition> beanDefinitionMap;
}

Spring框架会取出beanDefinitionMap中的每个BeanDefinition信息,反射构造方法或调用指定的工厂方法生成Bean实例对象,所以只要将BeanDefinition注册到beanDefinitionMap这个Map中,Spring就会进行对应的Bean的实例化操作

2.2 单例池和流程总结

基本流程:

  • 加载xml配置文件,解析获取配置中的每个<bean>的信息,封装成一个个的BeanDefinition对象;
  • 将BeanDefinition存储在一个名为beanDefinitionMapMap<String,BeanDefinition>中;
  • ApplicationContext底层遍历beanDefinitionMap,创建Bean实例对象;
  • 创建好的Bean实例对象,被存储到一个名为singletonObjects的Map<String,Object>中;
  • 当执行applicationContext.getBean(beanName)时,从singletonObjects去匹配Bean实例返回。

在这里插入图片描述

三、Spring的bean工厂后处理器

3.1 bean工厂后处理器入门

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

  • Spring主要有两种后处理器:
    • BeanFactoryPostProcessor: Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行;
    • BeanPostProcessor: Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行。

Bean工厂后处理器-BeanFactoryPostProcessor
BeanFactoryPostProcessor是一个接口规范,实现了该接口的类只要交由Spring容器管理的话,那么Spring就会回调该接口的方法,用于对BeanDefinition注册和修改的功能。

BeanFactoryPostProcessor定义如下:

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

3.2、注册BeanDefinition

使用这种方法,可以不用再spring容器内在创建一个类的<bean>标签

public class MyBeanFactoryProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {System.out.println("beandefinitionMap填充完毕后回调该方法");//1.注册一个beandefinition 创建一个RootBeanDefinition()对象RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();rootBeanDefinition.setBeanClassName("com.huanglei.Dao.Impl.processorImpl");//2.将beanFactory强转成DefaultListableBeanFactory类型DefaultListableBeanFactory beanFactory1 = (DefaultListableBeanFactory) beanFactory;beanFactory1.registerBeanDefinition("processor",rootBeanDefinition);}
} 
@Test
public void demo2(){ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");Object processor = classPathXmlApplicationContext.getBean("processor");System.out.println(processor);
} 

3.3、BeanDefinitionRegistryPostProcessor

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

public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {//创建一个RootBeanDefinition()对象RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();rootBeanDefinition.setBeanClassName("com.huanglei.Dao.Impl.processorImpl");//不需要强转就可以创建一个BeanbeanDefinitionRegistry.registerBeanDefinition("personDao",rootBeanDefinition);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {}
} 

3.4 完善实例化流程图

BeanFactoryPostProcessor在SpringBean的实例化过程中的体现

在这里插入图片描述

3.5、自定义@Component

要求:

  • 自定义@MyComponent注解,使用在类上;
  • 使用资料中提供好的包扫描器工具BaseClassScanUtils完成指定包的类扫描;
  • 自定义BeanFactoryPostProcessor完成注解@MyComponent的解析,解析后最终被Spring管理。

BaseClassScanUtils:

public class BaseClassScanUtils {//设置资源规则private static final String RESOURCE_PATTERN = "/**/*.class";public static Map<String, Class> scanMyComponentAnnotation(String basePackage) {//创建容器存储使用了指定注解的Bean字节码对象Map<String, Class> annotationClassMap = new HashMap<String, Class>();//spring工具类,可以获取指定路径下的全部类ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();try {String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +ClassUtils.convertClassNameToResourcePath(basePackage) + RESOURCE_PATTERN;Resource[] resources = resourcePatternResolver.getResources(pattern);//MetadataReader 的工厂类MetadataReaderFactory refractory = new CachingMetadataReaderFactory(resourcePatternResolver);for (Resource resource : resources) {//用于读取类信息MetadataReader reader = refractory.getMetadataReader(resource);//扫描到的classString classname = reader.getClassMetadata().getClassName();Class<?> clazz = Class.forName(classname);//判断是否属于指定的注解类型if(clazz.isAnnotationPresent(MyComponent.class)){//获得注解对象MyComponent annotation = clazz.getAnnotation(MyComponent.class);//获得属value属性值String beanName = annotation.value();//判断是否为""if(beanName!=null&&!beanName.equals("")){//存储到Map中去annotationClassMap.put(beanName,clazz);continue;}//如果没有为"",那就把当前类的类名作为beanNameannotationClassMap.put(clazz.getSimpleName(),clazz);}}} catch (Exception exception) {}return annotationClassMap;}public static void main(String[] args) {Map<String, Class> stringClassMap = scanMyComponentAnnotation("com.huanglei");System.out.println(stringClassMap);}
} 
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {String value();
} 
@MyComponent("One")
public class OneBean {
} 

四、Spring的Bean后处理器

4.1 概念和入门

Bean被实例化过后,在最后缓存到singletonObjects单例池之前,中间会进行Bean的初始化操作,例如:属性的赋值,初始化操作(init-method),其中包含着一个点BeanPostProcessor,这里被称为Bean后处理器。如果实现了这个接口,那么就会被Spring管理,然后Spring会自动调用

public class MyBeanPostProcesser implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println(beanName+"postProcessBeforeInitialization");return null;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println(beanName+"postProcessAfterInitialization");return null;}
}
  • postProcessBeforeInitialization方法和postProcessAfterInitialization方法需要进行手动创建,接口中实现的是null返回值的方法
  • 两者方法在bena创建之后执行,加入到singletonObjects之前执行

4.2 当中的一些调用方法的顺序

  1. 先执行bean的构造方法
  2. 执行before方法
  3. 执行InitializingBean接口中的afterPropertiesSet()方法
  4. 执行在xml文件中设置的Bean的init-method方法
  5. 执行after方法

执行操作如下
在这里插入图片描述

4.3 更加详细的实例化基本操作

BeanPostProcessor在 SpringBean的实例化过程中的体现
在这里插入图片描述

五、Spring的生命周期

5.1 概述

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

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

5.2 初始化阶段执行的步骤

由于Bean的初始化阶段的步骤比较复杂,所以着重研究Bean的初始化阶段
Spring Bean的初始化过程涉及如下几个过程:

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

5.3 初始化阶段注入属性信息封装

BeanDefinition 中有对当前Bean实体的注入信息通过属性propertyValues进行了存储
在这里插入图片描述

<bean id="userDao" class="com.huanglei.Dao.Impl.UserDaoImpl"></bean><bean id="userService" class="com.huanglei.service.Impl.UserServiceImpl"><property name="dao" ref="userDao"></property><property name="username" value="AAA"></property>
</bean> 

5.4、属性注入的三种情况

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

  • 注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;
  • 注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作
  • 注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)问题,下面会详细阐述解决方案。

5.4.1 单项注入的代码验证

public class UserServiceImpl implements UserService{private UserDao dao;private String username;public UserServiceImpl() {System.out.println("实例化UserService");}public UserServiceImpl(UserDao dao, String username) {this.dao = dao;this.username = username;}public void setDao(UserDao dao) {System.out.println("执行setDao方法");this.dao = dao;}public void setUsername(String username) {this.username = username;}
} 
public class UserDaoImpl implements UserDao{public UserDaoImpl() {System.out.println("实例化UserDao");}
} 

userDao在userService前面

<bean id="userDao" class="com.huanglei.Dao.Impl.UserDaoImpl"></bean><bean id="userService" class="com.huanglei.service.Impl.UserServiceImpl"><property name="dao" ref="userDao"></property><property name="username" value="AAA"></property>
</bean> 

执行顺序:

  1. 实例化UserDao
  2. 实例化UserService
  3. 执行setDao方法

userDao在userService后面

<bean id="userService" class="com.huanglei.service.Impl.UserServiceImpl"><property name="dao" ref="userDao"></property><property name="username" value="AAA"></property>
</bean><bean id="userDao" class="com.huanglei.Dao.Impl.UserDaoImpl"></bean>

总结:

就是说明如果包含了我要调用的Bean对象,有就调用,若无就先创建Bean对象

5.4.2 循环依赖概念及解决方案

多个实体之间相互依赖并形成闭环的情况就叫做 “循环依赖”,也叫做 “循环引用”

在这里插入图片描述

<bean id="userService" class="com.huanglei.service.Impl.UserServiceImpl"><property name="dao" ref="userDao"></property>
</bean><bean id="userDao" class="com.huanglei.Dao.Impl.UserDaoImpl"><property name="service" ref="userService"></property>
</bean> 
public class UserDaoImpl implements UserDao{private UserService service; public void setService(UserService service){this.service = service;}
}
public class UserServiceImpl implements UserService{private UserDao dao;public void setDao(UserDao dao) {this.dao = dao;}
} 

可以利用三级缓存来
在这里插入图片描述

5.4.3 三级缓存的设计原理

Spring提供了三级缓存存储完整Bean实例半成品Bean实例,用于解决循环引用问题
在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map:

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);
}

5.5 循环依赖源码流程剖析

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

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

5.6 Aware接口

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

Aware接口回调方法作用
ServletContextAwaresetServletContext(ServletContext context)Spring框架回调方法注入ServletContext对象,web环境下才生效
BeanFactoryAwaresetBeanFactory(BeanFactory factory)Spring框架回调方法注入beanFactory对象
BeanNameAwaresetBeanName(String beanName)Spring框架回调方法注入当前Bean在容器中的beanName
ApplicationContextAwaresetApplicationContext(ApplicationContext applicationContext)Spring框架回调方法注入applicationContext对象

六、IoC容器实例化Bean完整流程图展示

在这里插入图片描述

七、Spring xml方式整和第三方框架

  • xml整合第三方框架有两种整合方案:
    • 不需要自定义名空间,不需要使用Spring的配置文件配置第三方框架本身内容,例如: MyBatis;
    • 需要引入第三方框架命名空间,需要使用Spring的配置文件配置第三方框架本身内容,例如:Dubbo。

7.1 Mybatis整合Spring实现

Spring整合MyBatis,之前已经在Spring中简单的配置了SqlSessionFactory,但是这不是正规的整合方式,MyBatis提供了mybatis-spring.jar专门用于两大框架的整合。
Spring整合MyBatis的步骤如下:

  1. ==导入MyBatis整合Spring的相关坐标; ==
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><!--注意版本,因为版本过低的原因在这里卡了很久!!!--><version>3.0.1</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.25.RELEASE</version>
</dependency> 
  1. 编写Mapper和Mapper.xml;
  2. 配置SqlSessionFactoryBean和MapperScannerConfigurer;
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://localhost:3306/itheima"></property><property name="username" value="root"></property><property name="password" value="123456"></property>
</bean>
<!--配置SqlSessionFactoryBean,作用将SqlSessionFactory存储到spring容器-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"></property>
</bean>
<!--MapperScannerConfigurer,作用扫描指定的包,产生Mapper对象存储到Spring容器-->
<bean  class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.huanglei.mapper"></property>
</bean><bean id="userService" class="com.huanglei.service.Impl.UserServiceImpl"><property name="carMapper" ref="carMapper"></property>
</bean>  
  1. 编写测试代码

7.2、MyBatis整合Spring源码解析

整合包里提供了一个SqlSessionFactoryBean和一个扫描Mapper的配置对象,SqlSessionFactoryBean一旦被实例化,就开始扫描Mapper并通过动态代理产生Mapper的实现类存储到Spring容器中。相关的有如下四个类:

  • sqlSessionFactoryBean:需要进行配置,用于提供SqlSessionFactory;
  • MapperScannerConfigurer:"需要进行配置,用于扫描指定mapper注册BeanDefinition;
  • MapperFactoryBean: Mapper的FactoryBean,获得指定Mapper时调用getObject方法;
  • ClassPathMapperScanner: definition.setAutowireMode(2)修改了自动注入状态,所以MapperFactoryBean中的setSqlSessionFactory会自动注入进去。

7.3 加载外部properties文件

Spring整合其他组件时就不像MyBatis这么简单了,例如Dubbo框架在于Spring进行整合时,要使用Dubbo提供的命名空间的扩展方式,自定义了一些Dubbo的标签

<?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:dubbo="http://dubbo.apache.org/schema/dubbo"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://dubbo.apache.org/schema/dubbohttp://dubbo.apache.org/schema/dubbo/dubbo.xsd"><!-- 配置Dubbo应用信息 --><dubbo:application name="your-application-name" /><!-- 配置注册中心 --><dubbo:registry address="zookeeper://127.0.0.1:2181" /><!-- 配置服务提供者 --><dubbo:protocol name="dubbo" port="20880" /><dubbo:service interface="com.example.YourServiceInterface" ref="yourServiceBean" /><!-- 配置其他Bean --><!-- 消费者配置 --><dubbo:consumer check="false" timeout="1000" retries="0"/>
</beans> 

通过配置context文件来加载外部properties文件

<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--通过context加载properties文件--><context:property-placeholder location="classpath:jdbc.properties"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!--配置SqlSessionFactoryBean,作用将SqlSessionFactory存储到spring容器--><bean class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"></property></bean><!--MapperScannerConfigurer,作用扫描指定的包,产生Mapper对象存储到Spring容器--><bean  class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.huanglei.mapper"></property></bean><bean id="userService" class="com.huamglei.service.Impl.UserServiceImpl"><property name="carMapper" ref="carMapper"></property></bean>
</beans> 

7.4、自定义空间步骤

  • 将自定义标签的约束与物理约束文件与网络约束名称的约束以键值对形式存储到一个spring.schemas文件里,该文件存储在类加载路径的META-INF里,Spring会自动加载到;
  • 将自定义命名空间的名称与自定义命名空间的处理器映射关系以键值对形式存在到一个叫spring.handlers文件里,该文件存储在类加载路径的 META-INF里,Spring会自动加载到;
  • 准备好NamespaceHandler,如果命名空间只有一个标签,那么直接在parse方法中进行解析即可,一般解析结果就是注册该标签对应的BeanDefinition。如果命名空间里有多个标签,那么可以在init方法中为每个标签都注册一个BeanDefinitionParser,在执行NamespaceHandler的parse方法时在分流给不同的
    BeanDefinitionParser进行解析(重写doParse方法即可)。

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

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

相关文章

Dreambooth工作原理

什么是Dreambooth 中文名&#xff1a;梦想亭。 Dreambooth 由 Google 研究团队于 2022 年发布&#xff0c;是一种通过向模型注入自定义主题来微调扩散模型&#xff08;如稳定扩散&#xff09;的技术。 所谓自定义主体&#xff0c;就是一张照片&#xff0c;但是照片主体要鲜明…

idea启动vue项目:Error:0308010C:digital envelope routines::unsupported

此问题是因为Node.js的版本原因&#xff0c;此处安装的Node.js是最新长期维护版: 18.16.0 (includes npm 9.5.1) 有两种解决办法&#xff1a; #1、方法一 重新安装低版本的node.js#2、方法二 在package.json文件中进行配置【此种方法较简单】介绍一下第二种方法&#xff1a; …

win32汇编-使用子程序

当程序中相同功能的一段代码用得比较频繁时&#xff0c;可以将它分离出来写成一个子程序&#xff0c;在主程序中用call指令来调用它。这样可以不用重复写相同的代码&#xff0c; 仅仅用call指令就可以完成多次同样的工作了。Win 32汇编中的子程序也采用堆栈来传递参数&#xff…

Python学习-----Day09

一、利用装饰器来获取函数运行的时间、 #导入time模块 import timedef decorated(fn):def inner():#time.time获取函数执行的时间a time.time() # func开始的时间fn()b time.time() # func结束的时间print(f"{fn.__name__}程序运行的总数时间:{b - a}秒")return…

Win系统VMware虚拟机安装配置(二)

系统的安装得分两个步骤&#xff0c;第一步得配置一台电脑&#xff0c;选配 cpu&#xff0c;内存&#xff0c;磁盘&#xff0c;网卡等硬 件。第二步才是安装系统。 一、配置电脑 1、 进入 VMware 双击 VMware 图标&#xff0c;看到如下界面。 2、 自定义新的虚拟机 3、…

地铁大数据客流分析系统 设计与实现 计算机竞赛

文章目录 1 前言1.1 实现目的 2 数据集2.2 数据集概况2.3 数据字段 3 实现效果3.1 地铁数据整体概况3.2 平均指标3.3 地铁2018年9月开通运营的线路3.4 客流量相关统计3.4.1 线路客流量排行3.4.2 站点客流量排行3.4.3 入站客流排行3.4.4 整体客流随时间变化趋势3.4.5 不同线路客…

SNAP对Sentinel-1预处理

SNAP对Sentinel-1预处理 一、导入数据 二、轨道校正 点击run开始处理 三、噪声去除 打开S-1 Thermal Noise Removal工具 如果选中了VH&#xff0c;就只会输出一个VH极化结果 四、辐射定标 Run 五、滤波处理 六、地形校正 这边的dem需要自己下载 dem下载地址 如果一格…

跨境电子商城源代码定制网站搭建(商品采集,多货币,多语言)

欢迎来到全新的跨境电子商城源代码定制网站搭建!这是一个集商品采集、多币种和多语言于一身的创新平台&#xff0c;为您的跨境电商事业提供了前所未有的便利和机会! 一、精选全球商品&#xff0c;一站式采集 在跨境电子商务的时代&#xff0c;我们深谙选择高质量商品的重要性。…

Python 框架学习 Django篇 (三) 链接数据库

只要你是做后端开发的&#xff0c;那么就离不开各种数据库&#xff0c;Django框架对各种数据库都非常友好&#xff0c;比如常见的PostgreSQL、MySQL、SQLite、Oracle&#xff0c;django都对他们提供了统一调用api&#xff0c;我们这里主要使用mysql数据库作为演示 一、ORM机制 …

【开源分享】基于Html开发的房贷计算器,模仿新浪财经

房贷计算器是一种房贷计算的在线计算Web应用&#xff0c;按用户选择的贷款类型、贷款金额、期限、利率可计算得出每月月供参考、支付利息、还款总额这些信息。本文模仿新浪财经开发的房贷计算器。 作品预览 https://fangdai.gitapp.cn 源码地址 https://github.com/geeeeeee…

5、使用 pgAdmin4 图形化创建和管理 PostgreSQL 数据库

通过上几篇文章我们讲解了如何安装 PostgreSQL 数据库软件和 pgAdmin4 图形化管理工具。 今天我们继续学习如何通过 pgAdmin4 管理工具图形化创建和管理 PostgreSQL 数据库。 一、PostgreSQL的基本工作方式 在学习如何使用PostgreSQL创建数据库之前&#xff0c;我们需要了解一…

vue3+element-plus 封装高度搜索组件,支持多种类型

目录 一、应用场景 二、开发流程 三、详细开发流程 1.新建文件 2.开始步骤 3.详细代码 (1).index.vue (2).搜索组件 (3).单个搜索组件 总结 一、应用场景 一般很多网站&#xff0c;有很多数据列表&#xff0c;基本都要做搜索的功能&#xff0c;如果涉及很多页面&…

【CMN】Components组件汇总

CMN 700由各种类型的设备组成&#xff0c;包括路由器模块、CHI节点和网桥。所需要的组件取决于系统的需求&#xff0c;有些组件是可选的&#xff0c;或者只有在满足某些需求时才会使用。CMN 700可以集成到一个完整的SoC系统中&#xff0c;该系统还包括其他这里未描述到的设备。…

金融机器学习方法:K-均值算法

目录 1.算法介绍 2.算法原理 3.python实现示例 1.算法介绍 K均值聚类算法是机器学习和数据分析中常用的无监督学习方法之一&#xff0c;主要用于数据的分类。它的目标是将数据划分为几个独特的、互不重叠的子集或“集群”&#xff0c;以使得同一集群内的数据点彼此相似&…

Leetcode刷题详解——四数之和

1. 题目链接&#xff1a;四数之和 2. 题目描述&#xff1a; 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&#xff0…

stm32 cubeide 闪退 显示self upgrade failed

更新或安装新版cubeide时&#xff0c;可能会出现打开后一段时间直接闪退&#xff0c;显示如下图。此时怎么折腾cubeide都是没用的。应该去升级stm32 cubemx。记得打开cubemx时选择用管理员身份打开&#xff0c;升级完成后重新开打。然后尝试打开cubdeide&#xff0c;如果继续报…

接口测试面试题整理​​​​​​​

HTTP, HTTPS协议 什么是DNSHTTP协议怎么抓取HTTPS协议说出请求接口中常见的返回状态码http协议请求方式HTTP和HTTPS协议区别HTTP和HTTPS实现机有什么不同POST和GET的区别HTTP请求报文与响应报文格式什么是Http协议无状态协议?怎么解决HTTP协议无状态协议常见的POST提交数据方…

《向量数据库指南》——向量数据库是小题大作的方案?

假设大语言模型需要 10 秒钟才能生成一条结果,即需要存储的单条新记忆。那么我们获得 10 万条记忆的时间周期将为:100000 x 10 秒 = 1000000 秒——约等于 11.57 天。而即使我们用最简单的暴力算法(Numpy 的点查询),整个过程也只需要几秒钟时间,完全不值得进行优化!也就…

微信小程序会议OA系统

Flex弹性布局 Flex弹性布局是一种 CSS3 的布局模式&#xff0c;也叫Flexbox。它可以让容器中的元素按一定比例自动分配空间&#xff0c;使得它们在不同宽度、高度等情况下仍能保持整齐和密集不间隙地排列。 在使用Flexbox弹性布局时&#xff0c;首先需要创建一个容器和若干个…

VSCode搭建ESP32 ESP-IDF开发环境-Windows

陈拓 2023/10/09-2023/10/14 1. 安装Windows系统下的ESP32 ESP-IDF开发环境 见《Windows系统安装ESP32 ESP-IDF开发环境》 Windows系统安装ESP32 ESP-IDF开发环境-CSDN博客Windows系统安装ESP32 ESP-IDF开发环境。https://blog.csdn.net/chentuo2000/article/details/1339225…