在JDK17中引用seata作为分布式事务控制,项目启动失败,整体报文如下:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'globalTransactionScanner' defined in class path resource [io/seata/spring/boot/autoconfigure/SeataAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.seata.spring.annotation.GlobalTransactionScanner]: Factory method 'globalTransactionScanner' threw exception; nested exception is java.lang.ExceptionInInitializerError
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:638) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:258) ~[spring-context-5.3.23.jar:5.3.23]
at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:762) ~[spring-context-5.3.23.jar:5.3.23]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:567) ~[spring-context-5.3.23.jar:5.3.23]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.4.jar:2.7.4]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) ~[spring-boot-2.7.4.jar:2.7.4]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) ~[spring-boot-2.7.4.jar:2.7.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-boot-2.7.4.jar:2.7.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.4.jar:2.7.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.4.jar:2.7.4]
at com.fbi.fvite.FViteApplication.main(FViteApplication.java:10) ~[classes/:na]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.seata.spring.annotation.GlobalTransactionScanner]: Factory method 'globalTransactionScanner' threw exception; nested exception is java.lang.ExceptionInInitializerError
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.23.jar:5.3.23]
... 19 common frames omitted
Caused by: java.lang.ExceptionInInitializerError: null
at net.sf.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:166) ~[cglib-3.1.jar:na]
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25) ~[cglib-3.1.jar:na]
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216) ~[cglib-3.1.jar:na]
at net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:144) ~[cglib-3.1.jar:na]
at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:116) ~[cglib-3.1.jar:na]
at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:108) ~[cglib-3.1.jar:na]
at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:104) ~[cglib-3.1.jar:na]
at net.sf.cglib.proxy.Enhancer.(Enhancer.java:69) ~[cglib-3.1.jar:na]
at io.seata.config.ConfigurationCache.proxy(ConfigurationCache.java:104) ~[seata-all-1.5.2.jar:1.5.2]
at io.seata.config.ConfigurationFactory.buildConfiguration(ConfigurationFactory.java:136) ~[seata-all-1.5.2.jar:1.5.2]
at io.seata.config.ConfigurationFactory.getInstance(ConfigurationFactory.java:94) ~[seata-all-1.5.2.jar:1.5.2]
at io.seata.spring.annotation.GlobalTransactionScanner.(GlobalTransactionScanner.java:105) ~[seata-all-1.5.2.jar:1.5.2]
at io.seata.spring.annotation.GlobalTransactionScanner.(GlobalTransactionScanner.java:162) ~[seata-all-1.5.2.jar:1.5.2]
at io.seata.spring.boot.autoconfigure.SeataAutoConfiguration.globalTransactionScanner(SeataAutoConfiguration.java:83) ~[seata-spring-boot-starter-1.5.2.jar:1.5.2]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.23.jar:5.3.23]
... 20 common frames omitted
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @bcec361
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354) ~[na:na]
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297) ~[na:na]
at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199) ~[na:na]
at java.base/java.lang.reflect.Method.setAccessible(Method.java:193) ~[na:na]
at net.sf.cglib.core.ReflectUtils$2.run(ReflectUtils.java:56) ~[cglib-3.1.jar:na]
at java.base/java.security.AccessController.doPrivileged(AccessController.java:318) ~[na:na]
at net.sf.cglib.core.ReflectUtils.(ReflectUtils.java:46) ~[cglib-3.1.jar:na]
... 39 common frames omitted
临时解决方案
)https://github.com/seata/seata
all/pom.xml
和config/seata-config-core/pom.xml
, 修改cglib
的引用,使用bytebuddy
代替cglib
,seata项目中已经有了bytebuddy
的关联依赖,因此不需要重复指定版本号。 <dependency>
<groupId>net.bytebuddygroupId>
<artifactId>byte-buddyartifactId>
dependency>
config/seata-config-core/src/main/java/io/seata/config/ConfigurationCache.java
的proxy
方法,改为bytebuddy
实现方式,代码如下 public Configuration proxy(Configuration originalConfiguration) {
DynamicType.Builder.MethodDefinition.ReceiverTypeDefinition<Configuration> intercept = new ByteBuddy()
.subclass(Configuration.class)
.method(ElementMatchers.any())
.intercept(InvocationHandlerAdapter.of((proxy, method, args) -> {
if (method.getName().startsWith(METHOD_PREFIX)
&& !method.getName().equalsIgnoreCase(METHOD_LATEST_CONFIG)) {
String rawDataId = (String) args[0];
ObjectWrapper wrapper = CONFIG_CACHE.get(rawDataId);
ObjectWrapper.ConfigType type = ObjectWrapper.getTypeByName(method.getName().substring(METHOD_PREFIX.length()));
Object defaultValue = null;
if (args.length > 1 && method.getParameterTypes()[1].getSimpleName().equalsIgnoreCase(type.name())) {
defaultValue = args[1];
}
if (null == wrapper || (null != defaultValue && !Objects.equals(defaultValue, wrapper.lastDefaultValue))) {
Object result = method.invoke(originalConfiguration, args);
// The wrapper.data only exists in the cache when it is not null.
if (result != null) {
wrapper = new ObjectWrapper(result, type, defaultValue);
CONFIG_CACHE.put(rawDataId, wrapper);
}
}
return wrapper == null ? null : wrapper.convertData(type);
}
return method.invoke(originalConfiguration, args);
}));
try {
return intercept.make().load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.getLoaded().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
build/pom.xml
)如下:
<revision>1.6.0-SNAPSHOT.fixj17revision>
mvn clean install
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-seataartifactId>
<exclusions>
<exclusion>
<groupId>io.seatagroupId>
<artifactId>seata-allartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>io.seatagroupId>
<artifactId>seata-allartifactId>
<version>1.6.0-SNAPSHOT.fixj17version>
dependency>
刷新maven依赖后,至此问题解决。这是一个解决思路,可以适用于cglib在高版本jdk中导致的此类问题。
除了以上方式外,spring官方也给出了修复方案,如果你使用了spring框架,可以使用spring的修正版cglib,也就是说你无需重新实现代码也可以解决此类问题。
https://github.com/spring-projects/spring-framework/tree/main/spring-core/src/main/java/org/springframework/cglib
使用这里的来代替cglib的api,它和cglib的api完全一致,无需重新实现。
seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/io/seata/spring/boot/autoconfigure/provider/SpringBootConfigurationProvider.java
。