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

Spring注解方式整合Mybatis

Spring注解方式整合Mybatis

一、概述

二、实验

2.1注入数据源的各属性

先引入配置文件:

@PropertySource("classpath:jdbc.properties")

再是注入属性:

@Value("${jdbc.driver}")StringdriverClassName;@Value("${jdbc.url}")Stringurl;@Value("${jdbc.username}")Stringusername;@Value("${jdbc.password}")Stringpassword;

2.2创建数据源且注册成为Bean

@BeanpublicDataSourcedataSource(){DruidDataSourcedataSource=newDruidDataSource();dataSource.setDriverClassName(driverClassName);dataSource.setUsername(username);dataSource.setPassword(password);dataSource.setUrl(url);returndataSource;}

2.3创建SqlSessionFactoryBean且注册成为Bean

publicSqlSessionFactoryBeansqlSessionFactoryBean(DataSourcedataSource){// SqlSessionFactoryBean sqlSessionFactoryBean = sqlSessionFactoryBean(dataSource);SqlSessionFactoryBeansqlSessionFactoryBean=newSqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);returnsqlSessionFactoryBean;}

2.4设置接口扫描

@ComponentScan("com.itheima")

总的配置类(里面含有xml配置的对照):

packagecom.itheima.config;importcom.alibaba.druid.pool.DruidDataSource;importcom.itheima.beans.OtherBean3;importorg.mybatis.spring.SqlSessionFactoryBean;importorg.mybatis.spring.annotation.MapperScan;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.*;importjavax.sql.DataSource;//这个注解代表:这是一个核心配置类;这个类交给了Spring容器管理(就是相当于替换Spring配置文件)@Configuration//<context:component-scan base-package="com.itheima"/>:配置注解扫描,只有一个时直接写,有多个写成数组@ComponentScan("com.itheima")//<context:property-placeholder location="classpath:jdbc.properties"/>:引入配置文件@PropertySource("classpath:jdbc.properties")// <import resource="":导入其他配置类@Import(OtherBean3.class)//下面是接口扫描// <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">//<!-- 指定要扫描的包-->// <property name="basePackage" value="com.itheima.mapper"></property>// </bean>@MapperScan("com.itheima.mapper")publicclassSpringConfig2{@Value("${jdbc.driver}")StringdriverClassName;@Value("${jdbc.url}")Stringurl;@Value("${jdbc.username}")Stringusername;@Value("${jdbc.password}")Stringpassword;// <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">// <property name="driverClassName" value="${jdbc.driver}"/>// <property name="url" value="${jdbc.url}"/>// <property name="username" value="${jdbc.username}"/>// <property name="password" value="${jdbc.password}"/>// </bean>@BeanpublicDataSourcedataSource(){DruidDataSourcedataSource=newDruidDataSource();dataSource.setDriverClassName(driverClassName);dataSource.setUsername(username);dataSource.setPassword(password);dataSource.setUrl(url);returndataSource;}// <bean class="org.mybatis.spring.SqlSessionFactoryBean">//<!-- 最终是要得到由Sqlsession得到Conection,需要数据源属性-->// <property name="dataSource" ref="dataSource"></property>// </bean>@Bean// 在这里是通过类型进行注入的publicSqlSessionFactoryBeansqlSessionFactoryBean(DataSourcedataSource){// SqlSessionFactoryBean sqlSessionFactoryBean = sqlSessionFactoryBean(dataSource);SqlSessionFactoryBeansqlSessionFactoryBean=newSqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);returnsqlSessionFactoryBean;}}

结果:

三、原理剖析

先是进入@MapperScan看看里面:

@MapperScan("com.itheima.mapper")
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//packageorg.mybatis.spring.annotation;importjava.lang.annotation.Annotation;importjava.lang.annotation.Documented;importjava.lang.annotation.ElementType;importjava.lang.annotation.Repeatable;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;importorg.mybatis.spring.mapper.MapperFactoryBean;importorg.springframework.beans.factory.support.BeanNameGenerator;importorg.springframework.context.annotation.Import;@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE})@Documented@Import({MapperScannerRegistrar.class})@Repeatable(MapperScans.class)public@interfaceMapperScan{String[]value()default{};String[]basePackages()default{};Class<?>[]basePackageClasses()default{};Class<?extendsBeanNameGenerator>nameGenerator()defaultBeanNameGenerator.class;Class<?extendsAnnotation>annotationClass()defaultAnnotation.class;Class<?>markerInterface()defaultClass.class;StringsqlSessionTemplateRef()default"";StringsqlSessionFactoryRef()default"";Class<?extendsMapperFactoryBean>factoryBean()defaultMapperFactoryBean.class;StringlazyInitialization()default"";}

我们发现它导入了一个MapperScannerRegistrar,继续跟进:

voidregisterBeanDefinitions(AnnotationMetadataannoMeta,AnnotationAttributesannoAttrs,BeanDefinitionRegistryregistry,StringbeanName){BeanDefinitionBuilderbuilder=BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);builder.addPropertyValue("processPropertyPlaceHolders",true);Class<?extendsAnnotation>annotationClass=annoAttrs.getClass("annotationClass");if(!Annotation.class.equals(annotationClass)){builder.addPropertyValue("annotationClass",annotationClass);}

然后注册了一个MapperScannerConfigurer.class,是不是好熟悉啊?其实到这就是与xml配置一样了,都是通过MapperScannerConfigurer.class来注册,只不过注解方式还导入了一个MapperScannerRegistrar,再由MapperScannerRegistrar注册MapperScannerConfigurer.class,而xml方式是直接配置MapperScannerConfigurer.class。当然我们也还可以发现BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);,BeanDefinitionBuilder也是可以注册BeanDefinition的,以前我们都是通过new RootBeanDefinition(),然后由BeanDefinitionRegistry注册,现在又发现一种方式。

publicvoidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistryregistry){if(this.processPropertyPlaceHolders){this.processPropertyPlaceHolders();}ClassPathMapperScannerscanner=newClassPathMapperScanner(registry);scanner.setAddToConfig(this.addToConfig);scanner.setAnnotationClass(this.annotationClass);scanner.setMarkerInterface(this.markerInterface);scanner.setSqlSessionFactory(this.sqlSessionFactory);scanner.setSqlSessionTemplate(this.sqlSessionTemplate);scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);scanner.setResourceLoader(this.applicationContext);scanner.setBeanNameGenerator(this.nameGenerator);scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);if(StringUtils.hasText(this.lazyInitialization)){scanner.setLazyInitialization(Boolean.valueOf(this.lazyInitialization));}scanner.registerFilters();scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage,",; \t\n"));}

看吧,依然是调用postProcessBeanDefinitionRegistry的scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, “,; \t\n”));,然后进入scan方法:

protectedSet<BeanDefinitionHolder>doScan(String...basePackages){Assert.notEmpty(basePackages,"At least one base package must be specified");Set<BeanDefinitionHolder>beanDefinitions=newLinkedHashSet();for(StringbasePackage:basePackages){for(BeanDefinitioncandidate:this.findCandidateComponents(basePackage)){ScopeMetadatascopeMetadata=this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());StringbeanName=this.beanNameGenerator.generateBeanName(candidate,this.registry);if(candidateinstanceofAbstractBeanDefinition){this.postProcessBeanDefinition((AbstractBeanDefinition)candidate,beanName);}if(candidateinstanceofAnnotatedBeanDefinition){AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate);}if(this.checkCandidate(beanName,candidate)){BeanDefinitionHolderdefinitionHolder=newBeanDefinitionHolder(candidate,beanName);definitionHolder=AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,definitionHolder,this.registry);beanDefinitions.add(definitionHolder);this.registerBeanDefinition(definitionHolder,this.registry);}}}returnbeanDefinitions;}

同样是先注册BeanDefinitionHolder,然后注册BeanDefinition放到BeanDefinitionMap中,核心代码都是完全一样的。

http://www.jsqmd.com/news/387299/

相关文章:

  • @Import整合第三方框架原理
  • 使用 Google Earth Engine 快速导出 Copernicus GLO-30 和 ASTER GDEM 高程数据
  • 现代控制理论(1)—— 概论
  • 05]delphi10.3中richedit中删除线
  • 关于学习技术栈的思考
  • 实测才敢推!自考必备的降AI率平台 —— 千笔·专业降AIGC智能体
  • 【Python】从0到1完成轻量级接口测试工具:基于Python+FastAPI+Pytest
  • 适用于室内和室外的集成式LED PCBA解决方案
  • 基础入门 Flutter for OpenHarmony:battery_plus 电池状态监控详解
  • ArcPy 脚本:批量生成郑州市 1990-2019 年空间分析结果(核密度、热点、平均中心、标准差椭圆)
  • 这次终于选对!圈粉无数的一键生成论文工具 —— 千笔AI
  • 2026年阿里巴巴/1688平台开户代运营权威评测:深圳昊客网络 脱颖而出 - 深圳昊客网络
  • WAC集团推出WAC建筑品牌,以先进、技术驱动的解决方案赋能照明设计师
  • 使用 ArcPy 批量裁剪建筑面矢量:根据城区边界提取城市建筑数据
  • 2026最新!千笔,专科生专属降AI神器
  • 毕业论文神器!千笔,备受喜爱的AI论文平台
  • Windows Powershell 打开即闪退 | Windows PowerShell 内部错误。加载托管的 Windows Powershell 失败,返回错误 80131018。
  • 强烈安利!千笔,口碑爆棚的一键生成论文工具
  • 服务器运维(四十)日服务器linux-ps分析工具—东方仙盟
  • 用 Python 批量提取 1990–2019 年高层建筑并按城市导出 Shapefile
  • delphi10.3中UpDown1使用
  • 【信息科学与工程学】【智能交通】第五篇 自动驾驶02
  • 看完就会:AI论文平台,千笔 VS 灵感风暴AI,本科生写作神器!
  • vue3+nodejs校园活动管理系统的设计与实现
  • 人工智能之核心基础 机器学习 第十八章 经典实战项目 - 实践
  • vue3+nodejs气象数据共享平台 天气预报数据共享系统
  • axure: 下拉菜单
  • 香港中巴租赁市场分析:2026口碑租赁公司哪家强?大巴租车/汽车租赁/跨境租车/班车租赁/跨境包车,租赁公司推荐 - 品牌推荐师
  • vue3+nodejs的运动减肥计划系统的设计与实现
  • 洋葱好坏腐烂检测数据集VOC+YOLO格式1015张3类别