提交 f2e4ad23 编写于 作者: J Juergen Hoeller

ComponentScan annotation allows for registering beans with lazy initialization

Issue: SPR-10459
上级 ef51d4db
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -163,6 +163,14 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo ...@@ -163,6 +163,14 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
(beanDefinitionDefaults != null ? beanDefinitionDefaults : new BeanDefinitionDefaults()); (beanDefinitionDefaults != null ? beanDefinitionDefaults : new BeanDefinitionDefaults());
} }
/**
* Return the defaults to use for detected beans (never {@code null}).
* @since 4.1
*/
public BeanDefinitionDefaults getBeanDefinitionDefaults() {
return this.beanDefinitionDefaults;
}
/** /**
* Set the name-matching patterns for determining autowire candidates. * Set the name-matching patterns for determining autowire candidates.
* @param autowireCandidatePatterns the patterns to match against * @param autowireCandidatePatterns the patterns to match against
......
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -132,6 +132,13 @@ public @interface ComponentScan { ...@@ -132,6 +132,13 @@ public @interface ComponentScan {
*/ */
Filter[] excludeFilters() default {}; Filter[] excludeFilters() default {};
/**
* Specify whether scanned beans should be registered for lazy initialization.
* <p>Default is {@code false}; switch this to {@code true} when desired.
* @since 4.1
*/
boolean lazyInit() default false;
/** /**
* Declares the type filter to be used as an {@linkplain ComponentScan#includeFilters() * Declares the type filter to be used as an {@linkplain ComponentScan#includeFilters()
......
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -106,6 +106,11 @@ class ComponentScanAnnotationParser { ...@@ -106,6 +106,11 @@ class ComponentScanAnnotationParser {
} }
} }
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
List<String> basePackages = new ArrayList<String>(); List<String> basePackages = new ArrayList<String>();
for (String pkg : componentScan.getStringArray("value")) { for (String pkg : componentScan.getStringArray("value")) {
if (StringUtils.hasText(pkg)) { if (StringUtils.hasText(pkg)) {
......
...@@ -23,7 +23,17 @@ import java.lang.annotation.RetentionPolicy; ...@@ -23,7 +23,17 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.util.HashSet; import java.util.HashSet;
import example.scannable.CustomComponent;
import example.scannable.CustomStereotype;
import example.scannable.DefaultNamedComponent;
import example.scannable.FooService;
import example.scannable.MessageBean;
import example.scannable.ScopedProxyTestBean;
import example.scannable_implicitbasepackage.ComponentScanAnnotatedConfigWithImplicitBasePackage;
import example.scannable_scoped.CustomScopeAnnotationBean;
import example.scannable_scoped.MyScope;
import org.junit.Test; import org.junit.Test;
import org.springframework.aop.support.AopUtils; import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.CustomAutowireConfigurer; import org.springframework.beans.factory.annotation.CustomAutowireConfigurer;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
...@@ -36,16 +46,6 @@ import org.springframework.context.support.GenericApplicationContext; ...@@ -36,16 +46,6 @@ import org.springframework.context.support.GenericApplicationContext;
import org.springframework.tests.context.SimpleMapScope; import org.springframework.tests.context.SimpleMapScope;
import org.springframework.util.SerializationTestUtils; import org.springframework.util.SerializationTestUtils;
import example.scannable.CustomComponent;
import example.scannable.CustomStereotype;
import example.scannable.DefaultNamedComponent;
import example.scannable.FooService;
import example.scannable.MessageBean;
import example.scannable.ScopedProxyTestBean;
import example.scannable_implicitbasepackage.ComponentScanAnnotatedConfigWithImplicitBasePackage;
import example.scannable_scoped.CustomScopeAnnotationBean;
import example.scannable_scoped.MyScope;
import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
...@@ -116,10 +116,10 @@ public class ComponentScanAnnotationIntegrationTests { ...@@ -116,10 +116,10 @@ public class ComponentScanAnnotationIntegrationTests {
ctx.getBean(ComposedAnnotationConfig.class); ctx.getBean(ComposedAnnotationConfig.class);
ctx.getBean(SimpleComponent.class); ctx.getBean(SimpleComponent.class);
assertThat("config class bean not found", assertThat("config class bean not found",
ctx.containsBeanDefinition("componentScanAnnotationIntegrationTests.ComposedAnnotationConfig"), is(true)); ctx.containsBeanDefinition("componentScanAnnotationIntegrationTests.ComposedAnnotationConfig"), is(true));
assertThat("@ComponentScan annotated @Configuration class registered directly against " assertThat("@ComponentScan annotated @Configuration class registered directly against " +
+ "AnnotationConfigApplicationContext did not trigger component scanning as expected", "AnnotationConfigApplicationContext did not trigger component scanning as expected",
ctx.containsBean("simpleComponent"), is(true)); ctx.containsBean("simpleComponent"), is(true));
} }
@Test @Test
...@@ -159,7 +159,8 @@ public class ComponentScanAnnotationIntegrationTests { ...@@ -159,7 +159,8 @@ public class ComponentScanAnnotationIntegrationTests {
@Test @Test
public void withCustomTypeFilter() { public void withCustomTypeFilter() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ComponentScanWithCustomTypeFilter.class); AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ComponentScanWithCustomTypeFilter.class);
KustomAnnotationAutowiredBean testBean = ctx.getBean(KustomAnnotationAutowiredBean.class); assertFalse(ctx.getDefaultListableBeanFactory().containsSingleton("kustomBean"));
KustomAnnotationAutowiredBean testBean = ctx.getBean("kustomBean", KustomAnnotationAutowiredBean.class);
assertThat(testBean.getDependency(), notNullValue()); assertThat(testBean.getDependency(), notNullValue());
} }
...@@ -294,7 +295,8 @@ class MyScopeMetadataResolver extends AnnotationScopeMetadataResolver { ...@@ -294,7 +295,8 @@ class MyScopeMetadataResolver extends AnnotationScopeMetadataResolver {
useDefaultFilters=false, useDefaultFilters=false,
includeFilters=@Filter(type=FilterType.CUSTOM, value=ComponentScanParserTests.CustomTypeFilter.class), includeFilters=@Filter(type=FilterType.CUSTOM, value=ComponentScanParserTests.CustomTypeFilter.class),
// exclude this class from scanning since it's in the scanned package // exclude this class from scanning since it's in the scanned package
excludeFilters=@Filter(type=FilterType.ASSIGNABLE_TYPE, value=ComponentScanWithCustomTypeFilter.class)) excludeFilters=@Filter(type=FilterType.ASSIGNABLE_TYPE, value=ComponentScanWithCustomTypeFilter.class),
lazyInit = true)
class ComponentScanWithCustomTypeFilter { class ComponentScanWithCustomTypeFilter {
@Bean @Bean
@SuppressWarnings({ "rawtypes", "serial", "unchecked" }) @SuppressWarnings({ "rawtypes", "serial", "unchecked" })
......
/* /*
* Copyright 2002-2010 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package org.springframework.context.annotation; package org.springframework.context.annotation;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.support.DefaultBeanNameGenerator; import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.type.filter.TypeFilter; import org.springframework.core.type.filter.TypeFilter;
...@@ -29,6 +30,7 @@ import org.springframework.core.type.filter.TypeFilter; ...@@ -29,6 +30,7 @@ import org.springframework.core.type.filter.TypeFilter;
* @see ComponentScanAnnotationIntegrationTests * @see ComponentScanAnnotationIntegrationTests
*/ */
public class ComponentScanAnnotationTests { public class ComponentScanAnnotationTests {
@Test @Test
public void noop() { public void noop() {
// no-op; the @ComponentScan-annotated MyConfig class below simply excercises // no-op; the @ComponentScan-annotated MyConfig class below simply excercises
...@@ -36,7 +38,9 @@ public class ComponentScanAnnotationTests { ...@@ -36,7 +38,9 @@ public class ComponentScanAnnotationTests {
} }
} }
@interface MyAnnotation { }
@interface MyAnnotation {
}
@Configuration @Configuration
@ComponentScan( @ComponentScan(
...@@ -44,18 +48,19 @@ public class ComponentScanAnnotationTests { ...@@ -44,18 +48,19 @@ public class ComponentScanAnnotationTests {
nameGenerator = DefaultBeanNameGenerator.class, nameGenerator = DefaultBeanNameGenerator.class,
scopedProxy = ScopedProxyMode.NO, scopedProxy = ScopedProxyMode.NO,
scopeResolver = AnnotationScopeMetadataResolver.class, scopeResolver = AnnotationScopeMetadataResolver.class,
useDefaultFilters = false,
resourcePattern = "**/*custom.class", resourcePattern = "**/*custom.class",
useDefaultFilters = false,
includeFilters = { includeFilters = {
@Filter(type = FilterType.ANNOTATION, value = MyAnnotation.class) @Filter(type = FilterType.ANNOTATION, value = MyAnnotation.class)
}, },
excludeFilters = { excludeFilters = {
@Filter(type = FilterType.CUSTOM, value = TypeFilter.class) @Filter(type = FilterType.CUSTOM, value = TypeFilter.class)
} },
lazyInit = true
) )
class MyConfig { class MyConfig {
} }
@ComponentScan(basePackageClasses=example.scannable.NamedComponent.class) @ComponentScan(basePackageClasses=example.scannable.NamedComponent.class)
class SimpleConfig { } class SimpleConfig {
\ No newline at end of file }
...@@ -21,7 +21,10 @@ import java.lang.annotation.Retention; ...@@ -21,7 +21,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import example.profilescan.ProfileAnnotatedComponent;
import example.scannable.AutowiredQualifierFooService;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
...@@ -29,9 +32,7 @@ import org.springframework.context.support.GenericXmlApplicationContext; ...@@ -29,9 +32,7 @@ import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter; import org.springframework.core.type.filter.TypeFilter;
import org.springframework.stereotype.Component;
import example.profilescan.ProfileAnnotatedComponent;
import example.scannable.AutowiredQualifierFooService;
import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
...@@ -134,13 +135,13 @@ public class ComponentScanParserTests { ...@@ -134,13 +135,13 @@ public class ComponentScanParserTests {
* Intentionally spelling "custom" with a "k" since there are numerous * Intentionally spelling "custom" with a "k" since there are numerous
* classes in this package named *Custom*. * classes in this package named *Custom*.
*/ */
@Component("kustomBean")
public static class KustomAnnotationAutowiredBean { public static class KustomAnnotationAutowiredBean {
@Autowired @Autowired
@CustomAnnotation @CustomAnnotation
private KustomAnnotationDependencyBean dependency; private KustomAnnotationDependencyBean dependency;
public KustomAnnotationDependencyBean getDependency() { public KustomAnnotationDependencyBean getDependency() {
return this.dependency; return this.dependency;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册