mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-06 16:48:24 +08:00
mybatis-flex-solon-plugin:改为 MybatisFlexAutoConfiguration 容器自动装配的风格,方便熟悉 spring 的同学阅读和维护
This commit is contained in:
parent
9f52273905
commit
40c67468e9
@ -63,19 +63,6 @@ mybatis-flex:
|
||||
#
|
||||
```
|
||||
|
||||
主要支持的属性说明:
|
||||
|
||||
| 支持属性 | 别名(保持与之前的兼容) | 说明 |
|
||||
|-------------------------|----------------------------|----------------------------------|
|
||||
| type-aliases-package | typeAliases | 类型别名 |
|
||||
| type-aliases-super-type | typeAliasesSuperType | 类型别名的父类(用于过滤) |
|
||||
| type-handlers-package | typeHandlers | 类型处理器 |
|
||||
| mapper-locations | mappers | mapper 类或xml文件 |
|
||||
| configuration | configuration | mybatis 配置。对应类:FlexConfiguration |
|
||||
| global-config | globalConfig | 全局部置。对应类:FlexGlobalConfig |
|
||||
|
||||
|
||||
|
||||
##### Mapper 配置注意事项:
|
||||
|
||||
* 通过 mapper 类包名配置。 xml 与 mapper 需同包同名
|
||||
@ -95,13 +82,15 @@ mybatis-flex.mapper-locations: "classpath:mybatis/db1/*.xml"
|
||||
|
||||
```java
|
||||
//配置 mf (如果配置不能满足需求,可以进一步代助代码)
|
||||
@Configuration
|
||||
public class Config {
|
||||
@Bean
|
||||
public void ormConfig(@Inject FlexConfiguration cfg,
|
||||
@Inject FlexGlobalConfig globalConfig) {
|
||||
@Component
|
||||
public class MyBatisFlexCustomizerImpl implements MyBatisFlexCustomizer, ConfigurationCustomizer {
|
||||
@Override
|
||||
public void customize(FlexGlobalConfig globalConfig) {
|
||||
|
||||
cfg.setCacheEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(FlexConfiguration configuration) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,16 +5,18 @@ import org.noear.solon.data.datasource.RoutingDataSource;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* 数据源路由工具(用于确定当前真实数据源)
|
||||
*
|
||||
* @author noear 2024/12/3 created
|
||||
*/
|
||||
public class FlexDataSourceRouting {
|
||||
public static DataSource determineCurrentTarget(DataSource original) {
|
||||
if (original instanceof FlexDataSource) {
|
||||
return ((FlexDataSource) original).getDataSource();
|
||||
return determineCurrentTarget(((FlexDataSource) original).getDataSource());
|
||||
}
|
||||
|
||||
if (original instanceof RoutingDataSource) {
|
||||
return ((RoutingDataSource) original).determineCurrentTarget();
|
||||
return determineCurrentTarget(((RoutingDataSource) original).determineCurrentTarget());
|
||||
}
|
||||
|
||||
return original;
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mybatisflex.solon;
|
||||
|
||||
import com.mybatisflex.core.mybatis.FlexConfiguration;
|
||||
|
||||
/**
|
||||
* 为 {@link FlexConfiguration} 做自定义的配置支持。
|
||||
* @author michael
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ConfigurationCustomizer {
|
||||
|
||||
/**
|
||||
* 自定义配置 {@link FlexConfiguration}。
|
||||
*
|
||||
* @param configuration MyBatis Flex Configuration
|
||||
*/
|
||||
void customize(FlexConfiguration configuration);
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mybatisflex.solon;
|
||||
|
||||
import com.mybatisflex.core.FlexGlobalConfig;
|
||||
|
||||
/**
|
||||
* <p>MyBatis-Flex 配置。
|
||||
*
|
||||
* <p>一般可以用于去初始化:
|
||||
*
|
||||
* <ul>
|
||||
* <li>FlexGlobalConfig 的全局配置
|
||||
* <li>自定义主键生成器
|
||||
* <li>多租户配置
|
||||
* <li>动态表名配置
|
||||
* <li>逻辑删除处理器配置
|
||||
* <li>自定义脱敏规则
|
||||
* <li>SQL 审计配置
|
||||
* <li>SQL 打印配置
|
||||
* <li>数据源解密器配置
|
||||
* <li>自定义数据方言配置
|
||||
* <li>...
|
||||
* </ul>
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface MyBatisFlexCustomizer {
|
||||
|
||||
/**
|
||||
* 自定义 MyBatis-Flex 配置。
|
||||
*
|
||||
* @param globalConfig 全局配置
|
||||
*/
|
||||
void customize(FlexGlobalConfig globalConfig);
|
||||
}
|
||||
@ -0,0 +1,231 @@
|
||||
package com.mybatisflex.solon;
|
||||
|
||||
import com.mybatisflex.core.FlexConsts;
|
||||
import com.mybatisflex.core.FlexGlobalConfig;
|
||||
import com.mybatisflex.core.MybatisFlexBootstrap;
|
||||
import com.mybatisflex.core.mybatis.FlexConfiguration;
|
||||
import com.mybatisflex.core.mybatis.FlexSqlSessionFactoryBuilder;
|
||||
import com.mybatisflex.core.row.RowMapperInvoker;
|
||||
import com.mybatisflex.solon.transaction.MybatisMapperInterceptor;
|
||||
import com.mybatisflex.solon.transaction.SolonManagedTransactionFactory;
|
||||
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
|
||||
import org.apache.ibatis.executor.ErrorContext;
|
||||
import org.apache.ibatis.io.Resources;
|
||||
import org.apache.ibatis.mapping.Environment;
|
||||
import org.apache.ibatis.plugin.Interceptor;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
|
||||
import org.apache.ibatis.transaction.TransactionFactory;
|
||||
import org.apache.ibatis.type.TypeHandler;
|
||||
import org.noear.solon.Utils;
|
||||
import org.noear.solon.annotation.Bean;
|
||||
import org.noear.solon.annotation.Condition;
|
||||
import org.noear.solon.annotation.Configuration;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.core.AppContext;
|
||||
import org.noear.solon.core.event.EventBus;
|
||||
import org.noear.solon.core.util.ResourceUtil;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
/**
|
||||
* Mybatis-Flex 自动装配
|
||||
*
|
||||
* @author noear 2024/12/17 created
|
||||
*/
|
||||
@Configuration
|
||||
public class MybatisFlexAutoConfiguration {
|
||||
private DataSource getDataSource() {
|
||||
return MybatisFlexBootstrap.getInstance().getDataSource();
|
||||
}
|
||||
|
||||
@Inject
|
||||
private AppContext appContext;
|
||||
|
||||
@Bean
|
||||
public FlexConfiguration configuration(MybatisFlexProperties flexProperties,
|
||||
@Inject(required = false) ConfigurationCustomizer configurationCustomizer) {
|
||||
TransactionFactory tf = new SolonManagedTransactionFactory();
|
||||
Environment environment = new Environment(FlexConsts.NAME, tf, getDataSource());
|
||||
|
||||
FlexConfiguration configuration = new FlexConfiguration(environment);
|
||||
|
||||
if (Utils.isNotEmpty(flexProperties.getConfigurationProperties())) {
|
||||
Utils.injectProperties(configuration, flexProperties.getConfigurationProperties());
|
||||
}
|
||||
|
||||
if (flexProperties.getConfiguration() != null) {
|
||||
flexProperties.getConfiguration().applyTo(configuration);
|
||||
}
|
||||
|
||||
if (configurationCustomizer != null) {
|
||||
configurationCustomizer.customize(configuration);
|
||||
}
|
||||
|
||||
//增加事件总线扩展
|
||||
EventBus.publish(configuration);
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@Condition(onMissingBean = SqlSessionFactoryBuilder.class)
|
||||
public SqlSessionFactoryBuilder sqlSessionFactoryBuilder() {
|
||||
return new FlexSqlSessionFactoryBuilder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SqlSessionFactory sqlSessionFactory(MybatisFlexProperties flexProperties,
|
||||
FlexConfiguration flexConfiguration,
|
||||
SqlSessionFactoryBuilder sqlSessionFactoryBuilder) {
|
||||
appContext.subBeansOfType(Interceptor.class, bean -> {
|
||||
flexConfiguration.addInterceptor(bean);
|
||||
});
|
||||
|
||||
if (isNotEmpty(flexProperties.getTypeAliasesPackage())) {
|
||||
Class<?> typeAliasesSuperType = flexProperties.getTypeAliasesSuperType();
|
||||
for (String val : flexProperties.getTypeAliasesPackage()) {
|
||||
//package || type class,转为类表达式
|
||||
for (Class<?> clz : ResourceUtil.scanClasses(appContext.getClassLoader(), val)) {
|
||||
if (isTypeAliases(clz, typeAliasesSuperType)) {
|
||||
flexConfiguration.getTypeAliasRegistry().registerAlias(clz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isNotEmpty(flexProperties.getTypeHandlersPackage())) {
|
||||
for (String val : flexProperties.getTypeHandlersPackage()) {
|
||||
for (Class<?> clz : ResourceUtil.scanClasses(appContext.getClassLoader(), val)) {
|
||||
if (TypeHandler.class.isAssignableFrom(clz)) {
|
||||
flexConfiguration.getTypeHandlerRegistry().register(clz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isNotEmpty(flexProperties.getMapperLocations())) {
|
||||
for (String val : flexProperties.getMapperLocations()) {
|
||||
if (ResourceUtil.hasClasspath(val)) {
|
||||
//mapper xml, 新方法,替代旧的 *.xml (基于表达式;更自由,更语义化)
|
||||
for (String uri : ResourceUtil.scanResources(val)) {
|
||||
addMapperByXml(flexConfiguration, uri);
|
||||
}
|
||||
} else {
|
||||
//package || type class,转为类表达式
|
||||
for (Class<?> clz : ResourceUtil.scanClasses(appContext.getClassLoader(), val)) {
|
||||
if (clz.isInterface()) {
|
||||
//no mapperVerifyEnabled ...
|
||||
flexConfiguration.addMapper(clz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//如果有配置,但是没有 mapper 注册成功;说明有问题了
|
||||
if (flexConfiguration.getMapperRegistry().getMappers().size() == 0) {
|
||||
throw new IllegalStateException("Missing mapper registration, please check the 'mapperLocations' configuration!");
|
||||
}
|
||||
}
|
||||
|
||||
return sqlSessionFactoryBuilder.build(flexConfiguration);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FlexGlobalConfig globalConfig(MybatisFlexProperties flexProperties,
|
||||
FlexConfiguration flexConfiguration,
|
||||
SqlSessionFactory sqlSessionFactory,
|
||||
@Inject(required = false) MyBatisFlexCustomizer flexCustomizer) {
|
||||
|
||||
FlexGlobalConfig globalConfig = FlexGlobalConfig.getDefaultConfig();
|
||||
|
||||
if (flexProperties.getGlobalConfig() != null) {
|
||||
flexProperties.getGlobalConfig().applyTo(globalConfig);
|
||||
}
|
||||
|
||||
if (globalConfig.getKeyConfig() == null) {
|
||||
//如果没有,给个默认值
|
||||
globalConfig.setKeyConfig(new FlexGlobalConfig.KeyConfig());
|
||||
}
|
||||
|
||||
globalConfig.setConfiguration(flexConfiguration);
|
||||
globalConfig.setSqlSessionFactory(sqlSessionFactory);
|
||||
|
||||
if (flexCustomizer != null) {
|
||||
flexCustomizer.customize(globalConfig);
|
||||
}
|
||||
|
||||
//增加事件总线扩展
|
||||
EventBus.publish(globalConfig);
|
||||
|
||||
return globalConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public void mapperPublish(FlexConfiguration flexConfiguration,
|
||||
FlexGlobalConfig globalConfig,
|
||||
SqlSessionFactory sqlSessionFactory) {
|
||||
for (Class<?> mapperClz : flexConfiguration.getMapperRegistry().getMappers()) {
|
||||
MybatisMapperInterceptor handler = new MybatisMapperInterceptor(sqlSessionFactory, mapperClz);
|
||||
|
||||
Object mapperProxy = Proxy.newProxyInstance(
|
||||
mapperClz.getClassLoader(),
|
||||
new Class[]{mapperClz},
|
||||
handler);
|
||||
|
||||
//推入容器,之后可以被注入
|
||||
appContext.wrapAndPut(mapperClz, mapperProxy);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RowMapperInvoker rowMapperInvoker(SqlSessionFactory sqlSessionFactory) {
|
||||
return new RowMapperInvoker(sqlSessionFactory);
|
||||
}
|
||||
|
||||
/////////////
|
||||
|
||||
/**
|
||||
* 添加 xml mapper
|
||||
*/
|
||||
private void addMapperByXml(FlexConfiguration flexConfiguration, String uri) {
|
||||
try {
|
||||
// resource 配置方式
|
||||
ErrorContext.instance().resource(uri);
|
||||
|
||||
//读取mapper文件
|
||||
InputStream stream = Resources.getResourceAsStream(uri);
|
||||
|
||||
//mapper映射文件都是通过XMLMapperBuilder解析
|
||||
XMLMapperBuilder mapperParser = new XMLMapperBuilder(stream, flexConfiguration, uri, flexConfiguration.getSqlFragments());
|
||||
mapperParser.parse();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为非空数组
|
||||
*/
|
||||
private boolean isNotEmpty(String[] ary) {
|
||||
return ary != null && ary.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为类型别名
|
||||
*/
|
||||
private boolean isTypeAliases(Class<?> clz, Class<?> typeAliasesSuperType) {
|
||||
if (clz.isInterface()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeAliasesSuperType != null) {
|
||||
return typeAliasesSuperType.isAssignableFrom(clz);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -24,13 +24,11 @@ import org.apache.ibatis.scripting.LanguageDriver;
|
||||
import org.apache.ibatis.session.*;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import org.apache.ibatis.type.TypeHandler;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.core.util.ResourceUtil;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@ -42,6 +40,8 @@ import java.util.stream.Stream;
|
||||
* @author micahel
|
||||
* @author 王帅
|
||||
*/
|
||||
@org.noear.solon.annotation.Configuration
|
||||
@Inject("${mybatisFlex}")
|
||||
public class MybatisFlexProperties {
|
||||
private String defaultDatasourceKey;
|
||||
|
||||
@ -77,7 +77,7 @@ public class MybatisFlexProperties {
|
||||
/**
|
||||
* Packages to search type aliases. (Package delimiters are ",; \t\n")
|
||||
*/
|
||||
private String typeAliasesPackage;
|
||||
private String[] typeAliasesPackage;
|
||||
|
||||
/**
|
||||
* The super class for filtering type alias. If this not specifies, the MyBatis deal as type alias all classes that
|
||||
@ -88,7 +88,7 @@ public class MybatisFlexProperties {
|
||||
/**
|
||||
* Packages to search for type handlers. (Package delimiters are ",; \t\n")
|
||||
*/
|
||||
private String typeHandlersPackage;
|
||||
private String[] typeHandlersPackage;
|
||||
|
||||
/**
|
||||
* Indicates whether perform presence check of the MyBatis xml config file.
|
||||
@ -183,19 +183,19 @@ public class MybatisFlexProperties {
|
||||
this.mapperLocations = mapperLocations;
|
||||
}
|
||||
|
||||
public String getTypeHandlersPackage() {
|
||||
public String[] getTypeHandlersPackage() {
|
||||
return this.typeHandlersPackage;
|
||||
}
|
||||
|
||||
public void setTypeHandlersPackage(String typeHandlersPackage) {
|
||||
public void setTypeHandlersPackage(String[] typeHandlersPackage) {
|
||||
this.typeHandlersPackage = typeHandlersPackage;
|
||||
}
|
||||
|
||||
public String getTypeAliasesPackage() {
|
||||
public String[] getTypeAliasesPackage() {
|
||||
return this.typeAliasesPackage;
|
||||
}
|
||||
|
||||
public void setTypeAliasesPackage(String typeAliasesPackage) {
|
||||
public void setTypeAliasesPackage(String[] typeAliasesPackage) {
|
||||
this.typeAliasesPackage = typeAliasesPackage;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
package com.mybatisflex.solon.annotation;
|
||||
|
||||
import com.mybatisflex.annotation.UseDataSource;
|
||||
import com.mybatisflex.core.datasource.DataSourceKey;
|
||||
import org.noear.solon.core.aspect.Invocation;
|
||||
import org.noear.solon.core.aspect.MethodInterceptor;
|
||||
import org.noear.solon.core.util.TmplUtil;
|
||||
|
||||
/**
|
||||
* @author noear 2024/12/17 created
|
||||
*/
|
||||
public class UseDataSourceInterceptor implements MethodInterceptor {
|
||||
@Override
|
||||
public Object doIntercept(Invocation inv) throws Throwable {
|
||||
UseDataSource anno = inv.getMethodAnnotation(UseDataSource.class);
|
||||
|
||||
if (anno == null) {
|
||||
anno = inv.getTargetAnnotation(UseDataSource.class);
|
||||
}
|
||||
|
||||
if (anno == null) {
|
||||
return inv.invoke();
|
||||
} else {
|
||||
String dsName = TmplUtil.parse(anno.value(), inv);
|
||||
DataSourceKey.use(dsName);
|
||||
|
||||
try {
|
||||
return inv.invoke();
|
||||
} finally {
|
||||
//还原
|
||||
DataSourceKey.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
package com.mybatisflex.solon.aot;
|
||||
|
||||
import com.mybatisflex.solon.integration.XPluginImpl;
|
||||
import com.mybatisflex.solon.mybtais.MybatisAdapterDefault;
|
||||
import com.mybatisflex.core.mybatis.FlexConfiguration;
|
||||
import com.mybatisflex.solon.MybatisFlexProperties;
|
||||
import org.apache.ibatis.cache.decorators.FifoCache;
|
||||
import org.apache.ibatis.cache.decorators.LruCache;
|
||||
import org.apache.ibatis.cache.decorators.SoftCache;
|
||||
@ -25,6 +25,7 @@ import org.apache.ibatis.scripting.defaults.RawLanguageDriver;
|
||||
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
|
||||
import org.apache.ibatis.session.Configuration;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.apache.ibatis.type.TypeHandler;
|
||||
import org.noear.solon.aot.NativeMetadataUtils;
|
||||
import org.noear.solon.aot.RuntimeNativeMetadata;
|
||||
import org.noear.solon.aot.RuntimeNativeRegistrar;
|
||||
@ -98,27 +99,29 @@ public class MybatisRuntimeNativeRegistrar implements RuntimeNativeRegistrar {
|
||||
metadata.registerReflection(DefaultVFS.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
|
||||
|
||||
|
||||
registerMybatisAdapter(context, metadata, XPluginImpl.getAdapterFlex());
|
||||
registerMybatisAdapter(context, metadata);
|
||||
|
||||
}
|
||||
|
||||
protected void registerMybatisAdapter(AppContext context, RuntimeNativeMetadata metadata, MybatisAdapterDefault bean) {
|
||||
if (bean == null) {
|
||||
return;
|
||||
}
|
||||
protected void registerMybatisAdapter(AppContext context, RuntimeNativeMetadata metadata) {
|
||||
MybatisFlexProperties flexProperties = context.getBean(MybatisFlexProperties.class);
|
||||
|
||||
//注册 xml 资源
|
||||
for (String res : bean.getMappers()) {
|
||||
if (res.startsWith(ResourceUtil.TAG_classpath)) {
|
||||
res = res.substring(ResourceUtil.TAG_classpath.length());
|
||||
if (flexProperties != null) {
|
||||
for (String res : flexProperties.getMapperLocations()) {
|
||||
if (ResourceUtil.hasClasspath(res)) {
|
||||
res = ResourceUtil.remSchema(res);
|
||||
res = res.replace("**", "*");
|
||||
res = res.replace("*", ".*");
|
||||
metadata.registerResourceInclude(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FlexConfiguration flexConfiguration = context.getBean(FlexConfiguration.class);
|
||||
if (flexConfiguration != null) {
|
||||
//注册 mapper 代理
|
||||
for (Class<?> clz : bean.getConfiguration().getMapperRegistry().getMappers()) {
|
||||
for (Class<?> clz : flexConfiguration.getMapperRegistry().getMappers()) {
|
||||
metadata.registerJdkProxy(clz);
|
||||
metadata.registerReflection(clz, MemberCategory.INTROSPECT_PUBLIC_METHODS);
|
||||
Method[] declaredMethods = clz.getDeclaredMethods();
|
||||
@ -129,9 +132,16 @@ public class MybatisRuntimeNativeRegistrar implements RuntimeNativeRegistrar {
|
||||
}
|
||||
|
||||
// 注册 entity
|
||||
for (Class<?> clz : bean.getConfiguration().getTypeAliasRegistry().getTypeAliases().values()) {
|
||||
for (Class<?> clz : flexConfiguration.getTypeAliasRegistry().getTypeAliases().values()) {
|
||||
metadata.registerReflection(clz, MemberCategory.DECLARED_FIELDS, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
|
||||
metadata.registerDefaultConstructor(clz);
|
||||
}
|
||||
|
||||
//注处 typeHandler
|
||||
for (TypeHandler typeHandler : flexConfiguration.getTypeHandlerRegistry().getTypeHandlers()) {
|
||||
metadata.registerReflection(typeHandler.getClass(), MemberCategory.DECLARED_FIELDS, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
|
||||
metadata.registerDefaultConstructor(typeHandler.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,170 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mybatisflex.solon.integration;
|
||||
|
||||
import com.mybatisflex.core.FlexGlobalConfig;
|
||||
import com.mybatisflex.core.mybatis.FlexConfiguration;
|
||||
import com.mybatisflex.core.mybatis.FlexSqlSessionFactoryBuilder;
|
||||
import com.mybatisflex.core.row.RowMapperInvoker;
|
||||
import com.mybatisflex.solon.MybatisFlexProperties;
|
||||
import com.mybatisflex.solon.mybtais.MybatisAdapterDefault;
|
||||
import org.apache.ibatis.mapping.Environment;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.noear.solon.Utils;
|
||||
import org.noear.solon.core.BeanWrap;
|
||||
import org.noear.solon.core.Props;
|
||||
import org.noear.solon.core.VarHolder;
|
||||
import org.noear.solon.core.event.EventBus;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* MyBatis-Flex 适配器。
|
||||
*
|
||||
* @author noear
|
||||
* @since 2.2
|
||||
*/
|
||||
public class MybatisAdapterFlex extends MybatisAdapterDefault {
|
||||
private FlexSqlSessionFactoryBuilder factoryBuilderPlus;
|
||||
private FlexGlobalConfig globalConfig;
|
||||
private RowMapperInvoker rowMapperInvoker;
|
||||
private Class<?> typeAliasesBaseType;
|
||||
private MybatisFlexProperties flexProperties;
|
||||
|
||||
protected MybatisAdapterFlex(BeanWrap dsWrap, Props flexProps, MybatisFlexProperties flexProperties) {
|
||||
this.factoryBuilderPlus = new FlexSqlSessionFactoryBuilder();
|
||||
this.flexProperties = flexProperties;
|
||||
|
||||
//初始化开始
|
||||
initStart(dsWrap, flexProps);
|
||||
|
||||
//初始化之前
|
||||
initAfter(dsWrap);
|
||||
}
|
||||
|
||||
protected void initAfter(BeanWrap dsWrap) {
|
||||
globalConfig.setSqlSessionFactory(getFactory());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSource getDataSource() {
|
||||
return dsWrap.raw();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initConfiguration(Environment environment) {
|
||||
//for configuration section
|
||||
config = new FlexConfiguration(environment);
|
||||
|
||||
if (Utils.isNotEmpty(flexProperties.getConfigurationProperties())) {
|
||||
Utils.injectProperties(config, flexProperties.getConfigurationProperties());
|
||||
}
|
||||
|
||||
if (flexProperties.getConfiguration() != null) {
|
||||
flexProperties.getConfiguration().applyTo(config);
|
||||
}
|
||||
|
||||
//for globalConfig section
|
||||
if (dsWrap.typed()) {
|
||||
globalConfig = FlexGlobalConfig.getDefaultConfig();
|
||||
} else {
|
||||
globalConfig = new FlexGlobalConfig();
|
||||
}
|
||||
|
||||
if (flexProperties.getGlobalConfig() != null) {
|
||||
flexProperties.getGlobalConfig().applyTo(globalConfig);
|
||||
}
|
||||
|
||||
if (globalConfig.getKeyConfig() == null) {
|
||||
//如果没有,给个默认值
|
||||
globalConfig.setKeyConfig(new FlexGlobalConfig.KeyConfig());
|
||||
}
|
||||
|
||||
globalConfig.setConfiguration(config);
|
||||
|
||||
FlexGlobalConfig.setConfig(environment.getId(), globalConfig, false);
|
||||
|
||||
//增加事件扩展机制
|
||||
EventBus.publish(globalConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadConfiguration() {
|
||||
typeAliasesBaseType = flexProperties.getTypeAliasesSuperType();
|
||||
super.loadConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全局配置
|
||||
*/
|
||||
public FlexGlobalConfig getGlobalConfig() {
|
||||
return globalConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlSessionFactory getFactory() {
|
||||
if (factory == null) {
|
||||
factory = factoryBuilderPlus.build(getConfiguration());
|
||||
}
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectTo(VarHolder varH) {
|
||||
super.injectTo(varH);
|
||||
|
||||
// @Db("db1") FlexGlobalConfig globalConfig
|
||||
if (FlexGlobalConfig.class.isAssignableFrom(varH.getType())) {
|
||||
varH.setValue(this.getGlobalConfig());
|
||||
return;
|
||||
}
|
||||
|
||||
// @Db("db1") RowMapperInvoker rowMapper
|
||||
if (RowMapperInvoker.class.equals(varH.getType())) {
|
||||
if (rowMapperInvoker == null) {
|
||||
rowMapperInvoker = new RowMapperInvoker(getFactory());
|
||||
}
|
||||
varH.setValue(rowMapperInvoker);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isTypeAliasesType(Class<?> type) {
|
||||
//typeAliasesSuperType
|
||||
if (typeAliasesBaseType == null) {
|
||||
return true;
|
||||
} else {
|
||||
return typeAliasesBaseType.isAssignableFrom(type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isTypeAliasesKey(String key) {
|
||||
return super.isTypeAliasesKey(key) || key.startsWith("typeAliasesPackage[");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isTypeHandlersKey(String key) {
|
||||
return super.isTypeHandlersKey(key) || key.startsWith("typeHandlersPackage[");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isMappersKey(String key) {
|
||||
return super.isMappersKey(key) || key.startsWith("mapperLocations[");
|
||||
}
|
||||
}
|
||||
@ -17,35 +17,30 @@
|
||||
package com.mybatisflex.solon.integration;
|
||||
|
||||
import com.mybatisflex.annotation.UseDataSource;
|
||||
import com.mybatisflex.core.FlexConsts;
|
||||
import com.mybatisflex.core.FlexGlobalConfig;
|
||||
import com.mybatisflex.core.MybatisFlexBootstrap;
|
||||
import com.mybatisflex.core.datasource.*;
|
||||
import com.mybatisflex.core.logicdelete.LogicDeleteManager;
|
||||
import com.mybatisflex.core.logicdelete.LogicDeleteProcessor;
|
||||
import com.mybatisflex.core.mybatis.FlexConfiguration;
|
||||
import com.mybatisflex.core.row.RowMapperInvoker;
|
||||
import com.mybatisflex.core.table.DynamicSchemaProcessor;
|
||||
import com.mybatisflex.core.table.DynamicTableProcessor;
|
||||
import com.mybatisflex.core.table.TableManager;
|
||||
import com.mybatisflex.core.tenant.TenantFactory;
|
||||
import com.mybatisflex.core.tenant.TenantManager;
|
||||
import com.mybatisflex.solon.MybatisFlexAutoConfiguration;
|
||||
import com.mybatisflex.solon.MybatisFlexProperties;
|
||||
import com.mybatisflex.solon.annotation.UseDataSourceInterceptor;
|
||||
import com.mybatisflex.solon.aot.MybatisRuntimeNativeRegistrar;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.noear.solon.Utils;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.aot.RuntimeNativeRegistrar;
|
||||
import org.noear.solon.core.AppContext;
|
||||
import org.noear.solon.core.BeanWrap;
|
||||
import org.noear.solon.core.Plugin;
|
||||
import org.noear.solon.core.Props;
|
||||
import org.noear.solon.core.runtime.NativeDetector;
|
||||
import org.noear.solon.core.util.ClassUtil;
|
||||
import org.noear.solon.core.util.TmplUtil;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* 配置 MyBatis-Flex 插件。
|
||||
@ -53,28 +48,30 @@ import java.util.Map;
|
||||
* @author noear
|
||||
* @since 2.2
|
||||
*/
|
||||
public class XPluginImpl implements Plugin {
|
||||
private static final String CONFIG_PREFIX = "mybatisFlex.";
|
||||
|
||||
private static MybatisAdapterFlex adapterFlex;
|
||||
|
||||
public static MybatisAdapterFlex getAdapterFlex() {
|
||||
return adapterFlex;
|
||||
}
|
||||
|
||||
private Props flexProps;
|
||||
private MybatisFlexProperties flexProperties;
|
||||
|
||||
public class MybatisFlexPlugin implements Plugin {
|
||||
@Override
|
||||
public void start(AppContext context) throws Throwable {
|
||||
// 注册动态数据源的事务路由
|
||||
//TranManager.routing(FlexDataSource.class, new FlexDataSourceRouting());
|
||||
|
||||
flexProps = context.cfg().getProp(CONFIG_PREFIX);
|
||||
flexProperties = flexProps.toBean(MybatisFlexProperties.class);
|
||||
if (flexProperties == null) {
|
||||
flexProperties = new MybatisFlexProperties();
|
||||
MybatisFlexProperties flexProperties = context.beanMake(MybatisFlexProperties.class).get();
|
||||
|
||||
// 构建 flexProperties 配置的数据源(并推入应用上下文,可供其它工具使用)
|
||||
if (Utils.isNotEmpty(flexProperties.getDatasource())) {
|
||||
for (Map.Entry<String, Map<String, String>> entry : flexProperties.getDatasource().entrySet()) {
|
||||
String dsName = entry.getKey();
|
||||
DataSource ds = new DataSourceBuilder(entry.getValue()).build();
|
||||
BeanWrap bw = context.wrap(dsName, ds, dsName.equals(flexProperties.getDefaultDatasourceKey()));
|
||||
context.putWrap(dsName, bw);
|
||||
if (bw.typed()) {
|
||||
context.putWrap(DataSource.class, bw);
|
||||
}
|
||||
context.wrapPublish(bw);
|
||||
}
|
||||
}
|
||||
|
||||
// UseDataSource 拦截器(aop)
|
||||
context.beanInterceptorAdd(UseDataSource.class, new UseDataSourceInterceptor());
|
||||
|
||||
// 数据源解密器
|
||||
context.getBeanAsync(DataSourceDecipher.class, bean -> {
|
||||
@ -110,24 +107,11 @@ public class XPluginImpl implements Plugin {
|
||||
if (NativeDetector.isAotRuntime() && ClassUtil.hasClass(() -> RuntimeNativeRegistrar.class)) {
|
||||
context.wrapAndPut(MybatisRuntimeNativeRegistrar.class);
|
||||
}
|
||||
}
|
||||
|
||||
// 构建 mf 配置的数据源
|
||||
if (Utils.isNotEmpty(flexProperties.getDatasource())) {
|
||||
for (Map.Entry<String, Map<String, String>> entry : flexProperties.getDatasource().entrySet()) {
|
||||
String dsName = entry.getKey();
|
||||
DataSource ds = new DataSourceBuilder(entry.getValue()).build();
|
||||
BeanWrap bw = context.wrap(dsName, ds, dsName.equals(flexProperties.getDefaultDatasourceKey()));
|
||||
context.putWrap(dsName, bw);
|
||||
if (bw.typed()) {
|
||||
context.putWrap(DataSource.class, bw);
|
||||
}
|
||||
context.wrapPublish(bw);
|
||||
}
|
||||
}
|
||||
}
|
||||
private AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
|
||||
private void loadDs(AppContext context, BeanWrap bw) {
|
||||
boolean isInit = MybatisFlexBootstrap.getInstance().getDataSource() == null;
|
||||
MybatisFlexBootstrap.getInstance().addDataSource(bw.name(), bw.raw());
|
||||
|
||||
if (bw.typed()) {
|
||||
@ -136,61 +120,9 @@ public class XPluginImpl implements Plugin {
|
||||
flexDataSource.setDefaultDataSource(bw.name());
|
||||
}
|
||||
|
||||
if (isInit) {
|
||||
initDo(context);
|
||||
if (initialized.compareAndSet(false, true)) {
|
||||
//有数据源后,再启动自动装配
|
||||
context.beanMake(MybatisFlexAutoConfiguration.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void initDo(AppContext context) {
|
||||
BeanWrap dsBw = context.wrap(FlexConsts.NAME, MybatisFlexBootstrap.getInstance().getDataSource(), true);
|
||||
MybatisAdapterFlex dsFlex = new MybatisAdapterFlex(dsBw, flexProps, flexProperties);
|
||||
dsFlex.mapperPublish();
|
||||
adapterFlex = dsFlex;
|
||||
|
||||
// 注册到管理器(aot 时会用到)
|
||||
//MybatisAdapterManager.register(dsBw, dsFlex);
|
||||
|
||||
//绑定到容器
|
||||
context.beanInjectorAdd(Inject.class, FlexGlobalConfig.class, ((vh, anno) -> {
|
||||
dsFlex.injectTo(vh);
|
||||
}));
|
||||
|
||||
|
||||
context.beanInjectorAdd(Inject.class, FlexConfiguration.class, ((vh, anno) -> {
|
||||
dsFlex.injectTo(vh);
|
||||
}));
|
||||
|
||||
context.beanInjectorAdd(Inject.class, RowMapperInvoker.class, ((vh, anno) -> {
|
||||
dsFlex.injectTo(vh);
|
||||
}));
|
||||
|
||||
context.beanInjectorAdd(Inject.class, SqlSessionFactory.class, ((vh, anno) -> {
|
||||
dsFlex.injectTo(vh);
|
||||
}));
|
||||
|
||||
context.beanInterceptorAdd(UseDataSource.class, inv -> {
|
||||
UseDataSource anno = inv.getMethodAnnotation(UseDataSource.class);
|
||||
|
||||
if (anno == null) {
|
||||
anno = inv.getTargetAnnotation(UseDataSource.class);
|
||||
}
|
||||
|
||||
if (anno == null) {
|
||||
return inv.invoke();
|
||||
} else {
|
||||
//备份
|
||||
String backup = DataSourceKey.get();
|
||||
|
||||
try {
|
||||
String dsName = TmplUtil.parse(anno.value(), inv);
|
||||
|
||||
DataSourceKey.use(dsName);
|
||||
return inv.invoke();
|
||||
} finally {
|
||||
//还原
|
||||
DataSourceKey.use(backup);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,351 +0,0 @@
|
||||
package com.mybatisflex.solon.mybtais;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
|
||||
import org.apache.ibatis.executor.ErrorContext;
|
||||
import org.apache.ibatis.io.Resources;
|
||||
import org.apache.ibatis.mapping.Environment;
|
||||
import org.apache.ibatis.plugin.Interceptor;
|
||||
import org.apache.ibatis.session.Configuration;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
|
||||
import org.apache.ibatis.transaction.TransactionFactory;
|
||||
import org.apache.ibatis.type.TypeHandler;
|
||||
import org.noear.solon.Utils;
|
||||
import org.noear.solon.core.BeanWrap;
|
||||
import org.noear.solon.core.LifecycleIndex;
|
||||
import org.noear.solon.core.Props;
|
||||
import org.noear.solon.core.VarHolder;
|
||||
import org.noear.solon.core.event.EventBus;
|
||||
import org.noear.solon.core.util.ResourceUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Mybatis 适配器默认实现
|
||||
*
|
||||
* @author noear
|
||||
* @since 1.1
|
||||
*/
|
||||
public class MybatisAdapterDefault {
|
||||
protected static final Logger log = LoggerFactory.getLogger(MybatisAdapterDefault.class);
|
||||
|
||||
protected BeanWrap dsWrap;
|
||||
protected Props dsProps;
|
||||
|
||||
//mapper 注解验证启用?
|
||||
protected boolean mapperVerifyEnabled;
|
||||
|
||||
protected Configuration config;
|
||||
protected SqlSessionFactory factory;
|
||||
protected List<String> mappers = new ArrayList<>();
|
||||
protected SqlSessionFactoryBuilder factoryBuilder;
|
||||
|
||||
/**
|
||||
* 构建Sql工厂适配器,使用属性配置
|
||||
*/
|
||||
protected void initStart(BeanWrap dsWrap, Props dsProps) {
|
||||
this.dsWrap = dsWrap;
|
||||
if (dsProps == null) {
|
||||
this.dsProps = new Props();
|
||||
} else {
|
||||
this.dsProps = dsProps;
|
||||
}
|
||||
|
||||
this.mapperVerifyEnabled = dsProps.getBool("configuration.mapperVerifyEnabled", false);
|
||||
this.factoryBuilder = new SqlSessionFactoryBuilder();
|
||||
|
||||
DataSource dataSource = getDataSource();
|
||||
String dataSourceId = dsWrap.name();
|
||||
if (Utils.isEmpty(dataSourceId)) {
|
||||
dataSourceId = "_main";
|
||||
}
|
||||
|
||||
TransactionFactory tf = new SolonManagedTransactionFactory();
|
||||
Environment environment = new Environment(dataSourceId, tf, dataSource);
|
||||
|
||||
//1.初始化配置器
|
||||
initConfiguration(environment);
|
||||
|
||||
//加载插件(通过Bean)
|
||||
dsWrap.context().lifecycle(LifecycleIndex.PLUGIN_BEAN_USES, () -> {
|
||||
dsWrap.context().beanForeach(bw -> {
|
||||
if (bw.raw() instanceof Interceptor) {
|
||||
config.addInterceptor(bw.raw());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//2.分发事件,推给扩展处理
|
||||
EventBus.publish(config);
|
||||
|
||||
//3.加载配置器的内容(顺序不能乱)
|
||||
loadConfiguration();
|
||||
|
||||
dsWrap.context().getBeanAsync(SqlSessionFactoryBuilder.class, bean -> {
|
||||
factoryBuilder = bean;
|
||||
});
|
||||
}
|
||||
|
||||
public List<String> getMappers() {
|
||||
return mappers;
|
||||
}
|
||||
|
||||
protected DataSource getDataSource() {
|
||||
return dsWrap.raw();
|
||||
}
|
||||
|
||||
protected void initConfiguration(Environment environment) {
|
||||
config = new Configuration(environment);
|
||||
|
||||
//for configuration section
|
||||
Props cfgProps = dsProps.getProp("configuration");
|
||||
if (cfgProps.size() > 0) {
|
||||
Utils.injectProperties(config, cfgProps);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isTypeAliasesType(Class<?> type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isTypeAliasesKey(String key) {
|
||||
return key.startsWith("typeAliases[") || key.equals("typeAliases");
|
||||
}
|
||||
|
||||
protected boolean isTypeHandlersKey(String key) {
|
||||
return key.startsWith("typeHandlers[") || key.equals("typeHandlers");
|
||||
}
|
||||
|
||||
protected boolean isMappersKey(String key) {
|
||||
return key.startsWith("mappers[") || key.equals("mappers");
|
||||
}
|
||||
|
||||
protected void loadConfiguration() {
|
||||
//for typeAliases & typeHandlers section
|
||||
dsProps.forEach((k, v) -> {
|
||||
if (k instanceof String && v instanceof String) {
|
||||
String key = (String) k;
|
||||
String valStr = (String) v;
|
||||
|
||||
if (isTypeAliasesKey(key)) {
|
||||
for (String val : valStr.split(",")) {
|
||||
val = val.trim();
|
||||
if (val.length() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//package || type class,转为类表达式
|
||||
for (Class<?> clz : ResourceUtil.scanClasses(dsWrap.context().getClassLoader(), val)) {
|
||||
if (clz.isInterface() == false) {
|
||||
if (isTypeAliasesType(clz)) {
|
||||
getConfiguration().getTypeAliasRegistry().registerAlias(clz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isTypeHandlersKey(key)) {
|
||||
for (String val : valStr.split(",")) {
|
||||
val = val.trim();
|
||||
if (val.length() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//package || type class,转为类表达式
|
||||
for (Class<?> clz : ResourceUtil.scanClasses(dsWrap.context().getClassLoader(), val)) {
|
||||
if (TypeHandler.class.isAssignableFrom(clz)) {
|
||||
getConfiguration().getTypeHandlerRegistry().register(clz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//todo: 上面的完成后,才能做下面这个
|
||||
|
||||
//for mappers section
|
||||
dsProps.forEach((k, v) -> {
|
||||
if (k instanceof String && v instanceof String) {
|
||||
String key = (String) k;
|
||||
String valStr = (String) v;
|
||||
|
||||
if (isMappersKey(key)) {
|
||||
for (String val : valStr.split(",")) {
|
||||
val = val.trim();
|
||||
if (val.length() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mappers.add(val);
|
||||
|
||||
if (ResourceUtil.hasClasspath(val)) {
|
||||
//mapper xml, 新方法,替代旧的 *.xml (基于表达式;更自由,更语义化)
|
||||
for (String uri : ResourceUtil.scanResources(val)) {
|
||||
addMapperByXml(uri);
|
||||
}
|
||||
|
||||
//todo: 兼容提醒:
|
||||
compatibilityTipsOfXml(val);
|
||||
} else {
|
||||
//package || type class,转为类表达式
|
||||
for (Class<?> clz : ResourceUtil.scanClasses(dsWrap.context().getClassLoader(), val)) {
|
||||
if (clz.isInterface()) {
|
||||
if (mapperVerifyEnabled) {
|
||||
if (isMapper(clz)) {
|
||||
getConfiguration().addMapper(clz);
|
||||
}
|
||||
} else {
|
||||
getConfiguration().addMapper(clz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (mappers.size() == 0) {
|
||||
if (Utils.isEmpty(dsWrap.name())) {
|
||||
log.warn("Mybatis: Missing mappers configuration!");
|
||||
} else {
|
||||
log.warn("Mybatis: Missing mappers configuration. name='{}'", dsWrap.name());
|
||||
}
|
||||
//throw new IllegalStateException("Please add the mappers configuration!");
|
||||
} else {
|
||||
//如果有配置,但是没有 mapper 注册成功;说明有问题了
|
||||
if (config.getMapperRegistry().getMappers().size() == 0) {
|
||||
//log.warn("Mybatis: Missing mapper registration, please check the mappers configuration!");
|
||||
if (Utils.isEmpty(dsWrap.name())) {
|
||||
throw new IllegalStateException("Missing mapper registration, please check the mappers configuration!");
|
||||
} else {
|
||||
throw new IllegalStateException("Missing mapper registration, please check the mappers configuration. name='" + dsWrap.name() + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//for plugins section
|
||||
List<Interceptor> interceptors = MybatisPluginUtils.resolve(dsProps, "plugins");
|
||||
for (Interceptor itp : interceptors) {
|
||||
getConfiguration().addInterceptor(itp);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isMapper(Class<?> clz) {
|
||||
return clz.isAnnotationPresent(Mapper.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置器
|
||||
*/
|
||||
public Configuration getConfiguration() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会话工厂
|
||||
*/
|
||||
public SqlSessionFactory getFactory() {
|
||||
if (factory == null) {
|
||||
factory = factoryBuilder.build(getConfiguration());//new SqlSessionFactoryProxy(factoryBuilder.build(config));
|
||||
}
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
Map<Class<?>, Object> mapperCached = new HashMap<>();
|
||||
|
||||
public <T> T getMapper(Class<T> mapperClz) {
|
||||
Object mapper = mapperCached.get(mapperClz);
|
||||
|
||||
if (mapper == null) {
|
||||
synchronized (mapperClz) {
|
||||
mapper = mapperCached.get(mapperClz);
|
||||
if (mapper == null) {
|
||||
MybatisMapperInterceptor handler = new MybatisMapperInterceptor(getFactory(), mapperClz);
|
||||
|
||||
mapper = Proxy.newProxyInstance(
|
||||
mapperClz.getClassLoader(),
|
||||
new Class[]{mapperClz},
|
||||
handler);
|
||||
mapperCached.put(mapperClz, mapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (T) mapper;
|
||||
}
|
||||
|
||||
public void injectTo(VarHolder vh) {
|
||||
//@Db("db1") SqlSessionFactory factory;
|
||||
if (SqlSessionFactory.class.isAssignableFrom(vh.getType())) {
|
||||
vh.setValue(this.getFactory());
|
||||
return;
|
||||
}
|
||||
|
||||
//@Db("db1") Configuration cfg;
|
||||
if (Configuration.class.isAssignableFrom(vh.getType())) {
|
||||
vh.setValue(this.getConfiguration());
|
||||
return;
|
||||
}
|
||||
|
||||
//@Db("db1") UserMapper userMapper;
|
||||
if (vh.getType().isInterface()) {
|
||||
Object mapper = this.getMapper(vh.getType());
|
||||
|
||||
vh.setValue(mapper);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected void addMapperByXml(String uri) {
|
||||
try {
|
||||
// resource 配置方式
|
||||
ErrorContext.instance().resource(uri);
|
||||
|
||||
//读取mapper文件
|
||||
InputStream stream = Resources.getResourceAsStream(uri);
|
||||
|
||||
//mapper映射文件都是通过XMLMapperBuilder解析
|
||||
XMLMapperBuilder mapperParser = new XMLMapperBuilder(stream, getConfiguration(), uri, getConfiguration().getSqlFragments());
|
||||
mapperParser.parse();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void compatibilityTipsOfXml(String val) {
|
||||
//todo: 兼容提醒:
|
||||
//if (val.endsWith("*.xml") && val.indexOf("*") == val.indexOf("*.xml")) {
|
||||
//@Deprecated //弃用提示
|
||||
// log.warn("Mybatis-新文件表达式提示:'" + val + "' 不包括深度子目录;如有需要可增加'/**/'段");
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
public void mapperPublish() {
|
||||
for (Class<?> clz : getConfiguration().getMapperRegistry().getMappers()) {
|
||||
mapperPublishDo(clz);
|
||||
}
|
||||
}
|
||||
|
||||
private void mapperPublishDo(Class<?> clz) {
|
||||
if (clz != null && clz.isInterface()) {
|
||||
Object mapper = getMapper(clz);
|
||||
|
||||
//进入容器,用于 @Inject 注入
|
||||
dsWrap.context().wrapAndPut(clz, mapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
package com.mybatisflex.solon.mybtais;
|
||||
|
||||
import org.apache.ibatis.plugin.Interceptor;
|
||||
import org.noear.solon.core.Props;
|
||||
import org.noear.solon.core.util.ClassUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 插件解析工具
|
||||
*
|
||||
* @author noear
|
||||
* @since 1.10
|
||||
*/
|
||||
public class MybatisPluginUtils {
|
||||
/**
|
||||
* 解析
|
||||
*
|
||||
* @param prefix 配置前缀
|
||||
*/
|
||||
public static List<Interceptor> resolve(Props configRoot, String prefix) {
|
||||
List<Interceptor> interceptors = new ArrayList<>();
|
||||
|
||||
int index = 0;
|
||||
while (true) {
|
||||
Props props = configRoot.getProp(prefix + "[" + index + "]");
|
||||
if (props.size() == 0) {
|
||||
break;
|
||||
} else {
|
||||
index++;
|
||||
|
||||
String name = null;
|
||||
for (Map.Entry kv : props.entrySet()) {
|
||||
if (kv.getKey() instanceof String) {
|
||||
String key = (String) kv.getKey();
|
||||
if (key.endsWith(".class")) {
|
||||
name = key.split("\\.")[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (name != null) {
|
||||
props = props.getProp(name);
|
||||
Interceptor plugin = ClassUtil.tryInstance(props.get("class"));
|
||||
if (plugin == null) {
|
||||
throw new IllegalArgumentException("Mybatis plugin [" + name + "].class load failed");
|
||||
}
|
||||
props.remove("class");
|
||||
|
||||
plugin.setProperties(props);
|
||||
interceptors.add(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return interceptors;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.mybatisflex.solon.mybtais;
|
||||
package com.mybatisflex.solon.transaction;
|
||||
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
@ -1,4 +1,4 @@
|
||||
package com.mybatisflex.solon.mybtais;
|
||||
package com.mybatisflex.solon.transaction;
|
||||
|
||||
import com.mybatisflex.core.datasource.FlexDataSourceRouting;
|
||||
import org.apache.ibatis.transaction.Transaction;
|
||||
@ -1,4 +1,4 @@
|
||||
package com.mybatisflex.solon.mybtais;
|
||||
package com.mybatisflex.solon.transaction;
|
||||
|
||||
import org.apache.ibatis.session.TransactionIsolationLevel;
|
||||
import org.apache.ibatis.transaction.Transaction;
|
||||
@ -1,2 +1,2 @@
|
||||
solon.plugin=com.mybatisflex.solon.integration.XPluginImpl
|
||||
solon.plugin.priority=3
|
||||
solon.plugin=com.mybatisflex.solon.integration.MybatisFlexPlugin
|
||||
solon.plugin.priority=5
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
package com.mybatisflex.solon.demo;
|
||||
|
||||
import com.mybatisflex.core.FlexGlobalConfig;
|
||||
import com.mybatisflex.core.mybatis.FlexConfiguration;
|
||||
import com.mybatisflex.solon.ConfigurationCustomizer;
|
||||
import com.mybatisflex.solon.MyBatisFlexCustomizer;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
/**
|
||||
* @author noear 2024/12/17 created
|
||||
*/
|
||||
@Component
|
||||
public class MyBatisFlexCustomizerImpl implements MyBatisFlexCustomizer, ConfigurationCustomizer {
|
||||
@Override
|
||||
public void customize(FlexGlobalConfig globalConfig) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(FlexConfiguration configuration) {
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user