From 1f5b3648fb6fbb1fa9833b04fe9d7ed32eee9932 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Sat, 13 Mar 2021 19:13:35 +0800 Subject: [PATCH] Allow users to inject customized instance via ApolloInjectorCustomizer --- .../apollo/internals/DefaultInjector.java | 29 ++++++++++++++-- .../apollo/spi/ApolloInjectorCustomizer.java | 12 +++++++ .../framework/apollo/build/MockInjector.java | 33 ++++++++++++------- ...mework.apollo.spi.ApolloInjectorCustomizer | 1 + .../internals/ServiceBootstrap.java | 14 ++++---- .../internals/ServiceBootstrapTest.java | 11 +++++++ 6 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/spi/ApolloInjectorCustomizer.java create mode 100644 apollo-client/src/test/resources/META-INF/services/com.ctrip.framework.apollo.spi.ApolloInjectorCustomizer diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultInjector.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultInjector.java index 1f20f21e9..be1f9d94c 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultInjector.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultInjector.java @@ -1,6 +1,7 @@ package com.ctrip.framework.apollo.internals; import com.ctrip.framework.apollo.exceptions.ApolloConfigException; +import com.ctrip.framework.apollo.spi.ApolloInjectorCustomizer; import com.ctrip.framework.apollo.spi.ConfigFactory; import com.ctrip.framework.apollo.spi.ConfigFactoryManager; import com.ctrip.framework.apollo.spi.ConfigRegistry; @@ -14,20 +15,24 @@ import com.ctrip.framework.apollo.util.factory.PropertiesFactory; import com.ctrip.framework.apollo.util.http.HttpUtil; import com.ctrip.framework.apollo.util.yaml.YamlParser; +import com.ctrip.framework.foundation.internals.ServiceBootstrap; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Singleton; +import java.util.List; /** * Guice injector * @author Jason Song(song_s@ctrip.com) */ public class DefaultInjector implements Injector { - private com.google.inject.Injector m_injector; + private final com.google.inject.Injector m_injector; + private final List m_customizers; public DefaultInjector() { try { m_injector = Guice.createInjector(new ApolloModule()); + m_customizers = ServiceBootstrap.loadAllOrdered(ApolloInjectorCustomizer.class); } catch (Throwable ex) { ApolloConfigException exception = new ApolloConfigException("Unable to initialize Guice Injector!", ex); Tracer.logError(exception); @@ -38,6 +43,12 @@ public class DefaultInjector implements Injector { @Override public T getInstance(Class clazz) { try { + for (ApolloInjectorCustomizer customizer : m_customizers) { + T instance = customizer.getInstance(clazz); + if (instance != null) { + return instance; + } + } return m_injector.getInstance(clazz); } catch (Throwable ex) { Tracer.logError(ex); @@ -48,8 +59,20 @@ public class DefaultInjector implements Injector { @Override public T getInstance(Class clazz, String name) { - //Guice does not support get instance by type and name - return null; + try { + for (ApolloInjectorCustomizer customizer : m_customizers) { + T instance = customizer.getInstance(clazz, name); + if (instance != null) { + return instance; + } + } + //Guice does not support get instance by type and name + return null; + } catch (Throwable ex) { + Tracer.logError(ex); + throw new ApolloConfigException( + String.format("Unable to load instance for %s with name %s!", clazz.getName(), name), ex); + } } private static class ApolloModule extends AbstractModule { diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spi/ApolloInjectorCustomizer.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spi/ApolloInjectorCustomizer.java new file mode 100644 index 000000000..f678ea99f --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spi/ApolloInjectorCustomizer.java @@ -0,0 +1,12 @@ +package com.ctrip.framework.apollo.spi; + +import com.ctrip.framework.apollo.core.spi.Ordered; +import com.ctrip.framework.apollo.internals.DefaultInjector; +import com.ctrip.framework.apollo.internals.Injector; + +/** + * Allow users to inject customized instances, see {@link DefaultInjector#getInstance(java.lang.Class)} + */ +public interface ApolloInjectorCustomizer extends Injector, Ordered { + +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/build/MockInjector.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/build/MockInjector.java index 0e4591ad5..2c14d095f 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/build/MockInjector.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/build/MockInjector.java @@ -1,28 +1,24 @@ package com.ctrip.framework.apollo.build; -import java.util.Map; - import com.ctrip.framework.apollo.internals.DefaultInjector; import com.ctrip.framework.apollo.internals.Injector; +import com.ctrip.framework.apollo.spi.ApolloInjectorCustomizer; import com.google.common.collect.HashBasedTable; import com.google.common.collect.Maps; import com.google.common.collect.Table; +import java.util.Map; /** * @author Jason Song(song_s@ctrip.com) */ public class MockInjector implements Injector { + private static Map classMap = Maps.newHashMap(); private static Table classTable = HashBasedTable.create(); private static Injector delegate = new DefaultInjector(); @Override public T getInstance(Class clazz) { - T o = (T) classMap.get(clazz); - if (o != null) { - return o; - } - if (delegate != null) { return delegate.getInstance(clazz); } @@ -32,11 +28,6 @@ public class MockInjector implements Injector { @Override public T getInstance(Class clazz, String name) { - T o = (T) classTable.get(clazz, name); - if (o != null) { - return o; - } - if (delegate != null) { return delegate.getInstance(clazz, name); } @@ -61,4 +52,22 @@ public class MockInjector implements Injector { classTable.clear(); delegate = new DefaultInjector(); } + + public static class InjectCustomizer implements ApolloInjectorCustomizer { + + @Override + public T getInstance(Class clazz) { + return (T) classMap.get(clazz); + } + + @Override + public T getInstance(Class clazz, String name) { + return (T) classTable.get(clazz, name); + } + + @Override + public int getOrder() { + return 0; + } + } } diff --git a/apollo-client/src/test/resources/META-INF/services/com.ctrip.framework.apollo.spi.ApolloInjectorCustomizer b/apollo-client/src/test/resources/META-INF/services/com.ctrip.framework.apollo.spi.ApolloInjectorCustomizer new file mode 100644 index 000000000..42602228c --- /dev/null +++ b/apollo-client/src/test/resources/META-INF/services/com.ctrip.framework.apollo.spi.ApolloInjectorCustomizer @@ -0,0 +1 @@ +com.ctrip.framework.apollo.build.MockInjector$InjectCustomizer \ No newline at end of file diff --git a/apollo-core/src/main/java/com/ctrip/framework/foundation/internals/ServiceBootstrap.java b/apollo-core/src/main/java/com/ctrip/framework/foundation/internals/ServiceBootstrap.java index 4ae8bbba7..bfe272c7a 100644 --- a/apollo-core/src/main/java/com/ctrip/framework/foundation/internals/ServiceBootstrap.java +++ b/apollo-core/src/main/java/com/ctrip/framework/foundation/internals/ServiceBootstrap.java @@ -27,13 +27,6 @@ public class ServiceBootstrap { public static List loadAllOrdered(Class clazz) { Iterator iterator = loadAll(clazz); - - if (!iterator.hasNext()) { - throw new IllegalStateException(String.format( - "No implementation defined in /META-INF/services/%s, please check whether the file exists and has the right implementation class!", - clazz.getName())); - } - List candidates = Lists.newArrayList(iterator); Collections.sort(candidates, new Comparator() { @Override @@ -49,6 +42,13 @@ public class ServiceBootstrap { public static S loadPrimary(Class clazz) { List candidates = loadAllOrdered(clazz); + if (candidates.isEmpty()) { + throw new IllegalStateException(String.format( + "No implementation defined in /META-INF/services/%s, please check whether the file exists and has the right implementation class!", + clazz.getName())); + } + + return candidates.get(0); } } diff --git a/apollo-core/src/test/java/com/ctrip/framework/foundation/internals/ServiceBootstrapTest.java b/apollo-core/src/test/java/com/ctrip/framework/foundation/internals/ServiceBootstrapTest.java index 627e87621..d4b0b080a 100644 --- a/apollo-core/src/test/java/com/ctrip/framework/foundation/internals/ServiceBootstrapTest.java +++ b/apollo-core/src/test/java/com/ctrip/framework/foundation/internals/ServiceBootstrapTest.java @@ -5,6 +5,7 @@ import org.junit.Test; import java.util.ServiceConfigurationError; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** @@ -37,6 +38,11 @@ public class ServiceBootstrapTest { ServiceBootstrap.loadFirst(Interface5.class); } + @Test + public void loadAllWithServiceFileButNoServiceImpl() { + assertFalse(ServiceBootstrap.loadAll(Interface7.class).hasNext()); + } + @Test public void loadPrimarySuccessfully() { Interface6 service = ServiceBootstrap.loadPrimary(Interface6.class); @@ -48,6 +54,11 @@ public class ServiceBootstrapTest { ServiceBootstrap.loadPrimary(Interface7.class); } + @Test + public void loadAllOrderedWithServiceFileButNoServiceImpl() { + assertTrue(ServiceBootstrap.loadAllOrdered(Interface7.class).isEmpty()); + } + interface Interface1 { } -- GitLab