IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 关于bean的populateBean中获取ApplicationContext的源码过程 -> 正文阅读

[Java知识库]关于bean的populateBean中获取ApplicationContext的源码过程

前言

“风吹起如花般破碎的流年,而你的笑容摇晃摇晃,成为我命途中最美的点缀,看天,看雪,看季节深深的暗影。”- - 张爱玲

一、SSA

  • 我们都知道spring-framework的框架默认对bean的管理都是单例的,如果一个单例的类A里需要调用一个原型对象B,如果在A中@Autowired注入了B这个原型对象,那么从A中每次get到的B都是同一个(下面会证明这个现象),这里就发生了错误。
  • 此时我们可以使用在A中注入@Autowired ApplicationContext或者实现ApplicationContextAware接口拿到ApplicationContext,再从ApplicationContext中获取想要的bean。spring启动完成了,经过遍历spring的单例池并没有发现ApplicationContext这个对象。那ApplicationContext从哪里来又是怎样被@Autowired注解注入bean的呢,接下面从spring源代码看看。

二、GTTP

1.看下基本类,模拟的mybatis扩展spring接口实现查询

  • 这里创建的CustomSqlsession customSqlsession = new CustomSqlsession();其实就是上一代理的获取传入接口的代理对象的类
  • mapperInterface就是传入的接口,这里模拟的传入的就是IndexDao;
  • 这里提供了setMapperInterface是个set方法,意味着后面mybatis根据spring提供的接口规则将自己的代理对象注入spring的时候,spring通过这个set方法给mapperInterface设置值。
  • CustomFactoryBean这个类里也可以提供有参构造方法,spring根据有参构造填充mapperInterface这个属性。
package com.cusmybatis.example3.factorybean;

import com.cusmybatis.example3.sqlSession.CustomSqlsession;
import org.springframework.beans.factory.FactoryBean;

/**
 * @author xiansheng lv
 * @date 2021/6/15 11:20
 * 目的让mybati代理的这个对象注入spring.
 * 即此处 生成代理对象必须让这个CustomFactoryBean  的bean生效
 * 1, xml可以配置注册这个CustomFactoryBean类并且给他的属性指定需要代理的对象,
 * 但是这个做法很局限,代理的对象多个无法手动一一写出来
 * 2,注解的形式将需要被代理的对象注入CustomFactoryBean里
 * 这会导致CustomFactoryBean一并走spring实例化对象的周期,也就是出现代理两次,直接出错
 * 3,尝试添加这个代理对象的BeanDefintion  可行.
 *
 */
public class CustomFactoryBean implements FactoryBean {

	/*这个类是动态给的*/
	Class mapperInterface;

	@Override
	public Object getObject() {
		CustomSqlsession customSqlsession = new CustomSqlsession();
		/*代理类获取对象*/
		/*mabatis动态代理出来的类*/
		Object mapper = customSqlsession.getMapper(mapperInterface);
		/*此处实现FactoryBean返回的mapper对象会存到spring容器当中*/
		return mapper;
	}

	@Override
	public Class<?> getObjectType() {
		return mapperInterface;
	}

	/*提供一个set方法,属性注入的时候使用这个方法给
	* 相较于构造方法而写的这个
	* */
	public void setMapperInterface(Class mapperInterface) {
		this.mapperInterface = mapperInterface;
	}
}

  • 在spring实例化周期的过程中,这里实现了ImportBeanDefinitionRegistrar接口,来注入mybatis代理的对象
  • 很明显你要注入mybatis代理对象必须按照spring提供的规矩来。也就是上面的(implements FactoryBean)实现FactoryBean接口,用BeanDefinitionBuilder构建mybatis的beanDefinition模型,将构建好的模型注册(registry.registerBeanDefinition)进去。
  • 有一个大家很熟悉的后置处理器(implements BeanFactoryPostProcessor ),顾名思义,实现这个后置处理器可以根据实现类提供的beanFactory拿到你想要的beanDefinition,但这个是后置处理器,是已经走完注册BeanDefinition流程的接口,所以扩展这个接口只能获取不能在这里注册BeanDefinition;
  • beanDefinition也提供了相应的属性设置的方法可以是.getPropertyValues().add(“mapperInterface”, IndexDao.class)来设置
package com.cusmybatis.example3.bd;

import com.cusmybatis.example3.dao.IndexDao;
import com.cusmybatis.example3.factorybean.CustomFactoryBean;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @author xiansheng lv
 * @date 2021/6/15 14:00
 * spring里这个注册beanDefinition的类生效不能是Component注解
 * 而是在配置类加上Import注解指定
 */
public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
		MergedAnnotations annotations = importingClassMetadata.getAnnotations();
		/*
		 *真实的情况是根据这里的annotations注解扫描获取到所有的dao
		 * 循环遍历 给它做代理注册到spring里
		 * 这里只获取了一个IndexDao注册进去
		 * */
		/*构建传入class的beanDefinition信息*/
		BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(CustomFactoryBean.class);
		AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
		/*这里通过属性注入的方式 也可以是
		* beanDefinition.getConstructorArgumentValues().addArgumentValues();
		* 对应的CustomFactoryBean里也需要提供对应的有参构造
		* */
		beanDefinition.getPropertyValues().add("mapperInterface", IndexDao.class);

		/*注册beanDefinition*/
		registry.registerBeanDefinition("indexDao", beanDefinition);
	}
}

下面是模拟@MapperScan注解的自定义注解@CustomScan用到的所有的类。

可以看到成功从容器中获取到IndexDao,并用它的代理对象执行了数据库查询。

2.查看mybatis扩展spring源码

可以看到,用Mybatis扩展spring的注解MapperScan来查询数据库依然可以,且代理对象变成了org.apache.ibatis.binding.MapperProxy@7e5c856f。接下来就看下源代码中的处理过程是否和上面模拟的一样。


  • 可以看到@MapperScan(“com.cusmybatis.example3.dao”)中 @MapperScan注解上同样是@Import注解 导入了一个MapperScannerRegistrar.class类,这个类和笔者的@CustomScan注解导入的CustomImportBeanDefinitionRegistrar类一样实现了ImportBeanDefinitionRegistrar接口重写了registerBeanDefinitions方法。

  • 可以看到这个MapperScannerRegistrar类的BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);这行逻辑代码第一行就构建了BeanDefinitionBuilder ,当然这里的MapperScannerConfigurer顾名思义扫描了所有的指定包下的dao;除了第一行下面的逻辑都是 做 builder.addPropertyValue(),这个和笔者的

这里的作用类似,是给BeanDefinition配置属性,这个属性是属于BeanDefinition的。最后一行 registry.registerBeanDefinition(beanName, builder.getBeanDefinition())将构建好的就是BeanDefinition注册到spring。接下来就重点看下MapperScannerConfigurer扫描干的事。

  • 可以看到在MapperScannerConfigurer类的扫描过程中,在指定的com.cusmybatis.example3.dao包下扫描出了IndexDao。理论上扫描出来后应该是给它的BeanDefinition填充属性,这个属性是代理类需要的属性。

  • 上图可以看到,扫描出来的beanDefinitions只有一个也就是MyBatis mapper 有一个IndexDao。但是在for (BeanDefinitionHolder holder : beanDefinitions) { 会循环遍历它,遍历的操作里有
    definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
    definition.setBeanClass(this.mapperFactoryBeanClass);
    两行代码,查看属性知道beanClassName的值就是com.cusmybatis.example3.dao.IndexDao,也就是definition将来要实例化出来的对象的Constructor的参数是com.cusmybatis.example3.dao.IndexDao,实例化出来的对象是mapperFactoryBeanClass,这个是mybaits的提供的类实现了implements FactoryBean接口

作用就和上图的意思一样。当然理解上面的过程前提是对spring的beanDefinition有一定的理解。


总结

总结就是:

  • mybaits自个儿单独使用是。
  • 但是要接入spring,
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-13 17:19:45  更:2021-07-13 17:21:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/18 17:52:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码