Spring3新特性:graalvm打包Springboot+Mybatis

Spring3新特性

graalvm打包Springboot+Mybatis

项目源代码

https://github.com/cmdch2017/SpringNative_Graalvm_Mybatis
Spring3新特性:graalvm打包Springboot+Mybatis_第1张图片

如何安装与运行

安装graalvm与配置环境

首先安装步骤参考这篇博客
https://blog.csdn.net/weixin_38943666/article/details/129505945
其次如何处理反射
https://blog.csdn.net/qq_32740973/article/details/131799510
Spring3新特性:graalvm打包Springboot+Mybatis_第2张图片

运行核心步骤

Spring3新特性:graalvm打包Springboot+Mybatis_第3张图片

1、如上图所示,点击mvn clean

2、如上图所示,点击mvn compile

3、执行反射编译语句
java -agentlib:native-image-agent=config-output-dir=C:\Demos\graalvm\src\main\resources\META-INF\native-image  -jar .\target\graalvm-0.0.1-SNAPSHOT.jar 

4、打开 x64 Native Toogls Command Prompt for VS 并 cd到项目文件夹
mvn -Pnative -DskipTests clean native:compile

5、PowerShell中进入项目target目录下
.\graalvm.exe

遇到的零散问题

问题1

org.apache.catalina.LifecycleException: An invalid Lifecycle transition was attempted ([before_stop]) for componentSpring3新特性:graalvm打包Springboot+Mybatis_第4张图片
用不了反射,所以需要这个文件去

package org.wxy.example.sqlite.config;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import cn.hutool.core.util.ClassUtil;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;




/**
 * 反射将所有项目类扫描加入到服务, 大力出奇迹的操作,感觉不太合适,不过先让服务跑起来
 *
 * @author PC
 *
 */
@Component
public class ClassReflectConfig {

	static boolean begin = true;

//	@Value("${scanclass}")
	private Boolean scanclass=true;

	@Autowired
	private ThreadPoolTaskExecutor executorService;

	@PostConstruct
	public void init() {

		if (scanclass) {
			System.err.println("配置文件下 scanclass 开启了生成反射类");
		} else {
			System.err.println("配置文件下 scanclass 关闭了生成反射类");
		}

		synchronized (ClassReflectConfig.class) {
			if (begin && scanclass) {
				begin = false;
				executorService.submit(() -> {
					{
						// 扫描系统第二级开始的包
						String packageName = ClassReflectConfig.class.getPackageName();
						String proPackageName = packageName.substring(0,
								packageName.indexOf(".", packageName.indexOf(".") + 1));

						// 可以在这个地方,添加除了服务以外其他的包,将会加入反射,以供graalvm生成配置
						List<String> asList = Arrays.asList(proPackageName);

						for (String spn : asList) {
							try {
								Set<Class<?>> doScan = ClassUtil.scanPackage(spn);
								for (Class clazz : doScan) {
									handlerClass(clazz);
								}
							} catch (Throwable e) {
								e.printStackTrace();
							}
						}
					}
				});
			}
		}


	}

	private void handlerClass(Class clazz) {
		if (clazz.equals(ClassReflectConfig.class)) {
			// 跳过自己,避免形成循环
			return;
		}

		executorService.submit(() -> {
			try {
				System.err.println("反射注入:" + clazz.getName());
				// 生成所有的构造器
				Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
				// 找到无参构造器然后实例化
				Constructor declaredConstructor = clazz.getDeclaredConstructor();
				declaredConstructor.setAccessible(true);
				Object newInstance = declaredConstructor.newInstance();
				Method[] methods = clazz.getDeclaredMethods();
				for (Method method : methods) {
					try {
						// 实例化成功,那么调用一下
						method.setAccessible(true);
						// graalvm必须需要声明方法
						method.invoke(newInstance);
					} catch (Throwable e) {
					}
				}
				Field[] fields = clazz.getDeclaredFields();
				for (Field field : fields) {
					try {
						field.setAccessible(true);
						field.getType();
						String name = field.getName();
						field.get(newInstance);

					} catch (Throwable e) {
					}
				}
				System.err.println("反射注入完成:" + clazz.getName());
			} catch (Throwable e) {
			}
		});
	}

}

之后报错信息

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sqliteController': Unsatisfied dependency expressed through field 'personService': Error creating bean with name 'personService': Unsatisfied dependency expressed through field 'dao': Error creating bean with name 'personMapper': Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
        at org.springframework.beans.factory.aot.AutowiredFieldValueResolver.resolveValue(AutowiredFieldValueResolver.java:195) ~[na:na]
        at org.springframework.beans.factory.aot.AutowiredFieldValueResolver.resolveObject(AutowiredFieldValueResolver.java:154) ~[na:na]
        at org.springframework.beans.factory.aot.AutowiredFieldValueResolver.resolve(AutowiredFieldValueResolver.java:143) ~[na:na]
        at org.wxy.example.sqlite.controllers.SqliteController__Autowiring.apply(SqliteController__Autowiring.java:14) ~[na:na]
        at org.springframework.beans.factory.support.InstanceSupplier$1.get(InstanceSupplier.java:83) ~[na:na]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.obtainInstanceFromSupplier(DefaultListableBeanFactory.java:947) ~[mysqlandmybatis.exe:6.0.8]

问题2 报错信息提示无法读取外部 DTD ‘mybatis-3-mapper.dtd’

无法读取外部 DTD ‘mybatis-3-mapper.dtd’, 因为 accessExternalDTD 属性设置的限制导致不允许 ‘http’ 访问。

允许对 ‘http’ 的访问:
如果你确定从 ‘http’ 地址下载 DTD 文件是安全的,可以配置解析器以允许对 ‘http’ 的访问。在SpringbootApplication 中,可以使用以下代码:

System.setProperty("javax.xml.accessExternalDTD", "all");

Spring3新特性:graalvm打包Springboot+Mybatis_第5张图片

问题3 exe文件闪退日志

用powerShell打开

问题4 报错信息有提示http

加上支持http协议的参数

  <build>
    <plugins>
      <plugin>
        <groupId>org.graalvm.buildtoolsgroupId>
        <artifactId>native-maven-pluginartifactId>
        <configuration>
          <buildArgs combine.children="append">
            <buildArg>--enable-url-protocols=httpbuildArg>
          buildArgs>
        configuration>
      plugin>
      <plugin>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-maven-pluginartifactId>
      plugin>
    plugins>
  build>


  <repositories>
    <repository>
      <id>sonatype-oss-snapshotsid>
      <name>Sonatype OSS Snapshots Repositoryname>
      <url>https://oss.sonatype.org/content/repositories/snapshotsurl>
    repository>
  repositories>

问题5 RestController层的问题

org.apache.catalina.LifecycleException: An invalid Lifecycle transition was attempted ([before_stop]) for component [StandardEngine[Tomcat]] in state [INITIALIZED]
        at org.apache.catalina.util.LifecycleBase.invalidTransition(LifecycleBase.java:430) ~[mysqlandmybatis.exe:10.1.8]
        at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:244) ~[mysqlandmybatis.exe:10.1.8]
        at org.apache.catalina.core.StandardService.stopInternal(StandardService.java:491) ~[na:na]
        at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:257) ~[mysqlandmybatis.exe:10.1.8]
        at org.apache.catalina.core.StandardServer.stopInternal(StandardServer.java:966) ~[na:na]
        at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:257) ~[mysqlandmybatis.exe:10.1.8]
        at org.apache.catalina.util.LifecycleBase.destroy(LifecycleBase.java:293) ~[mysqlandmybatis.exe:10.1.8]
        at org.apache.catalina.startup.Tomcat.destroy(Tomcat.java:507) ~[mysqlandmybatis.exe:10.1.8]
        at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.destroySilently(TomcatWebServer.java:262) ~[mysqlandmybatis.exe:3.0.6]
        at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:141) ~[mysqlandmybatis.exe:3.0.6]
        at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:104) ~[mysqlandmybatis.exe:3.0.6]
        at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:488) ~[mysqlandmybatis.exe:3.0.6]

Spring3新特性:graalvm打包Springboot+Mybatis_第6张图片
或者是下面的Controller层报错
Spring3新特性:graalvm打包Springboot+Mybatis_第7张图片
原因是你没按照网上的教程来,在加了问题1的ClassReflectConfig 内容后,mvn -Pnative -DskipTests clean native:compile之后,你得执行以下语句,注意这里C:\Demos\springboot3-demo3-master\src\main\resources\META-INF\native-image还有.\target\springboot3-demo3-0.0.1-SNAPSHOT.jar的路径看你项目中的路径

java -agentlib:native-image-agent=config-output-dir=C:\Demos\springboot3-demo3-master\src\main\resources\META-INF\native-image  -jar  .\target\springboot3-demo3-0.0.1-SNAPSHOT.jar

Spring3新特性:graalvm打包Springboot+Mybatis_第8张图片

问题6 Mapper层问题

Spring3新特性:graalvm打包Springboot+Mybatis_第9张图片
检查yml文件中是否配置好了

mybatis:
  mapper-locations: classpath:mapper/*.xml
  typeAliasesPackage: org.wxy.example.*.model

问题7 只支持mybaits,不支持mybatis-plus

mybatis-plus暂不支持,官方也回应暂时没有计划支持graalvm

问题8 报错信息中有sqlSessionFactory

@MapperScan(basePackages ="org.wxy.example.*.mapper",sqlSessionFactoryRef = "sqlSessionFactory")

Spring3新特性:graalvm打包Springboot+Mybatis_第10张图片

你可能感兴趣的:(java)