Browse Source

ResolvableType-based resolution uses BeanNamesByType cache if possible

Issue: SPR-17282
pull/1961/head
Juergen Hoeller 7 years ago
parent
commit
c634b2fae7
  1. 8
      spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
  2. 63
      spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java
  3. 11
      spring-core/src/main/java/org/springframework/core/ResolvableType.java

8
spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

@ -453,7 +453,13 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -453,7 +453,13 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
public String[] getBeanNamesForType(ResolvableType type) {
return doGetBeanNamesForType(type, true, true);
Class<?> resolved = type.resolve();
if (resolved != null && !type.hasGenerics()) {
return getBeanNamesForType(resolved, true, true);
}
else {
return doGetBeanNamesForType(type, true, true);
}
}
@Override

63
spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java

@ -2440,6 +2440,7 @@ public class DefaultListableBeanFactoryTests { @@ -2440,6 +2440,7 @@ public class DefaultListableBeanFactoryTests {
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
lbf.registerBeanDefinition("test", rbd);
lbf.freezeConfiguration();
StopWatch sw = new StopWatch();
sw.start("prototype");
for (int i = 0; i < 100000; i++) {
@ -2460,6 +2461,7 @@ public class DefaultListableBeanFactoryTests { @@ -2460,6 +2461,7 @@ public class DefaultListableBeanFactoryTests {
rbd.setDependencyCheck(RootBeanDefinition.DEPENDENCY_CHECK_OBJECTS);
lbf.registerBeanDefinition("test", rbd);
lbf.addBeanPostProcessor(new LifecycleBean.PostProcessor());
lbf.freezeConfiguration();
StopWatch sw = new StopWatch();
sw.start("prototype");
for (int i = 0; i < 100000; i++) {
@ -2470,29 +2472,6 @@ public class DefaultListableBeanFactoryTests { @@ -2470,29 +2472,6 @@ public class DefaultListableBeanFactoryTests {
assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 3000);
}
/**
* @Test
* public void testPrototypeCreationIsFastEnough2() {
* if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) {
* // Skip this test: Trace logging blows the time limit.
* return;
* }
* DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
* Method setBeanNameMethod = TestBean.class.getMethod("setBeanName", String.class);
* Method setBeanFactoryMethod = TestBean.class.getMethod("setBeanFactory", BeanFactory.class);
* StopWatch sw = new StopWatch();
* sw.start("prototype");
* for (int i = 0; i < 100000; i++) {
* TestBean tb = TestBean.class.newInstance();
* setBeanNameMethod.invoke(tb, "test");
* setBeanFactoryMethod.invoke(tb, lbf);
* }
* sw.stop();
* // System.out.println(sw.getTotalTimeMillis());
* assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 500);
* }
*/
@Test
@Ignore // TODO re-enable when ConstructorResolver TODO sorted out
public void testPrototypeCreationWithConstructorArgumentsIsFastEnough() {
@ -2504,6 +2483,7 @@ public class DefaultListableBeanFactoryTests { @@ -2504,6 +2483,7 @@ public class DefaultListableBeanFactoryTests {
rbd.getConstructorArgumentValues().addGenericArgumentValue("juergen");
rbd.getConstructorArgumentValues().addGenericArgumentValue("99");
lbf.registerBeanDefinition("test", rbd);
lbf.freezeConfiguration();
StopWatch sw = new StopWatch();
sw.start("prototype");
for (int i = 0; i < 100000; i++) {
@ -2526,6 +2506,7 @@ public class DefaultListableBeanFactoryTests { @@ -2526,6 +2506,7 @@ public class DefaultListableBeanFactoryTests {
rbd.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference("spouse"));
lbf.registerBeanDefinition("test", rbd);
lbf.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class));
lbf.freezeConfiguration();
TestBean spouse = (TestBean) lbf.getBean("spouse");
StopWatch sw = new StopWatch();
sw.start("prototype");
@ -2548,6 +2529,7 @@ public class DefaultListableBeanFactoryTests { @@ -2548,6 +2529,7 @@ public class DefaultListableBeanFactoryTests {
rbd.getPropertyValues().add("name", "juergen");
rbd.getPropertyValues().add("age", "99");
lbf.registerBeanDefinition("test", rbd);
lbf.freezeConfiguration();
StopWatch sw = new StopWatch();
sw.start("prototype");
for (int i = 0; i < 100000; i++) {
@ -2570,6 +2552,7 @@ public class DefaultListableBeanFactoryTests { @@ -2570,6 +2552,7 @@ public class DefaultListableBeanFactoryTests {
rbd.getPropertyValues().add("spouse", new RuntimeBeanReference("spouse"));
lbf.registerBeanDefinition("test", rbd);
lbf.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class));
lbf.freezeConfiguration();
TestBean spouse = (TestBean) lbf.getBean("spouse");
StopWatch sw = new StopWatch();
sw.start("prototype");
@ -2582,6 +2565,40 @@ public class DefaultListableBeanFactoryTests { @@ -2582,6 +2565,40 @@ public class DefaultListableBeanFactoryTests {
assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000);
}
@Test
public void testSingletonLookupByNameIsFastEnough() {
// Assume.group(TestGroup.PERFORMANCE);
Assume.notLogging(factoryLog);
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
lbf.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class));
lbf.freezeConfiguration();
StopWatch sw = new StopWatch();
sw.start("singleton");
for (int i = 0; i < 1000000; i++) {
lbf.getBean("test");
}
sw.stop();
// System.out.println(sw.getTotalTimeMillis());
assertTrue("Singleton lookup took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 1000);
}
@Test
public void testSingletonLookupByTypeIsFastEnough() {
// Assume.group(TestGroup.PERFORMANCE);
Assume.notLogging(factoryLog);
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
lbf.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class));
lbf.freezeConfiguration();
StopWatch sw = new StopWatch();
sw.start("singleton");
for (int i = 0; i < 1000000; i++) {
lbf.getBean(TestBean.class);
}
sw.stop();
// System.out.println(sw.getTotalTimeMillis());
assertTrue("Singleton lookup took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 1000);
}
@Test
public void testBeanPostProcessorWithWrappedObjectAndDisposableBean() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();

11
spring-core/src/main/java/org/springframework/core/ResolvableType.java

@ -765,8 +765,11 @@ public class ResolvableType implements Serializable { @@ -765,8 +765,11 @@ public class ResolvableType implements Serializable {
/**
* Resolve this type to a {@link java.lang.Class}, returning {@code null}
* if the type cannot be resolved. This method will consider bounds of
* {@link TypeVariable TypeVariables} and {@link WildcardType WildcardTypes} if direct resolution fails;
* however, bounds of {@code Object.class} will be ignored.
* {@link TypeVariable TypeVariables} and {@link WildcardType WildcardTypes} if
* direct resolution fails; however, bounds of {@code Object.class} will be ignored.
* <p>If this method returns a non-null {@code Class} and {@link #hasGenerics()}
* returns {@code false}, the given type effectively wraps a plain {@code Class},
* allowing for plain {@code Class} processing if desirable.
* @return the resolved {@link Class}, or {@code null} if not resolvable
* @see #resolve(Class)
* @see #resolveGeneric(int...)
@ -780,8 +783,8 @@ public class ResolvableType implements Serializable { @@ -780,8 +783,8 @@ public class ResolvableType implements Serializable {
/**
* Resolve this type to a {@link java.lang.Class}, returning the specified
* {@code fallback} if the type cannot be resolved. This method will consider bounds
* of {@link TypeVariable TypeVariables} and {@link WildcardType WildcardTypes} if direct resolution fails;
* however, bounds of {@code Object.class} will be ignored.
* of {@link TypeVariable TypeVariables} and {@link WildcardType WildcardTypes} if
* direct resolution fails; however, bounds of {@code Object.class} will be ignored.
* @param fallback the fallback class to use if resolution fails
* @return the resolved {@link Class} or the {@code fallback}
* @see #resolve()

Loading…
Cancel
Save