【SpringBoot】覆盖jar包中@Bean的方法
问题分析方案一:allow-bean-definition-overridingspring:main:allow-bean-definition-overriding: true # 允许bd覆盖/*** @description: 先设置allow-bean-definition-overriding=true,然后在@Import{@link kfang.infra.feature.mysq
·
问题
项目启动类使用@Import
引入公司封装的基础框架中的jar
包中的MysqlConfig.class
,里面封装了一些使用规范。
@SpringCloudApplication
@Import({WebBaseConfig.class, ServiceBaseConfig.class, MysqlConfig.class})
@EnableScheduling
public class ImServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ImServiceApplication.class, args);
BootstrapLogDoneFilter.bootstrapDone();
}
}
nacos
中配置基础框架中定义的配置项
xx.infra.common.env.deploy=dev
xx.infra.common.env.app-name=service-im-data
xx.mysql.url=xxxxx
xx.mysql.username=root
xx.mysql.password=123456
xx.infra.service.mybatis.aliases-package=com.xxx.service.im
MysqlConfig.java
@ComponentScan({"xx.yy.feature.mysql.mybatis"})
@EnableConfigurationProperties({XxMysqlProperties.class})
public class MysqlConfig {
public MysqlConfig() {}
@Bean(name = {"mysqlSqlSessionFactory"})
public SqlSessionFactory mysqlSqlSessionFactory(DruidDataSource mysqlDataSource, XxInfraServiceProperties baseProperties) throws Exception {
SqlSessionFactory factory = ConfigFactory.makeSqlSessionFactory(baseProperties, mysqlDataSource, MySqlDialect.class);
return factory;
}
//......
}
public class BaseDaoConfigFactory {
public BaseDaoConfigFactory() {}
public static SqlSessionFactory makeSqlSessionFactory(XxInfraServiceProperties baseProperties, DataSource dataSource, Class<? extends Dialect> type) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
VFS.addImplClass(SpringBootVFS.class);
Properties properties = new Properties();
properties.setProperty("cacheEnabled", Boolean.toString(baseProperties.getMybatis().isCacheEnabled()));
properties.setProperty("defaultStatementTimeout", Integer.toString(baseProperties.getMybatis().getDefaultStatementTimeout()));
bean.setConfigurationProperties(properties);
BaseInterceptor multiDataSourceInterceptor = new BaseInterceptor();
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
Properties pageProperties = new Properties();
pageProperties.setProperty("dialectClass", type.getName());
paginationInterceptor.setProperties(pageProperties);
List<Interceptor> pluginList = CommonListUtil.NEW(new Interceptor[]{multiDataSourceInterceptor, paginationInterceptor});
if (baseProperties.getMybatis().isStatSql()) {
SqlStatInterceptor.turnOn();
pluginList.add(new SqlStatInterceptor());
}
if (CommonListUtil.isNotEmpty(ServiceBaseConfig.getCustomizeMybatisInterceptors())) {
pluginList.addAll(ServiceBaseConfig.getCustomizeMybatisInterceptors());
}
bean.setPlugins((Interceptor[])pluginList.toArray(new Interceptor[0]));
bean.setDataSource(dataSource);
bean.setTypeAliasesPackage(baseProperties.getMybatis().getAliasesPackage());
bean.setTypeAliasesSuperType(Entity.class); // 这里写死了superType,很烦,我要想办法去掉这个限制~
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
bean.setMapperLocations(resolver.getResources(baseProperties.getMybatis().getMapperLocation()));
SqlSessionFactory factory = bean.getObject();
factory.getConfiguration().setCacheEnabled(baseProperties.getMybatis().isCacheEnabled());
factory.getConfiguration().setDefaultStatementTimeout(baseProperties.getMybatis().getDefaultStatementTimeout());
return factory;
}
//......
}
由于jar包中MysqlConfig
的限制,只能为superType
是基础框架中定义的Entity
的类注册typeAlias
,但是我现在项目中写的实体类都没有继承自Entity
,所以mapper文件还是得写实体类的全路径,很烦~
<insert id="insertSelective" parameterType="com.xx.service.im.model.ImUserModel">
insert into t_im_user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="userId != null">
FUSER_ID,
</if>
<if test="userSig != null">
FUSER_SIG,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="userId != null">
#{userId},
</if>
<if test="userSig != null">
#{userSig},
</if>
</trim>
</insert >
分析
方案一:allow-bean-definition-overriding
spring:
main:
allow-bean-definition-overriding: true # 允许bd覆盖
/**
* @description: 先设置allow-bean-definition-overriding=true,然后在@Import{@link Xx.infra.feature.mysql.MysqlConfig}后再导入该类,从而覆盖其中的mysqlSqlSessionFactory
* @author: panxili
* @date: 2021/11/12
*/
public class MyMysqlConfig {
/**
* 改造{@link Xx.infra.feature.mysql.MysqlConfig#mysqlSqlSessionFactory},使得mybatis注册类别名时,取消对superType是{@link Xx.infra.common.model.Entity}的限制
*
* @param mysqlDataSource
* @param baseProperties
* @return
* @throws Exception
*/
@Bean(name = {"mysqlSqlSessionFactory"})
public SqlSessionFactory mysqlSqlSessionFactory(DruidDataSource mysqlDataSource, XxInfraServiceProperties baseProperties) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
VFS.addImplClass(SpringBootVFS.class);
Properties properties = new Properties();
properties.setProperty("cacheEnabled", Boolean.toString(baseProperties.getMybatis().isCacheEnabled()));
properties.setProperty("defaultStatementTimeout", Integer.toString(baseProperties.getMybatis().getDefaultStatementTimeout()));
bean.setConfigurationProperties(properties);
BaseInterceptor multiDataSourceInterceptor = new BaseInterceptor();
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
Properties pageProperties = new Properties();
pageProperties.setProperty("dialectClass", MySqlDialect.class.getName());
paginationInterceptor.setProperties(pageProperties);
List<Interceptor> pluginList = CommonListUtil.NEW(new Interceptor[]{multiDataSourceInterceptor, paginationInterceptor});
if (baseProperties.getMybatis().isStatSql()) {
SqlStatInterceptor.turnOn();
pluginList.add(new SqlStatInterceptor());
}
if (CommonListUtil.isNotEmpty(ServiceBaseConfig.getCustomizeMybatisInterceptors())) {
pluginList.addAll(ServiceBaseConfig.getCustomizeMybatisInterceptors());
}
bean.setPlugins((Interceptor[])pluginList.toArray(new Interceptor[0]));
bean.setDataSource(mysqlDataSource);
bean.setTypeAliasesPackage(baseProperties.getMybatis().getAliasesPackage());
// 取消对superType的限制
// bean.setTypeAliasesSuperType(Entity.class);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
bean.setMapperLocations(resolver.getResources(baseProperties.getMybatis().getMapperLocation()));
SqlSessionFactory factory = bean.getObject();
factory.getConfiguration().setCacheEnabled(baseProperties.getMybatis().isCacheEnabled());
factory.getConfiguration().setDefaultStatementTimeout(baseProperties.getMybatis().getDefaultStatementTimeout());
return factory;
}
}
@SpringCloudApplication
@Import({WebBaseConfig.class, ServiceBaseConfig.class, MysqlConfig.class, MyMysqlConfig.class})
@EnableScheduling
public class ImServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ImServiceApplication.class, args);
BootstrapLogDoneFilter.bootstrapDone();
}
}
方案二:BeanFactoryPostProcessor
允许bd
覆盖,可能会有隐患,SpringBoot
默认也是false
。
@Component
@Slf4j
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
/**
* 可以修改应用程序上下文的内部bd注册表,即对bd注册表进行crud
* @param registry
* @throws BeansException
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
log.debug("MyBeanDefinitionRegistryPostProcessor...postProcessBeanDefinitionRegistry...");
final var sqlSessionFactoryBeanName = "mysqlSqlSessionFactory";
final var sqlSessionFactoryBeanName2 = "mysqlSqlSessionFactory2";
// 若jar包和程序都注册了sqlSessionFactory,就将程序里的bd覆盖掉jar包里的bd(继续使用jar包里的beanName,防止jar包中其它bean指定依赖了这个beanName)
if (registry.containsBeanDefinition(sqlSessionFactoryBeanName) && registry.containsBeanDefinition(sqlSessionFactoryBeanName2)) {
registry.removeBeanDefinition(sqlSessionFactoryBeanName);
registry.registerBeanDefinition(sqlSessionFactoryBeanName, registry.getBeanDefinition(sqlSessionFactoryBeanName2));
registry.removeBeanDefinition(sqlSessionFactoryBeanName2);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
log.debug("MyBeanDefinitionRegistryPostProcessor...postProcessBeanFactory...");
final var beanDefinition = beanFactory.getBeanDefinition("mysqlSqlSessionFactory");
}
}
更多推荐
已为社区贡献3条内容
所有评论(0)