Skip to content

Commit c634b2f

Browse files
committed
ResolvableType-based resolution uses BeanNamesByType cache if possible
Issue: SPR-17282
1 parent 00a3afc commit c634b2f

File tree

3 files changed

+54
-28
lines changed

3 files changed

+54
-28
lines changed

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,13 @@ public String[] getBeanDefinitionNames() {
453453

454454
@Override
455455
public String[] getBeanNamesForType(ResolvableType type) {
456-
return doGetBeanNamesForType(type, true, true);
456+
Class<?> resolved = type.resolve();
457+
if (resolved != null && !type.hasGenerics()) {
458+
return getBeanNamesForType(resolved, true, true);
459+
}
460+
else {
461+
return doGetBeanNamesForType(type, true, true);
462+
}
457463
}
458464

459465
@Override

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

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2440,6 +2440,7 @@ public void testPrototypeCreationIsFastEnough() {
24402440
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
24412441
rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
24422442
lbf.registerBeanDefinition("test", rbd);
2443+
lbf.freezeConfiguration();
24432444
StopWatch sw = new StopWatch();
24442445
sw.start("prototype");
24452446
for (int i = 0; i < 100000; i++) {
@@ -2460,6 +2461,7 @@ public void testPrototypeCreationWithDependencyCheckIsFastEnough() {
24602461
rbd.setDependencyCheck(RootBeanDefinition.DEPENDENCY_CHECK_OBJECTS);
24612462
lbf.registerBeanDefinition("test", rbd);
24622463
lbf.addBeanPostProcessor(new LifecycleBean.PostProcessor());
2464+
lbf.freezeConfiguration();
24632465
StopWatch sw = new StopWatch();
24642466
sw.start("prototype");
24652467
for (int i = 0; i < 100000; i++) {
@@ -2470,29 +2472,6 @@ public void testPrototypeCreationWithDependencyCheckIsFastEnough() {
24702472
assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 3000);
24712473
}
24722474

2473-
/**
2474-
* @Test
2475-
* public void testPrototypeCreationIsFastEnough2() {
2476-
* if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) {
2477-
* // Skip this test: Trace logging blows the time limit.
2478-
* return;
2479-
* }
2480-
* DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
2481-
* Method setBeanNameMethod = TestBean.class.getMethod("setBeanName", String.class);
2482-
* Method setBeanFactoryMethod = TestBean.class.getMethod("setBeanFactory", BeanFactory.class);
2483-
* StopWatch sw = new StopWatch();
2484-
* sw.start("prototype");
2485-
* for (int i = 0; i < 100000; i++) {
2486-
* TestBean tb = TestBean.class.newInstance();
2487-
* setBeanNameMethod.invoke(tb, "test");
2488-
* setBeanFactoryMethod.invoke(tb, lbf);
2489-
* }
2490-
* sw.stop();
2491-
* // System.out.println(sw.getTotalTimeMillis());
2492-
* assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 500);
2493-
* }
2494-
*/
2495-
24962475
@Test
24972476
@Ignore // TODO re-enable when ConstructorResolver TODO sorted out
24982477
public void testPrototypeCreationWithConstructorArgumentsIsFastEnough() {
@@ -2504,6 +2483,7 @@ public void testPrototypeCreationWithConstructorArgumentsIsFastEnough() {
25042483
rbd.getConstructorArgumentValues().addGenericArgumentValue("juergen");
25052484
rbd.getConstructorArgumentValues().addGenericArgumentValue("99");
25062485
lbf.registerBeanDefinition("test", rbd);
2486+
lbf.freezeConfiguration();
25072487
StopWatch sw = new StopWatch();
25082488
sw.start("prototype");
25092489
for (int i = 0; i < 100000; i++) {
@@ -2526,6 +2506,7 @@ public void testPrototypeCreationWithResolvedConstructorArgumentsIsFastEnough()
25262506
rbd.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference("spouse"));
25272507
lbf.registerBeanDefinition("test", rbd);
25282508
lbf.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class));
2509+
lbf.freezeConfiguration();
25292510
TestBean spouse = (TestBean) lbf.getBean("spouse");
25302511
StopWatch sw = new StopWatch();
25312512
sw.start("prototype");
@@ -2548,6 +2529,7 @@ public void testPrototypeCreationWithPropertiesIsFastEnough() {
25482529
rbd.getPropertyValues().add("name", "juergen");
25492530
rbd.getPropertyValues().add("age", "99");
25502531
lbf.registerBeanDefinition("test", rbd);
2532+
lbf.freezeConfiguration();
25512533
StopWatch sw = new StopWatch();
25522534
sw.start("prototype");
25532535
for (int i = 0; i < 100000; i++) {
@@ -2570,6 +2552,7 @@ public void testPrototypeCreationWithResolvedPropertiesIsFastEnough() {
25702552
rbd.getPropertyValues().add("spouse", new RuntimeBeanReference("spouse"));
25712553
lbf.registerBeanDefinition("test", rbd);
25722554
lbf.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class));
2555+
lbf.freezeConfiguration();
25732556
TestBean spouse = (TestBean) lbf.getBean("spouse");
25742557
StopWatch sw = new StopWatch();
25752558
sw.start("prototype");
@@ -2582,6 +2565,40 @@ public void testPrototypeCreationWithResolvedPropertiesIsFastEnough() {
25822565
assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000);
25832566
}
25842567

2568+
@Test
2569+
public void testSingletonLookupByNameIsFastEnough() {
2570+
// Assume.group(TestGroup.PERFORMANCE);
2571+
Assume.notLogging(factoryLog);
2572+
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
2573+
lbf.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class));
2574+
lbf.freezeConfiguration();
2575+
StopWatch sw = new StopWatch();
2576+
sw.start("singleton");
2577+
for (int i = 0; i < 1000000; i++) {
2578+
lbf.getBean("test");
2579+
}
2580+
sw.stop();
2581+
// System.out.println(sw.getTotalTimeMillis());
2582+
assertTrue("Singleton lookup took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 1000);
2583+
}
2584+
2585+
@Test
2586+
public void testSingletonLookupByTypeIsFastEnough() {
2587+
// Assume.group(TestGroup.PERFORMANCE);
2588+
Assume.notLogging(factoryLog);
2589+
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
2590+
lbf.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class));
2591+
lbf.freezeConfiguration();
2592+
StopWatch sw = new StopWatch();
2593+
sw.start("singleton");
2594+
for (int i = 0; i < 1000000; i++) {
2595+
lbf.getBean(TestBean.class);
2596+
}
2597+
sw.stop();
2598+
// System.out.println(sw.getTotalTimeMillis());
2599+
assertTrue("Singleton lookup took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 1000);
2600+
}
2601+
25852602
@Test
25862603
public void testBeanPostProcessorWithWrappedObjectAndDisposableBean() {
25872604
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -765,8 +765,11 @@ public Class<?> resolveGeneric(int... indexes) {
765765
/**
766766
* Resolve this type to a {@link java.lang.Class}, returning {@code null}
767767
* if the type cannot be resolved. This method will consider bounds of
768-
* {@link TypeVariable TypeVariables} and {@link WildcardType WildcardTypes} if direct resolution fails;
769-
* however, bounds of {@code Object.class} will be ignored.
768+
* {@link TypeVariable TypeVariables} and {@link WildcardType WildcardTypes} if
769+
* direct resolution fails; however, bounds of {@code Object.class} will be ignored.
770+
* <p>If this method returns a non-null {@code Class} and {@link #hasGenerics()}
771+
* returns {@code false}, the given type effectively wraps a plain {@code Class},
772+
* allowing for plain {@code Class} processing if desirable.
770773
* @return the resolved {@link Class}, or {@code null} if not resolvable
771774
* @see #resolve(Class)
772775
* @see #resolveGeneric(int...)
@@ -780,8 +783,8 @@ public Class<?> resolve() {
780783
/**
781784
* Resolve this type to a {@link java.lang.Class}, returning the specified
782785
* {@code fallback} if the type cannot be resolved. This method will consider bounds
783-
* of {@link TypeVariable TypeVariables} and {@link WildcardType WildcardTypes} if direct resolution fails;
784-
* however, bounds of {@code Object.class} will be ignored.
786+
* of {@link TypeVariable TypeVariables} and {@link WildcardType WildcardTypes} if
787+
* direct resolution fails; however, bounds of {@code Object.class} will be ignored.
785788
* @param fallback the fallback class to use if resolution fails
786789
* @return the resolved {@link Class} or the {@code fallback}
787790
* @see #resolve()

0 commit comments

Comments
 (0)