diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index 86bbf183b25..13b5779c377 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -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 diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java index a0d90ea1610..d33452bee57 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java @@ -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 { 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 { 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 { 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 { 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 { 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 { 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 { 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(); diff --git a/spring-core/src/main/java/org/springframework/core/ResolvableType.java b/spring-core/src/main/java/org/springframework/core/ResolvableType.java index 3e076f8945f..08e072e0f01 100644 --- a/spring-core/src/main/java/org/springframework/core/ResolvableType.java +++ b/spring-core/src/main/java/org/springframework/core/ResolvableType.java @@ -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. + *

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 { /** * 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()