Browse Source

ComponentScan annotation allows for registering beans with lazy initialization

Issue: SPR-10459
pull/610/merge
Juergen Hoeller 12 years ago
parent
commit
f2e4ad2364
  1. 10
      spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java
  2. 9
      spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java
  3. 7
      spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java
  4. 34
      spring-context/src/test/java/org/springframework/context/annotation/ComponentScanAnnotationIntegrationTests.java
  5. 17
      spring-context/src/test/java/org/springframework/context/annotation/ComponentScanAnnotationTests.java
  6. 9
      spring-context/src/test/java/org/springframework/context/annotation/ComponentScanParserTests.java

10
spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* 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");
* 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());
}
/**
* 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.
* @param autowireCandidatePatterns the patterns to match against

9
spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* 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");
* 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 {};
/**
* 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()

7
spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* 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");
* 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>();
for (String pkg : componentScan.getStringArray("value")) {
if (StringUtils.hasText(pkg)) {

34
spring-context/src/test/java/org/springframework/context/annotation/ComponentScanAnnotationIntegrationTests.java

@ -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.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.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.CustomAutowireConfigurer;
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.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.junit.Assert.*;
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(SimpleComponent.class);
assertThat("config class bean not found",
ctx.containsBeanDefinition("componentScanAnnotationIntegrationTests.ComposedAnnotationConfig"), is(true));
assertThat("@ComponentScan annotated @Configuration class registered directly against "
+ "AnnotationConfigApplicationContext did not trigger component scanning as expected",
ctx.containsBean("simpleComponent"), is(true));
ctx.containsBeanDefinition("componentScanAnnotationIntegrationTests.ComposedAnnotationConfig"), is(true));
assertThat("@ComponentScan annotated @Configuration class registered directly against " +
"AnnotationConfigApplicationContext did not trigger component scanning as expected",
ctx.containsBean("simpleComponent"), is(true));
}
@Test
@ -159,7 +159,8 @@ public class ComponentScanAnnotationIntegrationTests { @@ -159,7 +159,8 @@ public class ComponentScanAnnotationIntegrationTests {
@Test
public void withCustomTypeFilter() {
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());
}
@ -294,7 +295,8 @@ class MyScopeMetadataResolver extends AnnotationScopeMetadataResolver { @@ -294,7 +295,8 @@ class MyScopeMetadataResolver extends AnnotationScopeMetadataResolver {
useDefaultFilters=false,
includeFilters=@Filter(type=FilterType.CUSTOM, value=ComponentScanParserTests.CustomTypeFilter.class),
// 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 {
@Bean
@SuppressWarnings({ "rawtypes", "serial", "unchecked" })

17
spring-context/src/test/java/org/springframework/context/annotation/ComponentScanAnnotationTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* 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");
* 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;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan.Filter;
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
*/
public class ComponentScanAnnotationTests {
@Test
public void noop() {
// 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
@ComponentScan(
@ -44,18 +48,19 @@ public class ComponentScanAnnotationTests { @@ -44,18 +48,19 @@ public class ComponentScanAnnotationTests {
nameGenerator = DefaultBeanNameGenerator.class,
scopedProxy = ScopedProxyMode.NO,
scopeResolver = AnnotationScopeMetadataResolver.class,
useDefaultFilters = false,
resourcePattern = "**/*custom.class",
useDefaultFilters = false,
includeFilters = {
@Filter(type = FilterType.ANNOTATION, value = MyAnnotation.class)
},
excludeFilters = {
@Filter(type = FilterType.CUSTOM, value = TypeFilter.class)
}
},
lazyInit = true
)
class MyConfig {
}
@ComponentScan(basePackageClasses=example.scannable.NamedComponent.class)
class SimpleConfig { }
class SimpleConfig {
}

9
spring-context/src/test/java/org/springframework/context/annotation/ComponentScanParserTests.java

@ -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.Target;
import example.profilescan.ProfileAnnotatedComponent;
import example.scannable.AutowiredQualifierFooService;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
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.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import example.profilescan.ProfileAnnotatedComponent;
import example.scannable.AutowiredQualifierFooService;
import org.springframework.stereotype.Component;
import static org.hamcrest.CoreMatchers.*;
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
* classes in this package named *Custom*.
*/
@Component("kustomBean")
public static class KustomAnnotationAutowiredBean {
@Autowired
@CustomAnnotation
private KustomAnnotationDependencyBean dependency;
public KustomAnnotationDependencyBean getDependency() {
return this.dependency;
}

Loading…
Cancel
Save