Browse Source

Fix bug in StaticListableBeanFactory.isSingleton()

Prior to this commit, StaticListableBeanFactory.isSingleton() returned
false for singleton beans unless they were created by a FactoryBean.

StaticListableBeanFactory.isSingleton() now properly returns true for
all beans not created by a FactoryBean.

Closes gh-25522
pull/25798/head
Sam Brannen 5 years ago
parent
commit
7a31885ae5
  1. 24
      spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
  2. 105
      spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java

24
spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -45,20 +45,22 @@ import org.springframework.util.StringUtils; @@ -45,20 +45,22 @@ import org.springframework.util.StringUtils;
/**
* Static {@link org.springframework.beans.factory.BeanFactory} implementation
* which allows to register existing singleton instances programmatically.
* Does not have support for prototype beans or aliases.
* which allows one to register existing singleton instances programmatically.
*
* <p>Serves as example for a simple implementation of the
* <p>Does not have support for prototype beans or aliases.
*
* <p>Serves as an example for a simple implementation of the
* {@link org.springframework.beans.factory.ListableBeanFactory} interface,
* managing existing bean instances rather than creating new ones based on bean
* definitions, and not implementing any extended SPI interfaces (such as
* {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}).
*
* <p>For a full-fledged factory based on bean definitions, have a look
* at {@link DefaultListableBeanFactory}.
* <p>For a full-fledged factory based on bean definitions, have a look at
* {@link DefaultListableBeanFactory}.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Sam Brannen
* @since 06.01.2003
* @see DefaultListableBeanFactory
*/
@ -83,7 +85,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory { @@ -83,7 +85,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
* or {@link java.util.Collections#emptyMap()} for a dummy factory which
* enforces operating against an empty set of beans.
* @param beans a {@code Map} for holding this factory's beans, with the
* bean name String as key and the corresponding singleton object as value
* bean name as key and the corresponding singleton object as value
* @since 4.3
*/
public StaticListableBeanFactory(Map<String, Object> beans) {
@ -94,7 +96,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory { @@ -94,7 +96,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
/**
* Add a new singleton bean.
* Will overwrite any existing instance for the given name.
* <p>Will overwrite any existing instance for the given name.
* @param name the name of the bean
* @param bean the bean instance
*/
@ -262,7 +264,10 @@ public class StaticListableBeanFactory implements ListableBeanFactory { @@ -262,7 +264,10 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
Object bean = getBean(name);
// In case of FactoryBean, return singleton status of created object.
return (bean instanceof FactoryBean && ((FactoryBean<?>) bean).isSingleton());
if (bean instanceof FactoryBean) {
return ((FactoryBean<?>) bean).isSingleton();
}
return true;
}
@Override
@ -337,7 +342,6 @@ public class StaticListableBeanFactory implements ListableBeanFactory { @@ -337,7 +342,6 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
return getBeanNamesForType(type, true, true);
}
@Override
public String[] getBeanNamesForType(@Nullable ResolvableType type,
boolean includeNonSingletons, boolean allowEagerInit) {

105
spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -43,6 +43,7 @@ import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifie @@ -43,6 +43,7 @@ import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifie
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
* @author Sam Brannen
* @since 04.07.2003
*/
public class BeanFactoryUtilsTests {
@ -323,4 +324,106 @@ public class BeanFactoryUtilsTests { @@ -323,4 +324,106 @@ public class BeanFactoryUtilsTests {
assertThat(Arrays.equals(new String[] { "buffer" }, deps)).isTrue();
}
@Test
public void isSingletonAndIsPrototypeWithStaticFactory() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
TestBean bean = new TestBean();
DummyFactory fb1 = new DummyFactory();
DummyFactory fb2 = new DummyFactory();
fb2.setSingleton(false);
TestBeanSmartFactoryBean sfb1 = new TestBeanSmartFactoryBean(true, true);
TestBeanSmartFactoryBean sfb2 = new TestBeanSmartFactoryBean(true, false);
TestBeanSmartFactoryBean sfb3 = new TestBeanSmartFactoryBean(false, true);
TestBeanSmartFactoryBean sfb4 = new TestBeanSmartFactoryBean(false, false);
lbf.addBean("bean", bean);
lbf.addBean("fb1", fb1);
lbf.addBean("fb2", fb2);
lbf.addBean("sfb1", sfb1);
lbf.addBean("sfb2", sfb2);
lbf.addBean("sfb3", sfb3);
lbf.addBean("sfb4", sfb4);
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, true);
assertThat(beans.get("bean")).isSameAs(bean);
assertThat(beans.get("fb1")).isSameAs(fb1.getObject());
assertThat(beans.get("fb2")).isInstanceOf(TestBean.class);
assertThat(beans.get("sfb1")).isInstanceOf(TestBean.class);
assertThat(beans.get("sfb2")).isInstanceOf(TestBean.class);
assertThat(beans.get("sfb3")).isInstanceOf(TestBean.class);
assertThat(beans.get("sfb4")).isInstanceOf(TestBean.class);
assertThat(lbf.getBeanDefinitionCount()).isEqualTo(7);
assertThat(lbf.getBean("bean")).isInstanceOf(TestBean.class);
assertThat(lbf.getBean("&fb1")).isInstanceOf(FactoryBean.class);
assertThat(lbf.getBean("&fb2")).isInstanceOf(FactoryBean.class);
assertThat(lbf.getBean("&sfb1")).isInstanceOf(SmartFactoryBean.class);
assertThat(lbf.getBean("&sfb2")).isInstanceOf(SmartFactoryBean.class);
assertThat(lbf.getBean("&sfb3")).isInstanceOf(SmartFactoryBean.class);
assertThat(lbf.getBean("&sfb4")).isInstanceOf(SmartFactoryBean.class);
assertThat(lbf.isSingleton("bean")).isTrue();
assertThat(lbf.isSingleton("fb1")).isTrue();
assertThat(lbf.isSingleton("fb2")).isTrue();
assertThat(lbf.isSingleton("sfb1")).isTrue();
assertThat(lbf.isSingleton("sfb2")).isTrue();
assertThat(lbf.isSingleton("sfb3")).isTrue();
assertThat(lbf.isSingleton("sfb4")).isTrue();
assertThat(lbf.isSingleton("&fb1")).isTrue();
assertThat(lbf.isSingleton("&fb2")).isFalse();
assertThat(lbf.isSingleton("&sfb1")).isTrue();
assertThat(lbf.isSingleton("&sfb2")).isTrue();
assertThat(lbf.isSingleton("&sfb3")).isFalse();
assertThat(lbf.isSingleton("&sfb4")).isFalse();
assertThat(lbf.isPrototype("bean")).isFalse();
assertThat(lbf.isPrototype("fb1")).isFalse();
assertThat(lbf.isPrototype("fb2")).isFalse();
assertThat(lbf.isPrototype("sfb1")).isFalse();
assertThat(lbf.isPrototype("sfb2")).isFalse();
assertThat(lbf.isPrototype("sfb3")).isFalse();
assertThat(lbf.isPrototype("sfb4")).isFalse();
assertThat(lbf.isPrototype("&fb1")).isFalse();
assertThat(lbf.isPrototype("&fb2")).isTrue();
assertThat(lbf.isPrototype("&sfb1")).isTrue();
assertThat(lbf.isPrototype("&sfb2")).isFalse();
assertThat(lbf.isPrototype("&sfb3")).isTrue();
assertThat(lbf.isPrototype("&sfb4")).isTrue();
}
static class TestBeanSmartFactoryBean implements SmartFactoryBean<TestBean> {
private final TestBean testBean = new TestBean("enigma", 42);
private final boolean singleton;
private final boolean prototype;
TestBeanSmartFactoryBean(boolean singleton, boolean prototype) {
this.singleton = singleton;
this.prototype = prototype;
}
@Override
public boolean isSingleton() {
return this.singleton;
}
@Override
public boolean isPrototype() {
return this.prototype;
}
@Override
public Class<TestBean> getObjectType() {
return TestBean.class;
}
public TestBean getObject() throws Exception {
// We don't really care if the actual instance is a singleton or prototype
// for the tests that use this factory.
return this.testBean;
}
}
}

Loading…
Cancel
Save