HHH-12907 Avoid creating too many ByteBuddy objects
This commit should reduce the garbage collection pressure as reported at https://github.com/raphw/byte-buddy/issues/515.
This commit is contained in:
parent
b65121c557
commit
7eb0cee178
|
@ -20,10 +20,6 @@ import net.bytebuddy.NamingStrategy;
|
|||
import net.bytebuddy.TypeCache;
|
||||
import net.bytebuddy.description.modifier.Visibility;
|
||||
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
|
||||
import net.bytebuddy.implementation.FieldAccessor;
|
||||
import net.bytebuddy.implementation.MethodDelegation;
|
||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
|
||||
public class BasicProxyFactoryImpl implements BasicProxyFactory {
|
||||
|
||||
|
@ -47,10 +43,10 @@ public class BasicProxyFactoryImpl implements BasicProxyFactory {
|
|||
.subclass( superClass == null ? Object.class : superClass, ConstructorStrategy.Default.DEFAULT_CONSTRUCTOR )
|
||||
.implement( interfaces == null ? NO_INTERFACES : interfaces )
|
||||
.defineField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME, ProxyConfiguration.Interceptor.class, Visibility.PRIVATE )
|
||||
.method( ElementMatchers.isVirtual().and( ElementMatchers.not( ElementMatchers.isFinalizer() ) ) )
|
||||
.intercept( MethodDelegation.to( ProxyConfiguration.InterceptorDispatcher.class ) )
|
||||
.method( byteBuddyState.getProxyDefinitionHelpers().getVirtualNotFinalizerFilter() )
|
||||
.intercept( byteBuddyState.getProxyDefinitionHelpers().getDelegateToInterceptorDispatcherMethodDelegation() )
|
||||
.implement( ProxyConfiguration.class )
|
||||
.intercept( FieldAccessor.ofField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME ).withAssigner( Assigner.DEFAULT, Assigner.Typing.DYNAMIC ) )
|
||||
.intercept( byteBuddyState.getProxyDefinitionHelpers().getInterceptorFieldAccessor() )
|
||||
);
|
||||
this.interceptor = new PassThroughInterceptor( proxyClass.getName() );
|
||||
}
|
||||
|
|
|
@ -6,6 +6,13 @@
|
|||
*/
|
||||
package org.hibernate.bytecode.internal.bytebuddy;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isFinalizer;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isSynthetic;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isVirtual;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.returns;
|
||||
import static org.hibernate.internal.CoreLogging.messageLogger;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -20,17 +27,23 @@ import java.util.function.Function;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.bytecode.spi.BasicProxyFactory;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.proxy.ProxyConfiguration;
|
||||
import org.hibernate.proxy.ProxyFactory;
|
||||
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.TypeCache;
|
||||
import net.bytebuddy.asm.AsmVisitorWrapper.ForDeclaredMethods;
|
||||
import net.bytebuddy.asm.MemberSubstitution;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.dynamic.DynamicType.Unloaded;
|
||||
import net.bytebuddy.dynamic.loading.ClassInjector;
|
||||
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
|
||||
import net.bytebuddy.dynamic.scaffold.TypeValidation;
|
||||
import net.bytebuddy.implementation.FieldAccessor;
|
||||
import net.bytebuddy.implementation.MethodDelegation;
|
||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.bytebuddy.pool.TypePool;
|
||||
|
||||
|
@ -52,6 +65,8 @@ public final class ByteBuddyState {
|
|||
private final ForDeclaredMethods getDeclaredMethodMemberSubstitution;
|
||||
private final ForDeclaredMethods getMethodMemberSubstitution;
|
||||
|
||||
private final ProxyDefinitionHelpers proxyDefinitionHelpers;
|
||||
|
||||
/**
|
||||
* It will be easier to maintain the cache and its state when it will no longer be static
|
||||
* in Hibernate ORM 6+.
|
||||
|
@ -75,6 +90,8 @@ public final class ByteBuddyState {
|
|||
this.getDeclaredMethodMemberSubstitution = null;
|
||||
this.getMethodMemberSubstitution = null;
|
||||
}
|
||||
|
||||
this.proxyDefinitionHelpers = new ProxyDefinitionHelpers();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,6 +152,17 @@ public final class ByteBuddyState {
|
|||
return make( typePool, builder ).getBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the proxy definition helpers to reuse when defining proxies.
|
||||
* <p>
|
||||
* These elements are shared as they are immutable.
|
||||
*
|
||||
* @return The proxy definition helpers.
|
||||
*/
|
||||
public ProxyDefinitionHelpers getProxyDefinitionHelpers() {
|
||||
return proxyDefinitionHelpers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wipes out all known caches used by ByteBuddy. This implies it might trigger the need
|
||||
* to re-create some helpers if used at runtime, especially as this state is shared by
|
||||
|
@ -276,4 +304,47 @@ public final class ByteBuddyState {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared proxy definition helpers. They are immutable so we can safely share them.
|
||||
*/
|
||||
public static class ProxyDefinitionHelpers {
|
||||
|
||||
private final ElementMatcher<? super MethodDescription> groovyGetMetaClassFilter;
|
||||
private final ElementMatcher<? super MethodDescription> virtualNotFinalizerFilter;
|
||||
private final ElementMatcher<? super MethodDescription> hibernateGeneratedMethodFilter;
|
||||
private final MethodDelegation delegateToInterceptorDispatcherMethodDelegation;
|
||||
private final FieldAccessor.PropertyConfigurable interceptorFieldAccessor;
|
||||
|
||||
private ProxyDefinitionHelpers() {
|
||||
this.groovyGetMetaClassFilter = isSynthetic().and( named( "getMetaClass" )
|
||||
.and( returns( td -> "groovy.lang.MetaClass".equals( td.getName() ) ) ) );
|
||||
this.virtualNotFinalizerFilter = isVirtual().and( not( isFinalizer() ) );
|
||||
this.hibernateGeneratedMethodFilter = nameStartsWith( "$$_hibernate_" ).and( isVirtual() );
|
||||
this.delegateToInterceptorDispatcherMethodDelegation = MethodDelegation
|
||||
.to( ProxyConfiguration.InterceptorDispatcher.class );
|
||||
this.interceptorFieldAccessor = FieldAccessor.ofField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME )
|
||||
.withAssigner( Assigner.DEFAULT, Assigner.Typing.DYNAMIC );
|
||||
}
|
||||
|
||||
public ElementMatcher<? super MethodDescription> getGroovyGetMetaClassFilter() {
|
||||
return groovyGetMetaClassFilter;
|
||||
}
|
||||
|
||||
public ElementMatcher<? super MethodDescription> getVirtualNotFinalizerFilter() {
|
||||
return virtualNotFinalizerFilter;
|
||||
}
|
||||
|
||||
public ElementMatcher<? super MethodDescription> getHibernateGeneratedMethodFilter() {
|
||||
return hibernateGeneratedMethodFilter;
|
||||
}
|
||||
|
||||
public MethodDelegation getDelegateToInterceptorDispatcherMethodDelegation() {
|
||||
return delegateToInterceptorDispatcherMethodDelegation;
|
||||
}
|
||||
|
||||
public FieldAccessor.PropertyConfigurable getInterceptorFieldAccessor() {
|
||||
return interceptorFieldAccessor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,17 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.proxy.pojo.bytebuddy;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isFinalizer;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isSynthetic;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isVirtual;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.returns;
|
||||
import static org.hibernate.internal.CoreLogging.messageLogger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
|
@ -28,24 +19,16 @@ import java.util.Set;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.proxy.ProxyConfiguration;
|
||||
import org.hibernate.proxy.ProxyFactory;
|
||||
import org.hibernate.type.CompositeType;
|
||||
|
||||
import net.bytebuddy.NamingStrategy;
|
||||
import net.bytebuddy.TypeCache;
|
||||
import net.bytebuddy.description.modifier.Visibility;
|
||||
import net.bytebuddy.dynamic.DynamicType.Unloaded;
|
||||
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
|
||||
import net.bytebuddy.implementation.FieldAccessor;
|
||||
import net.bytebuddy.implementation.MethodDelegation;
|
||||
import net.bytebuddy.implementation.SuperMethodCall;
|
||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||
|
||||
public class ByteBuddyProxyHelper implements Serializable {
|
||||
|
||||
|
@ -69,17 +52,17 @@ public class ByteBuddyProxyHelper implements Serializable {
|
|||
key.addAll( Arrays.<Class<?>>asList( interfaces ) );
|
||||
|
||||
return byteBuddyState.loadProxy( persistentClass, new TypeCache.SimpleKey(key), byteBuddy -> byteBuddy
|
||||
.ignore( isSynthetic().and( named( "getMetaClass" ).and( returns( td -> "groovy.lang.MetaClass".equals( td.getName() ) ) ) ) )
|
||||
.ignore( byteBuddyState.getProxyDefinitionHelpers().getGroovyGetMetaClassFilter() )
|
||||
.with( new NamingStrategy.SuffixingRandom( PROXY_NAMING_SUFFIX, new NamingStrategy.SuffixingRandom.BaseNameResolver.ForFixedValue( persistentClass.getName() ) ) )
|
||||
.subclass( interfaces.length == 1 ? persistentClass : Object.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING )
|
||||
.implement( (Type[]) interfaces )
|
||||
.method( isVirtual().and( not( isFinalizer() ) ) )
|
||||
.intercept( MethodDelegation.to( ProxyConfiguration.InterceptorDispatcher.class ) )
|
||||
.method( nameStartsWith( "$$_hibernate_" ).and( isVirtual() ) )
|
||||
.method( byteBuddyState.getProxyDefinitionHelpers().getVirtualNotFinalizerFilter() )
|
||||
.intercept( byteBuddyState.getProxyDefinitionHelpers().getDelegateToInterceptorDispatcherMethodDelegation() )
|
||||
.method( byteBuddyState.getProxyDefinitionHelpers().getHibernateGeneratedMethodFilter() )
|
||||
.intercept( SuperMethodCall.INSTANCE )
|
||||
.defineField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME, ProxyConfiguration.Interceptor.class, Visibility.PRIVATE )
|
||||
.implement( ProxyConfiguration.class )
|
||||
.intercept( FieldAccessor.ofField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME ).withAssigner( Assigner.DEFAULT, Assigner.Typing.DYNAMIC ) )
|
||||
.intercept( byteBuddyState.getProxyDefinitionHelpers().getInterceptorFieldAccessor() )
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue