07.Spring配置非自定义Bean,以Mybatis为例

本文介绍了如何在Spring中配置非自定义的MybatisSqlSessionFactory,包括引入依赖、XML配置步骤和实例代码,确保第三方jar包中的Bean通过Spring管理并成功注入。

简介

在前几章节中,通过 xml 方式配置的Bean,都是我们自己定义的,例如:UserDaoImpl,UserServiceImpl等。然而,在实际开发中有些功能类并不是我们自己定义的,是使用的第三方jar包中的。如果想让这些Bean通过Spring进行管理,也需要对其进行配置。

1. 前言

配置非自定义的Bean需要考虑如下两个问题:

被配置的Bean的实例化方式是什么?无参构造、有参构造、静态工厂方式还是实例工厂方式。
被配置的Bean是否需要注入必要属性

2. 示例(Mybatis)

applicationContext.xml的配置步骤和其他部分代码请参考 03.Spring的ApplicationContext
bean的实例化配置和依赖注入详解请参考 05.Spring的Bean配置详解

2.1 配置MyBatis的SqlSessionFactory交由Spring管理

pom.xml 导入MyBatis的相关坐标:

<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.49</version>
</dependency>
<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis</artifactId>
   <version>3.5.5</version>
</dependency>
<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis-spring</artifactId>
   <version>2.0.5</version>
</dependency>

MyBatis原始获得SqlSessionFactory的方式:

//加载mybatis核心配置文件,使用Spring静态工厂方式
InputStream in = Resources.getResourceAsStream(“mybatis-conifg.xml”);
//创建SqlSessionFactoryBuilder对象,使用Spring无参构造方式
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//调用SqlSessionFactoryBuilder的build方法,使用Spring实例工厂方式
SqlSessionFactory sqlSessionFactory = builder.build(in);

mybatis-conifg.xml 路径和具体内容:

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.8.160:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <package name="com.test.mapper"></package>
    </mappers>
</configuration>

SqlSessionFactory交由Spring管理配置如下:

共分为3步:
加载mybatis核心配置文件,使用Spring静态工厂方式
创建SqlSessionFactoryBuilder对象,使用Spring无参构造方式
调用SqlSessionFactoryBuilder的build方法,使用Spring实例工厂方式

具体在 applicationContext.xml 中的配置如下

<!--静态工厂方式产生Bean实例-->
<bean id="inputStream" class="org.apache.ibatis.io.Resources" factory-method="getResourceAsStream">
   <constructor-arg name="resource" value="mybatis-config.xml" />
</bean>
<!--无参构造方式产生Bean实例-->
<bean id="sqlSessionFactoryBuilder" class="org.apache.ibatis.session.SqlSessionFactoryBuilder"/>
<!--实例工厂方式产生Bean实例-->
<bean id="sqlSessionFactory" factory-bean="sqlSessionFactoryBuilder" factory-method="build">
   <constructor-arg name="inputStream" ref="inputStream"/>
</bean>

2.2 核心代码(测试)

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) applicationContext.getBean("sqlSessionFactory");
SqlSession sqlSession = sqlSessionFactory.openSession();
System.out.println(sqlSession);

测试打印输出,sqlSession 已成功获取,说明我们自己定义的 SqlSessionFactory 可以成功使用

在这里插入图片描述

package com.hikvision.stms.config.landesk; import com.alibaba.druid.pool.DruidDataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.boot.autoconfigure.SpringBootVFS; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import javax.sql.DataSource; /** * 资产盘点数据库配置 * * @author: zhaoweicheng * @date: 2023/04/18 10:03 */ @Configuration @MapperScan(basePackages = "com.hikvision.stms.mapper.landeskDB.one", sqlSessionTemplateRef = "landeskDBOneSqlSessionTemplate") public class LandeskDbOneConfig { @Bean(name = "landeskDBOneDataSource") @ConfigurationProperties(prefix = "spring.datasource.landeskDB.one") public DataSource landeskDBOneDataSource() { return new DruidDataSource(); } @Bean(name = "landeskDBOneSessionFactory") public SqlSessionFactory landeskDBOneSessionFactory(@Qualifier("landeskDBOneDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/landeskDB/one/*.xml")); bean.setTypeAliasesPackage("com.hikvision.stms.domain.vo"); bean.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/mybatis-config.xml")); bean.setVfs(SpringBootVFS.class); return bean.getObject(); } @Bean public DataSourceTransactionManager landeskDBOneTransactionManager(@Qualifier("landeskDBOneDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Bean public SqlSessionTemplate landeskDBOneSqlSessionTemplate(@Qualifier("landeskDBOneSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } } spring boot,我有多个数据源配置,每个数据源配置都要写一个这样的config,太麻烦了,有没有更简单的党法
最新发布
07-03
Spring Boot 多数据源配置中,确实可以通过 **抽象配置类 + 动态 Bean 注册** 的方式避免重复代码。以下是优化后的方案: --- ### **优化方案:动态数据源配置基类** #### 1. 创建抽象配置基类 ```java import com.alibaba.druid.pool.DruidDataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.boot.autoconfigure.SpringBootVFS; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import javax.sql.DataSource; public abstract class AbstractDataSourceConfig { // 抽象方法:由子类指定数据源前缀和Mapper包路径 protected abstract String getDataSourcePrefix(); protected abstract String getMapperPackage(); protected abstract String getXmlPath(); protected abstract String getTypeAliasesPackage(); @Bean @ConfigurationProperties(prefix = getDataSourcePrefix()) // 动态绑定配置前缀 public DataSource dataSource() { return new DruidDataSource(); } @Bean public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations( new PathMatchingResourcePatternResolver().getResources(getXmlPath()) ); bean.setTypeAliasesPackage(getTypeAliasesPackage()); bean.setConfigLocation( new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/mybatis-config.xml") ); bean.setVfs(SpringBootVFS.class); return bean.getObject(); } @Bean public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Bean public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } } ``` #### 2. 子类配置(以 `LandeskDbOneConfig` 为) ```java @Configuration @MapperScan( basePackages = "com.hikvision.stms.mapper.landeskDB.one", sqlSessionTemplateRef = "sqlSessionTemplate" // 使用基类定义的Bean名称 ) public class LandeskDbOneConfig extends AbstractDataSourceConfig { @Override protected String getDataSourcePrefix() { return "spring.datasource.landeskDB.one"; } @Override protected String getMapperPackage() { return "com.hikvision.stms.mapper.landeskDB.one"; } @Override protected String getXmlPath() { return "classpath:mybatis/mapper/landeskDB/one/*.xml"; } @Override protected String getTypeAliasesPackage() { return "com.hikvision.stms.domain.vo"; } } ``` --- ### **进阶优化:完全动态注册(无需子类)** 如果连子类都不想写,可以通过 **`@ConfigurationProperties` + `BeanDefinitionRegistryPostProcessor`** 实现全自动化配置: #### 1. 配置文件示(`application.yml`) ```yaml spring: datasource: multi: datasources: one: prefix: spring.datasource.landeskDB.one mapper-package: com.hikvision.stms.mapper.landeskDB.one xml-path: classpath:mybatis/mapper/landeskDB/one/*.xml type-aliases-package: com.hikvision.stms.domain.vo two: prefix: spring.datasource.landeskDB.two mapper-package: com.hikvision.stms.mapper.landeskDB.two xml-path: classpath:mybatis/mapper/landeskDB/two/*.xml type-aliases-package: com.hikvision.stms.domain.entity ``` #### 2. 动态配置类 ```java import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import java.util.Map; @Configuration @EnableConfigurationProperties(MultiDataSourceProperties.class) public class DynamicDataSourceConfig implements EnvironmentAware { @Autowired private MultiDataSourceProperties properties; @Override public void setEnvironment(Environment environment) { properties.getDatasources().forEach((name, config) -> { // 1. 注册DataSource BeanDefinitionBuilder dataSourceBuilder = BeanDefinitionBuilder .rootBeanDefinition(DruidDataSource.class) .addPropertyValue("url", environment.getProperty(config.getPrefix() + ".url")) .addPropertyValue("username", environment.getProperty(config.getPrefix() + ".username")) .addPropertyValue("password", environment.getProperty(config.getPrefix() + ".password")); // 2. 注册SqlSessionFactory BeanDefinitionBuilder factoryBuilder = BeanDefinitionBuilder .rootBeanDefinition(SqlSessionFactoryBean.class) .addPropertyReference("dataSource", name + "DataSource") .addPropertyValue("mapperLocations", config.getXmlPath()) .addPropertyValue("typeAliasesPackage", config.getTypeAliasesPackage()); // 3. 注册Mapper扫描器(需通过其他方式触发) // ... // 注册到Spring容器 BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory(); registry.registerBeanDefinition(name + "DataSource", dataSourceBuilder.getBeanDefinition()); registry.registerBeanDefinition(name + "SqlSessionFactory", factoryBuilder.getBeanDefinition()); }); } } ``` --- ### **关键优化点** 1. **代码复用** - 基类方案通过抽象方法统一公共逻辑,子类只需提供差异化配置。 - 动态方案通过配置文件驱动,彻底消除重复代码。 2. **配置灵活性** - 支持通过 `application.yml` 动态增减数据源,无需修改代码。 3. **Spring 原生支持** - 仍使用标准的 `@MapperScan` 和 MyBatis 组件,兼容性良好。 --- ### **注意事项** 1. **`@Primary` 注解** - 如果多个数据源,需在主数据源的 Bean 上添加 `@Primary`。 2. **事务管理** - 动态方案中需额外处理 `DataSourceTransactionManager` 的注册。 3. **Mapper 扫描** - 动态方案可能需要结合 `ImportBeanDefinitionRegistrar` 实现 `@MapperScan` 的动态注册。 --- ### **最终建议** - **中等规模项目**:使用 **抽象基类方案**(平衡灵活性与简洁性)。 - **超多数据源项目**:使用 **全动态配置方案**(需配合自定义 `MapperScan` 逻辑)。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值