Skip to content

Commit

Permalink
Allow users to inject customized instance via ApolloInjectorCustomizer
Browse files Browse the repository at this point in the history
  • Loading branch information
nobodyiam committed Mar 13, 2021
1 parent d059795 commit 0718c18
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -14,20 +15,24 @@
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([email protected])
*/
public class DefaultInjector implements Injector {
private com.google.inject.Injector m_injector;
private final com.google.inject.Injector m_injector;
private final List<ApolloInjectorCustomizer> 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);
Expand All @@ -38,6 +43,12 @@ public DefaultInjector() {
@Override
public <T> T getInstance(Class<T> 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);
Expand All @@ -48,8 +59,20 @@ public <T> T getInstance(Class<T> clazz) {

@Override
public <T> T getInstance(Class<T> 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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {

}
Original file line number Diff line number Diff line change
@@ -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([email protected])
*/
public class MockInjector implements Injector {

private static Map<Class, Object> classMap = Maps.newHashMap();
private static Table<Class, String, Object> classTable = HashBasedTable.create();
private static Injector delegate = new DefaultInjector();

@Override
public <T> T getInstance(Class<T> clazz) {
T o = (T) classMap.get(clazz);
if (o != null) {
return o;
}

if (delegate != null) {
return delegate.getInstance(clazz);
}
Expand All @@ -32,11 +28,6 @@ public <T> T getInstance(Class<T> clazz) {

@Override
public <T> T getInstance(Class<T> clazz, String name) {
T o = (T) classTable.get(clazz, name);
if (o != null) {
return o;
}

if (delegate != null) {
return delegate.getInstance(clazz, name);
}
Expand All @@ -61,4 +52,22 @@ public static void reset() {
classTable.clear();
delegate = new DefaultInjector();
}

public static class InjectCustomizer implements ApolloInjectorCustomizer {

@Override
public <T> T getInstance(Class<T> clazz) {
return (T) classMap.get(clazz);
}

@Override
public <T> T getInstance(Class<T> clazz, String name) {
return (T) classTable.get(clazz, name);
}

@Override
public int getOrder() {
return 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.ctrip.framework.apollo.build.MockInjector$InjectCustomizer
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,6 @@ public static <S> Iterator<S> loadAll(Class<S> clazz) {

public static <S extends Ordered> List<S> loadAllOrdered(Class<S> clazz) {
Iterator<S> 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<S> candidates = Lists.newArrayList(iterator);
Collections.sort(candidates, new Comparator<S>() {
@Override
Expand All @@ -49,6 +42,13 @@ public int compare(S o1, S o2) {
public static <S extends Ordered> S loadPrimary(Class<S> clazz) {
List<S> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import java.util.ServiceConfigurationError;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

/**
Expand Down Expand Up @@ -37,6 +38,11 @@ public void loadFirstWithServiceImplNotExists() throws Exception {
ServiceBootstrap.loadFirst(Interface5.class);
}

@Test
public void loadAllWithServiceFileButNoServiceImpl() {
assertFalse(ServiceBootstrap.loadAll(Interface7.class).hasNext());
}

@Test
public void loadPrimarySuccessfully() {
Interface6 service = ServiceBootstrap.loadPrimary(Interface6.class);
Expand All @@ -48,6 +54,11 @@ public void loadPrimaryWithServiceFileButNoServiceImpl() {
ServiceBootstrap.loadPrimary(Interface7.class);
}

@Test
public void loadAllOrderedWithServiceFileButNoServiceImpl() {
assertTrue(ServiceBootstrap.loadAllOrdered(Interface7.class).isEmpty());
}

interface Interface1 {
}

Expand Down

0 comments on commit 0718c18

Please sign in to comment.