diff --git a/docs/graalvm-native-image.md b/docs/graalvm-native-image.md index 8f00860..256fa4f 100644 --- a/docs/graalvm-native-image.md +++ b/docs/graalvm-native-image.md @@ -67,7 +67,10 @@ src/main/resources/META-INF/native-image/ - `@MapperScan` 显式声明 `sqlSessionFactoryRef`,否则 AOT 丢 `AUTOWIRE_BY_TYPE` 装配; - `spring-cloud-starter-bootstrap` 与 AOT 不兼容,改用 `spring.config.import`; - MyBatis mapper 代理与实体由官方 `MyBatisNativeConfiguration` 模板的 AOT 处理器注册, - bean 名勿与 MP 自带的 `MyBatisPlusNativeImageConfiguration` 重复; + bean 名勿与 MP 自带的 `MyBatisPlusNativeImageConfiguration` 重复;Boot 4 模块用的 + mybatis-spring 4.1.0 已内置构造参数修正与 AOT 运行时跳过重复扫描(mybatis/spring#1238、 + #1239),模板因此只剩该处理器;`springboot3-sample` 解析到的 mybatis-spring 3.0.5 + 尚无这两处修复,保留完整模板; - `MySQLContainer` 的挂载问题见 testcontainers-java#7954(子类跳过挂载或用 `GenericContainer`); - ShardingSphere 用 `config-native.yaml`(算法与行表达式限制见官方文档),另需显式依赖 `javax.transaction-api`;其自带元数据在 JDBC 用法下多不生效,以本仓库条目为准; diff --git a/docs/upstream-todo.md b/docs/upstream-todo.md index e5f7d28..ee2ed04 100644 --- a/docs/upstream-todo.md +++ b/docs/upstream-todo.md @@ -9,6 +9,11 @@ - TODO https://github.com/spring-projects/spring-framework/issues/37500 :Spring AOT 保留 `autowireMode` 后,去掉各模块 `@MapperScan` 的 `sqlSessionFactoryRef` (逐模块去属性并跑 nativeTest 验证)。 +- TODO https://github.com/mybatis/spring/issues/1309 :mybatis-spring 内置 mapper 的 AOT + 处理器(为 mapper 接口注册反射、JDK 代理与同名 XML 等 hints)后,升级父 POM 的 + `mybatis-spring.version`,删除 Boot 4 各模块的 `MyBatisNativeConfiguration` 并逐模块跑 + nativeTest 验证;`springboot3-sample` 不必等此项:MP 3.5.17 起自带 + `mybatis-plus-spring-boot-native-image`,升级 MP 后即可删除其副本。 - TODO https://github.com/baomidou/dynamic-datasource/issues/809 :DD 补上 `@NestedConfigurationProperty` 或自带元数据后,删除各模块 `dynamic-datasource-creator` 目录下的 `DatasourceInitProperties` 条目。 diff --git a/spring-boot-4/druid-sample/src/main/java/com/baomidou/samples/druid/config/MyBatisNativeConfiguration.java b/spring-boot-4/druid-sample/src/main/java/com/baomidou/samples/druid/config/MyBatisNativeConfiguration.java index 0b5d43b..f26fe7a 100644 --- a/spring-boot-4/druid-sample/src/main/java/com/baomidou/samples/druid/config/MyBatisNativeConfiguration.java +++ b/spring-boot-4/druid-sample/src/main/java/com/baomidou/samples/druid/config/MyBatisNativeConfiguration.java @@ -19,81 +19,52 @@ import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.logging.LogFactory; import org.apache.ibatis.annotations.DeleteProvider; import org.apache.ibatis.annotations.InsertProvider; import org.apache.ibatis.annotations.SelectProvider; import org.apache.ibatis.annotations.UpdateProvider; import org.apache.ibatis.reflection.TypeParameterResolver; import org.mybatis.spring.mapper.MapperFactoryBean; -import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.RuntimeHints; import org.springframework.beans.PropertyValue; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; -import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter; import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.config.ConstructorArgumentValues; -import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; -import org.springframework.beans.factory.support.RegisteredBean; -import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.ResolvableType; -import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; /** * MyBatis 的 Spring AOT 集成。 * - *
取自 MyBatis 官方的 MyBatisNativeConfiguration 模板;静态的 GraalVM 元数据(日志实现、 缓存装饰器、dtd/xsd 资源等)已按依赖分目录改为
- * {@code META-INF/native-image/ 取自 MyBatis 官方的 MyBatisNativeConfiguration 模板;静态的 GraalVM 元数据(日志实现、缓存装饰器、dtd/xsd 资源等)已按依赖分目录改为
+ * {@code META-INF/native-image/ 模板中的 {@code MyBatisMapperFactoryBeanPostProcessor} 与对 {@code MapperScannerConfigurer} 的 AOT
+ * 排除已删除:mybatis-spring 4.1.0 起扫描器直接以 {@code Class} 登记 mapper 构造参数(mybatis/spring#1238),并在使用 AOT
+ * 产物运行时跳过重复扫描(mybatis/spring#1239)。该后处理器补齐的泛型 targetType 随之不再生成,native 运行时按类型匹配时会先实例化 {@code
+ * MapperFactoryBean}(只调用构造器)以取得 mapper 类型,nativeTest 实测无影响。
+ *
+ * 这里只保留 mybatis-spring 尚未内置、又无法用静态元数据表达的部分:{@code MyBatisBeanFactoryInitializationAotProcessor}
+ * 按 AOT 扫描结果为 mapper 接口注册反射、JDK 代理与同名 XML 资源,并为其方法的参数、返回值及 SQL Provider 类型注册反射。
*/
@Configuration(proxyBeanMethods = false)
public class MyBatisNativeConfiguration {
- @Bean
- static MyBatisMapperFactoryBeanPostProcessor myBatisMapperFactoryBeanPostProcessor() {
- return new MyBatisMapperFactoryBeanPostProcessor();
- }
-
@Bean
MyBatisBeanFactoryInitializationAotProcessor myBatisBeanFactoryInitializationAotProcessor() {
return new MyBatisBeanFactoryInitializationAotProcessor();
}
static class MyBatisBeanFactoryInitializationAotProcessor
- implements BeanFactoryInitializationAotProcessor, BeanRegistrationExcludeFilter {
-
- private final Set 向上下文暴露泛型类型信息以避免过早初始化;同时把构造参数重新注册为 {@code Class} 字面量——扫描器只会记录 mapper 类名字符串,这会使 AOT
- * 代码生成退回到 自动装配 {@code MapperFactoryBean} 构造器,native 测试下会尝试自动装配 {@code Class>}。
- */
- private void resolveMapperFactoryBeanTypeIfNecessary(RootBeanDefinition beanDefinition) {
- if (!beanDefinition.hasBeanClass()
- || !MapperFactoryBean.class.isAssignableFrom(beanDefinition.getBeanClass())) {
- return;
- }
- if (beanDefinition.getResolvableType().hasUnresolvableGenerics()) {
- Class> mapperInterface = getMapperInterface(beanDefinition);
- if (mapperInterface != null) {
- beanDefinition.setTargetType(
- ResolvableType.forClassWithGenerics(
- beanDefinition.getBeanClass(), mapperInterface));
- ConstructorArgumentValues constructorArgumentValues =
- new ConstructorArgumentValues();
- constructorArgumentValues.addGenericArgumentValue(mapperInterface);
- beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
- }
- }
- }
-
- private Class> getMapperInterface(RootBeanDefinition beanDefinition) {
- try {
- return (Class>) beanDefinition.getPropertyValues().get("mapperInterface");
- } catch (Exception e) {
- LOG.debug("Fail getting mapper interface type.", e);
- return null;
- }
- }
- }
}
diff --git a/spring-boot-4/mybatis-sample/src/main/java/com/baomidou/samples/mybatis/config/MyBatisNativeConfiguration.java b/spring-boot-4/mybatis-sample/src/main/java/com/baomidou/samples/mybatis/config/MyBatisNativeConfiguration.java
index 97ea16e..e9cff99 100644
--- a/spring-boot-4/mybatis-sample/src/main/java/com/baomidou/samples/mybatis/config/MyBatisNativeConfiguration.java
+++ b/spring-boot-4/mybatis-sample/src/main/java/com/baomidou/samples/mybatis/config/MyBatisNativeConfiguration.java
@@ -19,81 +19,52 @@
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
-import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;
import org.apache.ibatis.reflection.TypeParameterResolver;
import org.mybatis.spring.mapper.MapperFactoryBean;
-import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.beans.PropertyValue;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
-import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter;
import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.config.ConstructorArgumentValues;
-import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
-import org.springframework.beans.factory.support.RegisteredBean;
-import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.core.ResolvableType;
-import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* MyBatis 的 Spring AOT 集成。
*
- * 取自 MyBatis 官方的 MyBatisNativeConfiguration 模板;静态的 GraalVM 元数据(日志实现、 缓存装饰器、dtd/xsd 资源等)已按依赖分目录改为
- * {@code META-INF/native-image/ 取自 MyBatis 官方的 MyBatisNativeConfiguration 模板;静态的 GraalVM 元数据(日志实现、缓存装饰器、dtd/xsd 资源等)已按依赖分目录改为
+ * {@code META-INF/native-image/ 模板中的 {@code MyBatisMapperFactoryBeanPostProcessor} 与对 {@code MapperScannerConfigurer} 的 AOT
+ * 排除已删除:mybatis-spring 4.1.0 起扫描器直接以 {@code Class} 登记 mapper 构造参数(mybatis/spring#1238),并在使用 AOT
+ * 产物运行时跳过重复扫描(mybatis/spring#1239)。该后处理器补齐的泛型 targetType 随之不再生成,native 运行时按类型匹配时会先实例化 {@code
+ * MapperFactoryBean}(只调用构造器)以取得 mapper 类型,nativeTest 实测无影响。
+ *
+ * 这里只保留 mybatis-spring 尚未内置、又无法用静态元数据表达的部分:{@code MyBatisBeanFactoryInitializationAotProcessor}
+ * 按 AOT 扫描结果为 mapper 接口注册反射、JDK 代理与同名 XML 资源,并为其方法的参数、返回值及 SQL Provider 类型注册反射。
*/
@Configuration(proxyBeanMethods = false)
public class MyBatisNativeConfiguration {
- @Bean
- static MyBatisMapperFactoryBeanPostProcessor myBatisMapperFactoryBeanPostProcessor() {
- return new MyBatisMapperFactoryBeanPostProcessor();
- }
-
@Bean
MyBatisBeanFactoryInitializationAotProcessor myBatisBeanFactoryInitializationAotProcessor() {
return new MyBatisBeanFactoryInitializationAotProcessor();
}
static class MyBatisBeanFactoryInitializationAotProcessor
- implements BeanFactoryInitializationAotProcessor, BeanRegistrationExcludeFilter {
-
- private final Set 向上下文暴露泛型类型信息以避免过早初始化;同时把构造参数重新注册为 {@code Class} 字面量——扫描器只会记录 mapper 类名字符串,这会使 AOT
- * 代码生成退回到 自动装配 {@code MapperFactoryBean} 构造器,native 测试下会尝试自动装配 {@code Class>}。
- */
- private void resolveMapperFactoryBeanTypeIfNecessary(RootBeanDefinition beanDefinition) {
- if (!beanDefinition.hasBeanClass()
- || !MapperFactoryBean.class.isAssignableFrom(beanDefinition.getBeanClass())) {
- return;
- }
- if (beanDefinition.getResolvableType().hasUnresolvableGenerics()) {
- Class> mapperInterface = getMapperInterface(beanDefinition);
- if (mapperInterface != null) {
- beanDefinition.setTargetType(
- ResolvableType.forClassWithGenerics(
- beanDefinition.getBeanClass(), mapperInterface));
- ConstructorArgumentValues constructorArgumentValues =
- new ConstructorArgumentValues();
- constructorArgumentValues.addGenericArgumentValue(mapperInterface);
- beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
- }
- }
- }
-
- private Class> getMapperInterface(RootBeanDefinition beanDefinition) {
- try {
- return (Class>) beanDefinition.getPropertyValues().get("mapperInterface");
- } catch (Exception e) {
- LOG.debug("Fail getting mapper interface type.", e);
- return null;
- }
- }
- }
}
diff --git a/spring-boot-4/name-pattern-sample/src/main/java/com/baomidou/samples/pattern/config/MyBatisNativeConfiguration.java b/spring-boot-4/name-pattern-sample/src/main/java/com/baomidou/samples/pattern/config/MyBatisNativeConfiguration.java
index 8006a80..6efcbf4 100644
--- a/spring-boot-4/name-pattern-sample/src/main/java/com/baomidou/samples/pattern/config/MyBatisNativeConfiguration.java
+++ b/spring-boot-4/name-pattern-sample/src/main/java/com/baomidou/samples/pattern/config/MyBatisNativeConfiguration.java
@@ -19,81 +19,52 @@
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
-import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;
import org.apache.ibatis.reflection.TypeParameterResolver;
import org.mybatis.spring.mapper.MapperFactoryBean;
-import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.beans.PropertyValue;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
-import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter;
import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.config.ConstructorArgumentValues;
-import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
-import org.springframework.beans.factory.support.RegisteredBean;
-import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.core.ResolvableType;
-import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* MyBatis 的 Spring AOT 集成。
*
- * 取自 MyBatis 官方的 MyBatisNativeConfiguration 模板;静态的 GraalVM 元数据(日志实现、 缓存装饰器、dtd/xsd 资源等)已按依赖分目录改为
- * {@code META-INF/native-image/ 取自 MyBatis 官方的 MyBatisNativeConfiguration 模板;静态的 GraalVM 元数据(日志实现、缓存装饰器、dtd/xsd 资源等)已按依赖分目录改为
+ * {@code META-INF/native-image/ 模板中的 {@code MyBatisMapperFactoryBeanPostProcessor} 与对 {@code MapperScannerConfigurer} 的 AOT
+ * 排除已删除:mybatis-spring 4.1.0 起扫描器直接以 {@code Class} 登记 mapper 构造参数(mybatis/spring#1238),并在使用 AOT
+ * 产物运行时跳过重复扫描(mybatis/spring#1239)。该后处理器补齐的泛型 targetType 随之不再生成,native 运行时按类型匹配时会先实例化 {@code
+ * MapperFactoryBean}(只调用构造器)以取得 mapper 类型,nativeTest 实测无影响。
+ *
+ * 这里只保留 mybatis-spring 尚未内置、又无法用静态元数据表达的部分:{@code MyBatisBeanFactoryInitializationAotProcessor}
+ * 按 AOT 扫描结果为 mapper 接口注册反射、JDK 代理与同名 XML 资源,并为其方法的参数、返回值及 SQL Provider 类型注册反射。
*/
@Configuration(proxyBeanMethods = false)
public class MyBatisNativeConfiguration {
- @Bean
- static MyBatisMapperFactoryBeanPostProcessor myBatisMapperFactoryBeanPostProcessor() {
- return new MyBatisMapperFactoryBeanPostProcessor();
- }
-
@Bean
MyBatisBeanFactoryInitializationAotProcessor myBatisBeanFactoryInitializationAotProcessor() {
return new MyBatisBeanFactoryInitializationAotProcessor();
}
static class MyBatisBeanFactoryInitializationAotProcessor
- implements BeanFactoryInitializationAotProcessor, BeanRegistrationExcludeFilter {
-
- private final Set 向上下文暴露泛型类型信息以避免过早初始化;同时把构造参数重新注册为 {@code Class} 字面量——扫描器只会记录 mapper 类名字符串,这会使 AOT
- * 代码生成退回到 自动装配 {@code MapperFactoryBean} 构造器,native 测试下会尝试自动装配 {@code Class>}。
- */
- private void resolveMapperFactoryBeanTypeIfNecessary(RootBeanDefinition beanDefinition) {
- if (!beanDefinition.hasBeanClass()
- || !MapperFactoryBean.class.isAssignableFrom(beanDefinition.getBeanClass())) {
- return;
- }
- if (beanDefinition.getResolvableType().hasUnresolvableGenerics()) {
- Class> mapperInterface = getMapperInterface(beanDefinition);
- if (mapperInterface != null) {
- beanDefinition.setTargetType(
- ResolvableType.forClassWithGenerics(
- beanDefinition.getBeanClass(), mapperInterface));
- ConstructorArgumentValues constructorArgumentValues =
- new ConstructorArgumentValues();
- constructorArgumentValues.addGenericArgumentValue(mapperInterface);
- beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
- }
- }
- }
-
- private Class> getMapperInterface(RootBeanDefinition beanDefinition) {
- try {
- return (Class>) beanDefinition.getPropertyValues().get("mapperInterface");
- } catch (Exception e) {
- LOG.debug("Fail getting mapper interface type.", e);
- return null;
- }
- }
- }
}
diff --git a/spring-boot-4/shardingsphere-jdbc-5.x-core-sample/src/main/java/com/baomidou/samples/shardingsphere/jdbc/v5/core/config/MyBatisNativeConfiguration.java b/spring-boot-4/shardingsphere-jdbc-5.x-core-sample/src/main/java/com/baomidou/samples/shardingsphere/jdbc/v5/core/config/MyBatisNativeConfiguration.java
index 3f031ea..61e93ba 100644
--- a/spring-boot-4/shardingsphere-jdbc-5.x-core-sample/src/main/java/com/baomidou/samples/shardingsphere/jdbc/v5/core/config/MyBatisNativeConfiguration.java
+++ b/spring-boot-4/shardingsphere-jdbc-5.x-core-sample/src/main/java/com/baomidou/samples/shardingsphere/jdbc/v5/core/config/MyBatisNativeConfiguration.java
@@ -19,81 +19,52 @@
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
-import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;
import org.apache.ibatis.reflection.TypeParameterResolver;
import org.mybatis.spring.mapper.MapperFactoryBean;
-import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.beans.PropertyValue;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
-import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter;
import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.config.ConstructorArgumentValues;
-import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
-import org.springframework.beans.factory.support.RegisteredBean;
-import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.core.ResolvableType;
-import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* MyBatis 的 Spring AOT 集成。
*
- * 取自 MyBatis 官方的 MyBatisNativeConfiguration 模板;静态的 GraalVM 元数据(日志实现、 缓存装饰器、dtd/xsd 资源等)已按依赖分目录改为
- * {@code META-INF/native-image/ 取自 MyBatis 官方的 MyBatisNativeConfiguration 模板;静态的 GraalVM 元数据(日志实现、缓存装饰器、dtd/xsd 资源等)已按依赖分目录改为
+ * {@code META-INF/native-image/ 模板中的 {@code MyBatisMapperFactoryBeanPostProcessor} 与对 {@code MapperScannerConfigurer} 的 AOT
+ * 排除已删除:mybatis-spring 4.1.0 起扫描器直接以 {@code Class} 登记 mapper 构造参数(mybatis/spring#1238),并在使用 AOT
+ * 产物运行时跳过重复扫描(mybatis/spring#1239)。该后处理器补齐的泛型 targetType 随之不再生成,native 运行时按类型匹配时会先实例化 {@code
+ * MapperFactoryBean}(只调用构造器)以取得 mapper 类型,nativeTest 实测无影响。
+ *
+ * 这里只保留 mybatis-spring 尚未内置、又无法用静态元数据表达的部分:{@code MyBatisBeanFactoryInitializationAotProcessor}
+ * 按 AOT 扫描结果为 mapper 接口注册反射、JDK 代理与同名 XML 资源,并为其方法的参数、返回值及 SQL Provider 类型注册反射。
*/
@Configuration(proxyBeanMethods = false)
public class MyBatisNativeConfiguration {
- @Bean
- static MyBatisMapperFactoryBeanPostProcessor myBatisMapperFactoryBeanPostProcessor() {
- return new MyBatisMapperFactoryBeanPostProcessor();
- }
-
@Bean
MyBatisBeanFactoryInitializationAotProcessor myBatisBeanFactoryInitializationAotProcessor() {
return new MyBatisBeanFactoryInitializationAotProcessor();
}
static class MyBatisBeanFactoryInitializationAotProcessor
- implements BeanFactoryInitializationAotProcessor, BeanRegistrationExcludeFilter {
-
- private final Set 向上下文暴露泛型类型信息以避免过早初始化;同时把构造参数重新注册为 {@code Class} 字面量——扫描器只会记录 mapper 类名字符串,这会使 AOT
- * 代码生成退回到 自动装配 {@code MapperFactoryBean} 构造器,native 测试下会尝试自动装配 {@code Class>}。
- */
- private void resolveMapperFactoryBeanTypeIfNecessary(RootBeanDefinition beanDefinition) {
- if (!beanDefinition.hasBeanClass()
- || !MapperFactoryBean.class.isAssignableFrom(beanDefinition.getBeanClass())) {
- return;
- }
- if (beanDefinition.getResolvableType().hasUnresolvableGenerics()) {
- Class> mapperInterface = getMapperInterface(beanDefinition);
- if (mapperInterface != null) {
- beanDefinition.setTargetType(
- ResolvableType.forClassWithGenerics(
- beanDefinition.getBeanClass(), mapperInterface));
- ConstructorArgumentValues constructorArgumentValues =
- new ConstructorArgumentValues();
- constructorArgumentValues.addGenericArgumentValue(mapperInterface);
- beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
- }
- }
- }
-
- private Class> getMapperInterface(RootBeanDefinition beanDefinition) {
- try {
- return (Class>) beanDefinition.getPropertyValues().get("mapperInterface");
- } catch (Exception e) {
- LOG.debug("Fail getting mapper interface type.", e);
- return null;
- }
- }
- }
}
diff --git a/spring-boot-4/spel-sample/src/main/java/com/baomidou/samples/spel/config/MyBatisNativeConfiguration.java b/spring-boot-4/spel-sample/src/main/java/com/baomidou/samples/spel/config/MyBatisNativeConfiguration.java
index e7322a3..88cdb89 100644
--- a/spring-boot-4/spel-sample/src/main/java/com/baomidou/samples/spel/config/MyBatisNativeConfiguration.java
+++ b/spring-boot-4/spel-sample/src/main/java/com/baomidou/samples/spel/config/MyBatisNativeConfiguration.java
@@ -19,81 +19,52 @@
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
-import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;
import org.apache.ibatis.reflection.TypeParameterResolver;
import org.mybatis.spring.mapper.MapperFactoryBean;
-import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.beans.PropertyValue;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
-import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter;
import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.config.ConstructorArgumentValues;
-import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
-import org.springframework.beans.factory.support.RegisteredBean;
-import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.core.ResolvableType;
-import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* MyBatis 的 Spring AOT 集成。
*
- * 取自 MyBatis 官方的 MyBatisNativeConfiguration 模板;静态的 GraalVM 元数据(日志实现、 缓存装饰器、dtd/xsd 资源等)已按依赖分目录改为
- * {@code META-INF/native-image/ 取自 MyBatis 官方的 MyBatisNativeConfiguration 模板;静态的 GraalVM 元数据(日志实现、缓存装饰器、dtd/xsd 资源等)已按依赖分目录改为
+ * {@code META-INF/native-image/ 模板中的 {@code MyBatisMapperFactoryBeanPostProcessor} 与对 {@code MapperScannerConfigurer} 的 AOT
+ * 排除已删除:mybatis-spring 4.1.0 起扫描器直接以 {@code Class} 登记 mapper 构造参数(mybatis/spring#1238),并在使用 AOT
+ * 产物运行时跳过重复扫描(mybatis/spring#1239)。该后处理器补齐的泛型 targetType 随之不再生成,native 运行时按类型匹配时会先实例化 {@code
+ * MapperFactoryBean}(只调用构造器)以取得 mapper 类型,nativeTest 实测无影响。
+ *
+ * 这里只保留 mybatis-spring 尚未内置、又无法用静态元数据表达的部分:{@code MyBatisBeanFactoryInitializationAotProcessor}
+ * 按 AOT 扫描结果为 mapper 接口注册反射、JDK 代理与同名 XML 资源,并为其方法的参数、返回值及 SQL Provider 类型注册反射。
*/
@Configuration(proxyBeanMethods = false)
public class MyBatisNativeConfiguration {
- @Bean
- static MyBatisMapperFactoryBeanPostProcessor myBatisMapperFactoryBeanPostProcessor() {
- return new MyBatisMapperFactoryBeanPostProcessor();
- }
-
@Bean
MyBatisBeanFactoryInitializationAotProcessor myBatisBeanFactoryInitializationAotProcessor() {
return new MyBatisBeanFactoryInitializationAotProcessor();
}
static class MyBatisBeanFactoryInitializationAotProcessor
- implements BeanFactoryInitializationAotProcessor, BeanRegistrationExcludeFilter {
-
- private final Set 向上下文暴露泛型类型信息以避免过早初始化;同时把构造参数重新注册为 {@code Class} 字面量——扫描器只会记录 mapper 类名字符串,这会使 AOT
- * 代码生成退回到 自动装配 {@code MapperFactoryBean} 构造器,native 测试下会尝试自动装配 {@code Class>}。
- */
- private void resolveMapperFactoryBeanTypeIfNecessary(RootBeanDefinition beanDefinition) {
- if (!beanDefinition.hasBeanClass()
- || !MapperFactoryBean.class.isAssignableFrom(beanDefinition.getBeanClass())) {
- return;
- }
- if (beanDefinition.getResolvableType().hasUnresolvableGenerics()) {
- Class> mapperInterface = getMapperInterface(beanDefinition);
- if (mapperInterface != null) {
- beanDefinition.setTargetType(
- ResolvableType.forClassWithGenerics(
- beanDefinition.getBeanClass(), mapperInterface));
- ConstructorArgumentValues constructorArgumentValues =
- new ConstructorArgumentValues();
- constructorArgumentValues.addGenericArgumentValue(mapperInterface);
- beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
- }
- }
- }
-
- private Class> getMapperInterface(RootBeanDefinition beanDefinition) {
- try {
- return (Class>) beanDefinition.getPropertyValues().get("mapperInterface");
- } catch (Exception e) {
- LOG.debug("Fail getting mapper interface type.", e);
- return null;
- }
- }
- }
}
- *
+ *
- *
+ *
- *
+ *
- *
+ *
- *
+ *