Add property to enable/disable Guice just-in-time bindings and log just-in-time bindings usage

This commit is contained in:
Kevin Wang
2019-10-02 13:15:31 -07:00
committed by Taylor Wicksell
parent 1e7cbb0e31
commit 368ebc4d36
5 changed files with 105 additions and 12 deletions

View File

@@ -70,9 +70,12 @@ class ModuleRegistryConfiguration
implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
private static final String SPRING_GUICE_DEDUPE_BINDINGS_PROPERTY_NAME = "spring.guice.dedup";
private static final String SPRING_GUICE_AUTOWIRE_JIT_PROPERTY_NAME = "spring.guice.autowireJIT";
private ApplicationContext applicationContext;
private List<Module> modules;
private AtomicBoolean injectorCreated = new AtomicBoolean(false);
private boolean enableJustInTimeBinding = true;
private void createInjector(List<Module> modules,
ConfigurableListableBeanFactory beanFactory) {
@@ -178,7 +181,7 @@ class ModuleRegistryConfiguration
throws BeansException {
modules = new ArrayList<Module>(((ConfigurableListableBeanFactory) registry)
.getBeansOfType(Module.class).values());
modules.add(new SpringModule((ConfigurableListableBeanFactory) registry));
modules.add(new SpringModule((ConfigurableListableBeanFactory) registry, enableJustInTimeBinding));
Map<Key<?>, Binding<?>> bindings = new HashMap<Key<?>, Binding<?>>();
List<Element> elements = Elements.getElements(Stage.TOOL, modules);
if (applicationContext.getEnvironment().getProperty(
@@ -303,6 +306,8 @@ class ModuleRegistryConfiguration
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
this.enableJustInTimeBinding = applicationContext.getEnvironment()
.getProperty(SPRING_GUICE_AUTOWIRE_JIT_PROPERTY_NAME, Boolean.class, true);
}
private static class GuiceInjectorInitializingBeanPostProcessor

View File

@@ -67,6 +67,10 @@ class GuiceAutowireCandidateResolver extends ContextAnnotationAutowireCandidateR
try {
beanFactory.doResolveDependency(descriptor, beanName, null, null);
} catch (NoSuchBeanDefinitionException e) {
if (e.getResolvableType() != null) {
logger.info(String.format("Use just in time binding for %s in bean: %s",
e.getResolvableType().getType().getTypeName(), beanName));
}
return true;
}
return super.isLazy(descriptor);

View File

@@ -73,12 +73,23 @@ public class SpringModule extends AbstractModule {
private Provider<ConfigurableListableBeanFactory> beanFactoryProvider;
private boolean enableJustInTimeBinding = true;
public SpringModule(ApplicationContext context) {
this((ConfigurableListableBeanFactory) context.getAutowireCapableBeanFactory());
this(context, true);
}
public SpringModule(ApplicationContext context, boolean enableJustInTimeBinding) {
this((ConfigurableListableBeanFactory) context.getAutowireCapableBeanFactory(), enableJustInTimeBinding);
}
public SpringModule(ConfigurableListableBeanFactory beanFactory) {
this(beanFactory, true);
}
public SpringModule(ConfigurableListableBeanFactory beanFactory, boolean enableJustInTimeBinding) {
this.beanFactory = beanFactory;
this.enableJustInTimeBinding = enableJustInTimeBinding;
}
public SpringModule(Provider<ConfigurableListableBeanFactory> beanFactoryProvider) {
@@ -95,10 +106,12 @@ public class SpringModule extends AbstractModule {
beanFactory.getBeansOfType(ProvisionListener.class).values()
.toArray(new ProvisionListener[0]));
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAutowireCandidateResolver(new GuiceAutowireCandidateResolver(
binder().getProvider(Injector.class)));
if (enableJustInTimeBinding) {
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAutowireCandidateResolver(new GuiceAutowireCandidateResolver(
binder().getProvider(Injector.class)));
}
}
if (beanFactory.getBeanNamesForType(GuiceModuleMetadata.class).length > 0) {
this.matcher = new CompositeTypeMatcher(

View File

@@ -1,6 +1,16 @@
{"properties": [{
"name": "spring.guice.dedup",
"type": "java.lang.Boolean",
"description": "When using `@EnableGuiceModules`, if a Spring Bean and a Guice Binding both exist for the same type and Qualifier, the Spring Bean will be kept and the Guice Binding discarded.",
"defaultValue": "false"
}]}
{
"properties": [
{
"name": "spring.guice.dedup",
"type": "java.lang.Boolean",
"description": "When using `@EnableGuiceModules`, if a Spring Bean and a Guice Binding both exist for the same type and Qualifier, the Spring Bean will be kept and the Guice Binding discarded.",
"defaultValue": "false"
},
{
"name": "spring.guice.autowireJIT",
"type": "java.lang.Boolean",
"description": "When enabled, beans without explicit definitions will be created using Guice just-in-time bindings. Otherwise, it will fail with UnsatisfiedDependencyException.",
"defaultValue": "true"
}
]
}

View File

@@ -0,0 +1,61 @@
package org.springframework.guice;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.guice.annotation.EnableGuiceModules;
import javax.inject.Inject;
import static org.junit.Assert.assertNotNull;
public class JustInTimeBindingTests {
@After
public void tearDown() {
System.clearProperty("spring.guice.autowireJIT");
}
@Test
public void springWithJustInTimeBinding() {
System.setProperty("spring.guice.autowireJIT", "true");
assertNotNull(springGetFoo());
}
@Test(expected = UnsatisfiedDependencyException.class)
public void springWithoutJustInTimeBinding() {
System.setProperty("spring.guice.autowireJIT", "false");
springGetFoo();
}
private Foo springGetFoo() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ModulesConfig.class);
context.getDefaultListableBeanFactory().registerBeanDefinition(Foo.class.getSimpleName(), new RootBeanDefinition(Foo.class));
return context.getBean(Foo.class);
}
@Configuration
@EnableGuiceModules
static class ModulesConfig {
}
public static class Service {
}
public static class Foo {
Service service;
@Inject
public Foo(Service service) {
this.service = service;
}
}
}