Spring注解方式整合Mybatis

📅 发布时间:2026/7/7 8:07:19 👁️ 浏览次数:
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创建数据源且注册成为BeanBeanpublicDataSourcedataSource(){DruidDataSourcedataSourcenewDruidDataSource();dataSource.setDriverClassName(driverClassName);dataSource.setUsername(username);dataSource.setPassword(password);dataSource.setUrl(url);returndataSource;}2.3创建SqlSessionFactoryBean且注册成为BeanpublicSqlSessionFactoryBeansqlSessionFactoryBean(DataSourcedataSource){// SqlSessionFactoryBean sqlSessionFactoryBean sqlSessionFactoryBean(dataSource);SqlSessionFactoryBeansqlSessionFactoryBeannewSqlSessionFactoryBean();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-packagecom.itheima/配置注解扫描只有一个时直接写有多个写成数组ComponentScan(com.itheima)//context:property-placeholder locationclasspath:jdbc.properties/引入配置文件PropertySource(classpath:jdbc.properties)// import resource导入其他配置类Import(OtherBean3.class)//下面是接口扫描// bean classorg.mybatis.spring.mapper.MapperScannerConfigurer//!-- 指定要扫描的包--// property namebasePackage valuecom.itheima.mapper/property// /beanMapperScan(com.itheima.mapper)publicclassSpringConfig2{Value(${jdbc.driver})StringdriverClassName;Value(${jdbc.url})Stringurl;Value(${jdbc.username})Stringusername;Value(${jdbc.password})Stringpassword;// bean iddataSource classcom.alibaba.druid.pool.DruidDataSource// property namedriverClassName value${jdbc.driver}/// property nameurl value${jdbc.url}/// property nameusername value${jdbc.username}/// property namepassword value${jdbc.password}/// /beanBeanpublicDataSourcedataSource(){DruidDataSourcedataSourcenewDruidDataSource();dataSource.setDriverClassName(driverClassName);dataSource.setUsername(username);dataSource.setPassword(password);dataSource.setUrl(url);returndataSource;}// bean classorg.mybatis.spring.SqlSessionFactoryBean//!-- 最终是要得到由Sqlsession得到Conection需要数据源属性--// property namedataSource refdataSource/property// /beanBean// 在这里是通过类型进行注入的publicSqlSessionFactoryBeansqlSessionFactoryBean(DataSourcedataSource){// SqlSessionFactoryBean sqlSessionFactoryBean sqlSessionFactoryBean(dataSource);SqlSessionFactoryBeansqlSessionFactoryBeannewSqlSessionFactoryBean();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})DocumentedImport({MapperScannerRegistrar.class})Repeatable(MapperScans.class)publicinterfaceMapperScan{String[]value()default{};String[]basePackages()default{};Class?[]basePackageClasses()default{};Class?extendsBeanNameGeneratornameGenerator()defaultBeanNameGenerator.class;Class?extendsAnnotationannotationClass()defaultAnnotation.class;Class?markerInterface()defaultClass.class;StringsqlSessionTemplateRef()default;StringsqlSessionFactoryRef()default;Class?extendsMapperFactoryBeanfactoryBean()defaultMapperFactoryBean.class;StringlazyInitialization()default;}我们发现它导入了一个MapperScannerRegistrar继续跟进voidregisterBeanDefinitions(AnnotationMetadataannoMeta,AnnotationAttributesannoAttrs,BeanDefinitionRegistryregistry,StringbeanName){BeanDefinitionBuilderbuilderBeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);builder.addPropertyValue(processPropertyPlaceHolders,true);Class?extendsAnnotationannotationClassannoAttrs.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();}ClassPathMapperScannerscannernewClassPathMapperScanner(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方法protectedSetBeanDefinitionHolderdoScan(String...basePackages){Assert.notEmpty(basePackages,At least one base package must be specified);SetBeanDefinitionHolderbeanDefinitionsnewLinkedHashSet();for(StringbasePackage:basePackages){for(BeanDefinitioncandidate:this.findCandidateComponents(basePackage)){ScopeMetadatascopeMetadatathis.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());StringbeanNamethis.beanNameGenerator.generateBeanName(candidate,this.registry);if(candidateinstanceofAbstractBeanDefinition){this.postProcessBeanDefinition((AbstractBeanDefinition)candidate,beanName);}if(candidateinstanceofAnnotatedBeanDefinition){AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate);}if(this.checkCandidate(beanName,candidate)){BeanDefinitionHolderdefinitionHoldernewBeanDefinitionHolder(candidate,beanName);definitionHolderAnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,definitionHolder,this.registry);beanDefinitions.add(definitionHolder);this.registerBeanDefinition(definitionHolder,this.registry);}}}returnbeanDefinitions;}同样是先注册BeanDefinitionHolder然后注册BeanDefinition放到BeanDefinitionMap中核心代码都是完全一样的。