From 3cb9d3793d8a1bf0a9985a0dce0102fd6d52fc90 Mon Sep 17 00:00:00 2001 From: terrymanu Date: Thu, 27 Sep 2018 15:37:54 +0800 Subject: [PATCH] for #1172, avoid load spi multiple times to cause gc --- .../spi/NewInstanceServiceLoader.java | 55 +++++++++++++++++++ .../spi/executor/SPISQLExecutionHook.java | 13 +++-- .../spi/parsing/SPIParsingHook.java | 14 +++-- .../spi/root/SPIRootInvokeHook.java | 12 ++-- 4 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 sharding-core/src/main/java/io/shardingsphere/spi/NewInstanceServiceLoader.java diff --git a/sharding-core/src/main/java/io/shardingsphere/spi/NewInstanceServiceLoader.java b/sharding-core/src/main/java/io/shardingsphere/spi/NewInstanceServiceLoader.java new file mode 100644 index 0000000000000..f417e4bf9697c --- /dev/null +++ b/sharding-core/src/main/java/io/shardingsphere/spi/NewInstanceServiceLoader.java @@ -0,0 +1,55 @@ +package io.shardingsphere.spi; + +import io.shardingsphere.core.exception.ShardingException; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.ServiceLoader; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * SPI service loader for new instance for every call. + * + * @author zhangliang + * @param type of class + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class NewInstanceServiceLoader { + + private final Collection> serviceClasses = new CopyOnWriteArrayList<>(); + + /** + * Creates a new service class loader for the given service type. + * + * @param service service type + * @param type of service + * @return new service class loader + */ + @SuppressWarnings("unchecked") + public static synchronized NewInstanceServiceLoader load(final Class service) { + NewInstanceServiceLoader result = new NewInstanceServiceLoader(); + for (T each : ServiceLoader.load(service)) { + result.serviceClasses.add(each.getClass()); + } + return result; + } + + /** + * New service instances. + * + * @return service instances + */ + public Collection newServiceInstances() { + Collection result = new LinkedList<>(); + for (Class each : serviceClasses) { + try { + result.add(each.newInstance()); + } catch (final ReflectiveOperationException ex) { + throw new ShardingException(ex); + } + } + return result; + } +} diff --git a/sharding-core/src/main/java/io/shardingsphere/spi/executor/SPISQLExecutionHook.java b/sharding-core/src/main/java/io/shardingsphere/spi/executor/SPISQLExecutionHook.java index a2db6d60a7ccb..80aa618478129 100644 --- a/sharding-core/src/main/java/io/shardingsphere/spi/executor/SPISQLExecutionHook.java +++ b/sharding-core/src/main/java/io/shardingsphere/spi/executor/SPISQLExecutionHook.java @@ -19,8 +19,9 @@ import io.shardingsphere.core.metadata.datasource.DataSourceMetaData; import io.shardingsphere.core.routing.RouteUnit; +import io.shardingsphere.spi.NewInstanceServiceLoader; -import java.util.ServiceLoader; +import java.util.Collection; /** * SQL Execution hook for SPI. @@ -29,25 +30,27 @@ */ public final class SPISQLExecutionHook implements SQLExecutionHook { - private final ServiceLoader serviceLoader = ServiceLoader.load(SQLExecutionHook.class); + private static final NewInstanceServiceLoader SERVICE_LOADER = NewInstanceServiceLoader.load(SQLExecutionHook.class); + + private final Collection sqlExecutionHooks = SERVICE_LOADER.newServiceInstances(); @Override public void start(final RouteUnit routeUnit, final DataSourceMetaData dataSourceMetaData, final boolean isTrunkThread) { - for (SQLExecutionHook each : serviceLoader) { + for (SQLExecutionHook each : sqlExecutionHooks) { each.start(routeUnit, dataSourceMetaData, isTrunkThread); } } @Override public void finishSuccess() { - for (SQLExecutionHook each : serviceLoader) { + for (SQLExecutionHook each : sqlExecutionHooks) { each.finishSuccess(); } } @Override public void finishFailure(final Exception cause) { - for (SQLExecutionHook each : serviceLoader) { + for (SQLExecutionHook each : sqlExecutionHooks) { each.finishFailure(cause); } } diff --git a/sharding-core/src/main/java/io/shardingsphere/spi/parsing/SPIParsingHook.java b/sharding-core/src/main/java/io/shardingsphere/spi/parsing/SPIParsingHook.java index a1f2e02675225..53c0ee4f51e56 100644 --- a/sharding-core/src/main/java/io/shardingsphere/spi/parsing/SPIParsingHook.java +++ b/sharding-core/src/main/java/io/shardingsphere/spi/parsing/SPIParsingHook.java @@ -17,7 +17,9 @@ package io.shardingsphere.spi.parsing; -import java.util.ServiceLoader; +import io.shardingsphere.spi.NewInstanceServiceLoader; + +import java.util.Collection; /** * Parsing hook for SPI. @@ -26,25 +28,27 @@ */ public final class SPIParsingHook implements ParsingHook { - private final ServiceLoader serviceLoader = ServiceLoader.load(ParsingHook.class); + private static final NewInstanceServiceLoader SERVICE_LOADER = NewInstanceServiceLoader.load(ParsingHook.class); + + private final Collection parsingHooks = SERVICE_LOADER.newServiceInstances(); @Override public void start(final String sql) { - for (ParsingHook each : serviceLoader) { + for (ParsingHook each : parsingHooks) { each.start(sql); } } @Override public void finishSuccess() { - for (ParsingHook each : serviceLoader) { + for (ParsingHook each : parsingHooks) { each.finishSuccess(); } } @Override public void finishFailure(final Exception cause) { - for (ParsingHook each : serviceLoader) { + for (ParsingHook each : parsingHooks) { each.finishFailure(cause); } } diff --git a/sharding-core/src/main/java/io/shardingsphere/spi/root/SPIRootInvokeHook.java b/sharding-core/src/main/java/io/shardingsphere/spi/root/SPIRootInvokeHook.java index 913a57899f435..005bb43caf273 100644 --- a/sharding-core/src/main/java/io/shardingsphere/spi/root/SPIRootInvokeHook.java +++ b/sharding-core/src/main/java/io/shardingsphere/spi/root/SPIRootInvokeHook.java @@ -17,7 +17,9 @@ package io.shardingsphere.spi.root; -import java.util.ServiceLoader; +import io.shardingsphere.spi.NewInstanceServiceLoader; + +import java.util.Collection; /** * Root invoke hook for SPI. @@ -26,18 +28,20 @@ */ public final class SPIRootInvokeHook implements RootInvokeHook { - private final ServiceLoader serviceLoader = ServiceLoader.load(RootInvokeHook.class); + private static final NewInstanceServiceLoader SERVICE_LOADER = NewInstanceServiceLoader.load(RootInvokeHook.class); + + private final Collection rootInvokeHooks = SERVICE_LOADER.newServiceInstances(); @Override public void start() { - for (RootInvokeHook each : serviceLoader) { + for (RootInvokeHook each : rootInvokeHooks) { each.start(); } } @Override public void finish(final int connectionCount) { - for (RootInvokeHook each : serviceLoader) { + for (RootInvokeHook each : rootInvokeHooks) { each.finish(connectionCount); } }