Merge branch '6.0.x'
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,8 +21,8 @@ import org.springframework.instrument.classloading.LoadTimeWeaver;
|
||||
/**
|
||||
* Interface to be implemented by
|
||||
* {@link org.springframework.context.annotation.Configuration @Configuration}
|
||||
* classes annotated with {@link EnableLoadTimeWeaving @EnableLoadTimeWeaving} that wish to
|
||||
* customize the {@link LoadTimeWeaver} instance to be used.
|
||||
* classes annotated with {@link EnableLoadTimeWeaving @EnableLoadTimeWeaving}
|
||||
* that wish to customize the {@link LoadTimeWeaver} instance to be used.
|
||||
*
|
||||
* <p>See {@link org.springframework.scheduling.annotation.EnableAsync @EnableAsync}
|
||||
* for usage examples and information on how a default {@code LoadTimeWeaver}
|
||||
@@ -36,9 +36,9 @@ import org.springframework.instrument.classloading.LoadTimeWeaver;
|
||||
public interface LoadTimeWeavingConfigurer {
|
||||
|
||||
/**
|
||||
* Create, configure and return the {@code LoadTimeWeaver} instance to be used. Note
|
||||
* that it is unnecessary to annotate this method with {@code @Bean}, because the
|
||||
* object returned will automatically be registered as a bean by
|
||||
* Create, configure and return the {@code LoadTimeWeaver} instance to be used.
|
||||
* Note that it is unnecessary to annotate this method with {@code @Bean}
|
||||
* because the object returned will automatically be registered as a bean by
|
||||
* {@link LoadTimeWeavingConfiguration#loadTimeWeaver()}
|
||||
*/
|
||||
LoadTimeWeaver getLoadTimeWeaver();
|
||||
|
||||
@@ -769,7 +769,8 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
|
||||
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
|
||||
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
|
||||
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
|
||||
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null &&
|
||||
beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
|
||||
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
|
||||
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,8 @@ import java.security.ProtectionDomain;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.DecoratingClassLoader;
|
||||
import org.springframework.core.OverridingClassLoader;
|
||||
import org.springframework.core.SmartClassLoader;
|
||||
@@ -45,15 +47,26 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
|
||||
}
|
||||
|
||||
|
||||
private static Method findLoadedClassMethod;
|
||||
@Nullable
|
||||
private static final Method findLoadedClassMethod;
|
||||
|
||||
static {
|
||||
// Try to enable findLoadedClass optimization which allows us to selectively
|
||||
// override classes that have not been loaded yet. If not accessible, we will
|
||||
// always override requested classes, even when the classes have been loaded
|
||||
// by the parent ClassLoader already and cannot be transformed anymore anyway.
|
||||
Method method = null;
|
||||
try {
|
||||
findLoadedClassMethod = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
|
||||
method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Invalid [java.lang.ClassLoader] class: no 'findLoadedClass' method defined!");
|
||||
catch (Throwable ex) {
|
||||
// Typically a JDK 9+ InaccessibleObjectException...
|
||||
// Avoid through JVM startup with --add-opens=java.base/java.lang=ALL-UNNAMED
|
||||
LogFactory.getLog(ContextTypeMatchClassLoader.class).debug(
|
||||
"ClassLoader.findLoadedClass not accessible -> will always override requested class", ex);
|
||||
}
|
||||
findLoadedClassMethod = method;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,13 +109,14 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart
|
||||
if (isExcluded(className) || ContextTypeMatchClassLoader.this.isExcluded(className)) {
|
||||
return false;
|
||||
}
|
||||
ReflectionUtils.makeAccessible(findLoadedClassMethod);
|
||||
ClassLoader parent = getParent();
|
||||
while (parent != null) {
|
||||
if (ReflectionUtils.invokeMethod(findLoadedClassMethod, parent, className) != null) {
|
||||
return false;
|
||||
if (findLoadedClassMethod != null) {
|
||||
ClassLoader parent = getParent();
|
||||
while (parent != null) {
|
||||
if (ReflectionUtils.invokeMethod(findLoadedClassMethod, parent, className) != null) {
|
||||
return false;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ class EnableLoadTimeWeavingTests {
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.DISABLED)
|
||||
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.DISABLED)
|
||||
static class EnableLTWConfig_withAjWeavingDisabled implements LoadTimeWeavingConfigurer {
|
||||
|
||||
@Override
|
||||
@@ -88,8 +88,9 @@ class EnableLoadTimeWeavingTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.AUTODETECT)
|
||||
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.AUTODETECT)
|
||||
static class EnableLTWConfig_withAjWeavingAutodetect implements LoadTimeWeavingConfigurer {
|
||||
|
||||
@Override
|
||||
@@ -98,8 +99,9 @@ class EnableLoadTimeWeavingTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
|
||||
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.ENABLED)
|
||||
static class EnableLTWConfig_withAjWeavingEnabled implements LoadTimeWeavingConfigurer {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -85,16 +85,13 @@ public class ReflectiveLoadTimeWeaverTests {
|
||||
|
||||
private int numTimesAddTransformerCalled = 0;
|
||||
|
||||
|
||||
public int getNumTimesGetThrowawayClassLoaderCalled() {
|
||||
return this.numTimesAddTransformerCalled;
|
||||
}
|
||||
|
||||
|
||||
public void addTransformer(ClassFileTransformer transformer) {
|
||||
++this.numTimesAddTransformerCalled;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -102,18 +99,15 @@ public class ReflectiveLoadTimeWeaverTests {
|
||||
|
||||
private int numTimesGetThrowawayClassLoaderCalled = 0;
|
||||
|
||||
|
||||
@Override
|
||||
public int getNumTimesGetThrowawayClassLoaderCalled() {
|
||||
return this.numTimesGetThrowawayClassLoaderCalled;
|
||||
}
|
||||
|
||||
|
||||
public ClassLoader getThrowawayClassLoader() {
|
||||
++this.numTimesGetThrowawayClassLoaderCalled;
|
||||
return getClass().getClassLoader();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InaccessibleObjectException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -508,14 +509,14 @@ public class ReflectUtils {
|
||||
catch (InvocationTargetException ex) {
|
||||
throw new CodeGenerationException(ex.getTargetException());
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Fall through if setAccessible fails with InaccessibleObjectException on JDK 9+
|
||||
// (on the module path and/or with a JVM bootstrapped with --illegal-access=deny)
|
||||
if (!ex.getClass().getName().endsWith("InaccessibleObjectException")) {
|
||||
throw new CodeGenerationException(ex);
|
||||
}
|
||||
catch (InaccessibleObjectException ex) {
|
||||
// setAccessible failed with JDK 9+ InaccessibleObjectException -> fall through
|
||||
// Avoid through JVM startup with --add-opens=java.base/java.lang=ALL-UNNAMED
|
||||
t = ex;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new CodeGenerationException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,13 +526,14 @@ public class ReflectUtils {
|
||||
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(contextClass, MethodHandles.lookup());
|
||||
c = lookup.defineClass(b);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
catch (LinkageError | IllegalAccessException ex) {
|
||||
throw new CodeGenerationException(ex) {
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "ClassLoader mismatch for [" + contextClass.getName() +
|
||||
"]: JVM should be started with --add-opens=java.base/java.lang=ALL-UNNAMED " +
|
||||
"for ClassLoader.defineClass to be accessible on " + loader.getClass().getName();
|
||||
"for ClassLoader.defineClass to be accessible on " + loader.getClass().getName() +
|
||||
"; consider co-locating the affected class in that target ClassLoader instead.";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -507,16 +507,8 @@ public abstract class ReflectionUtils {
|
||||
* @see java.lang.Object#equals(Object)
|
||||
*/
|
||||
public static boolean isEqualsMethod(@Nullable Method method) {
|
||||
if (method == null) {
|
||||
return false;
|
||||
}
|
||||
if (method.getParameterCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (!method.getName().equals("equals")) {
|
||||
return false;
|
||||
}
|
||||
return method.getParameterTypes()[0] == Object.class;
|
||||
return (method != null && method.getParameterCount() == 1 && method.getName().equals("equals") &&
|
||||
method.getParameterTypes()[0] == Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -524,7 +516,7 @@ public abstract class ReflectionUtils {
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
public static boolean isHashCodeMethod(@Nullable Method method) {
|
||||
return method != null && method.getParameterCount() == 0 && method.getName().equals("hashCode");
|
||||
return (method != null && method.getParameterCount() == 0 && method.getName().equals("hashCode"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -97,16 +97,18 @@ import org.springframework.util.Assert;
|
||||
* support nested transactions! Hence, do not expect Hibernate access code to
|
||||
* semantically participate in a nested transaction.</i>
|
||||
*
|
||||
* <p><b>NOTE: Hibernate ORM 6.x is officially only supported as a JPA provider.
|
||||
* Please use {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}
|
||||
* with {@link org.springframework.orm.jpa.JpaTransactionManager} there instead.</b>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
* @see #setSessionFactory
|
||||
* @see #setDataSource
|
||||
* @see SessionFactory#getCurrentSession()
|
||||
* @see DataSourceUtils#getConnection
|
||||
* @see DataSourceUtils#releaseConnection
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate
|
||||
* @see org.springframework.jdbc.support.JdbcTransactionManager
|
||||
* @see org.springframework.transaction.jta.JtaTransactionManager
|
||||
* @see org.springframework.orm.jpa.JpaTransactionManager
|
||||
* @see org.springframework.orm.jpa.vendor.HibernateJpaDialect
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class HibernateTransactionManager extends AbstractPlatformTransactionManager
|
||||
@@ -271,7 +273,11 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
* @see Connection#setHoldability
|
||||
* @see ResultSet#HOLD_CURSORS_OVER_COMMIT
|
||||
* @see #disconnectOnCompletion(Session)
|
||||
* @deprecated as of 5.3.29 since Hibernate 5.x aggressively closes ResultSets on commit,
|
||||
* making it impossible to rely on ResultSet holdability. Also, Spring does not provide
|
||||
* an equivalent setting on {@link org.springframework.orm.jpa.JpaTransactionManager}.
|
||||
*/
|
||||
@Deprecated(since = "5.3.29")
|
||||
public void setAllowResultAccessAfterCompletion(boolean allowResultAccessAfterCompletion) {
|
||||
this.allowResultAccessAfterCompletion = allowResultAccessAfterCompletion;
|
||||
}
|
||||
@@ -487,7 +493,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
|
||||
session = txObject.getSessionHolder().getSession().unwrap(SessionImplementor.class);
|
||||
|
||||
boolean holdabilityNeeded = this.allowResultAccessAfterCompletion && !txObject.isNewSession();
|
||||
boolean holdabilityNeeded = (this.allowResultAccessAfterCompletion && !txObject.isNewSession());
|
||||
boolean isolationLevelNeeded = (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT);
|
||||
if (holdabilityNeeded || isolationLevelNeeded || definition.isReadOnly()) {
|
||||
if (this.prepareConnection && ConnectionReleaseMode.ON_CLOSE.equals(
|
||||
@@ -500,7 +506,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
||||
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
|
||||
txObject.setPreviousIsolationLevel(previousIsolationLevel);
|
||||
txObject.setReadOnly(definition.isReadOnly());
|
||||
if (this.allowResultAccessAfterCompletion && !txObject.isNewSession()) {
|
||||
if (holdabilityNeeded) {
|
||||
int currentHoldability = con.getHoldability();
|
||||
if (currentHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
|
||||
txObject.setPreviousHoldability(currentHoldability);
|
||||
|
||||
@@ -66,6 +66,10 @@ import org.springframework.lang.Nullable;
|
||||
* {@link HibernateTransactionManager}, this naturally allows for mixing JPA access code
|
||||
* with native Hibernate access code within the same transaction.
|
||||
*
|
||||
* <p><b>NOTE: Hibernate ORM 6.x is officially only supported as a JPA provider.
|
||||
* Please use {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}
|
||||
* with {@link org.springframework.orm.jpa.JpaTransactionManager} there instead.</b>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
* @see #setDataSource
|
||||
|
||||
Reference in New Issue
Block a user