Backend Development 12 min read

Mastering Spring Boot 3 @ComponentScan: Advanced Configurations & Examples

This article provides a comprehensive, step‑by‑step guide to using Spring Boot 3's @ComponentScan annotation, covering basic usage, package filtering, include/exclude filters, lazy initialization, custom name generators, scoped proxies, and custom scope resolvers, complete with runnable code samples and output screenshots.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering Spring Boot 3 @ComponentScan: Advanced Configurations & Examples

1. Introduction

In Spring, the @ComponentScan annotation is a powerful tool for automatically detecting and registering beans annotated with @Component , @Service , @Repository , or @Controller . This article explores its hidden features and best practices.

2. Practical Cases

2.1 Basic Usage

With a simple @ComponentScan on the configuration class, Spring scans the current package and its sub‑packages, registering classes A , B , etc.

<code>package com.pack.ioc.scan_component;
@Component
public class A {}

package com.pack.ioc.scan_component.child;
@Component
public class B {}

@Configuration
@ComponentScan
public class AppConfig {}
</code>
<code>public class ComponentScanTest {
    public static void main(String[] args) {
        try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
            context.registerBean(AppConfig.class);
            context.refresh();
            System.out.println(Arrays.toString(context.getBeanDefinitionNames()));
        }
    }
}
</code>

Output shows both A and B are registered.

2.2 Specifying basePackages

<code>@ComponentScan(basePackages = {"com.pack.ioc.scan_component.child"})
public class AppConfig {}
</code>

Only beans in the specified sub‑package ( B ) are registered.

2.3 Specifying basePackageClasses

<code>@ComponentScan(basePackageClasses = {B.class})
public class AppConfig {}
</code>

Scanning is performed based on the package of the given class ( B ).

2.4 Using includeFilters

The excludeFilters and includeFilters attributes allow fine‑grained control. The FilterType enum provides the following values:

<code>public enum FilterType {
    ANNOTATION,
    ASSIGNABLE_TYPE,
    ASPECTJ,
    REGEX,
    CUSTOM
}
</code>

2.4.1 ANNOTATION

<code>@ComponentScan(includeFilters = @Filter(type = FilterType.ANNOTATION, classes = Pack.class))
public class AppConfig {}
</code>

Custom annotation @Pack is detected and its beans are registered.

2.4.2 ASPECTJ

<code>@ComponentScan(includeFilters = @Filter(type = FilterType.ASPECTJ, pattern = {"com.pack.*Pack*"}))
public class AppConfig {}
</code>

2.4.3 ASSIGNABLE_TYPE

<code>@ComponentScan(includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {DAO.class}))
public class AppConfig {}
</code>

All classes implementing DAO are scanned.

2.4.4 REGEX

<code>@ComponentScan(includeFilters = @Filter(type = FilterType.REGEX, pattern = {"com\\.pack\\..*Pack.*"}))
public class AppConfig {}
</code>

2.4.5 CUSTOM

<code>public class PackTypeFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader mr, MetadataReaderFactory mf) throws IOException {
        return mr.getAnnotationMetadata().hasAnnotation(Pack.class.getName());
    }
}

@ComponentScan(includeFilters = @Filter(type = FilterType.CUSTOM, classes = {PackTypeFilter.class}))
public class AppConfig {}
</code>

2.5 Specifying lazyInit

<code>@ComponentScan(lazyInit = true)
public class AppConfig {}
</code>

Beans are created lazily; initialization callbacks are not executed at context startup.

2.6 Specifying useDefaultFilters

<code>@ComponentScan(useDefaultFilters = false, includeFilters = @Filter(type = FilterType.CUSTOM, classes = {PackTypeFilter.class}))
public class AppConfig {}
</code>

Only custom filters are applied; default @Component detection is disabled.

2.7 Specifying nameGenerator

<code>public class PackBeanNameGenerator extends AnnotationBeanNameGenerator {
    @Override
    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
        String beanName = super.generateBeanName(definition, registry);
        beanName = beanName.replaceFirst("^.", beanName.substring(0, 1).toUpperCase());
        return "pack" + beanName;
    }
}

@ComponentScan(nameGenerator = PackBeanNameGenerator.class)
public class AppConfig {}
</code>

All bean names receive the pack prefix.

2.8 Specifying scopedProxy

<code>@Component
@Scope
public class A implements InitializingBean {}

@ComponentScan(scopedProxy = ScopedProxyMode.TARGET_CLASS)
public class AppConfig {}
</code>

The bean A is proxied using CGLIB.

2.9 Specifying scopeResolver

<code>@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PackScope {
    @AliasFor("scopeName") String value() default "";
    @AliasFor("value") String scopeName() default "";
    ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}

public class PackAnnotationScopeMetadataResolver extends AnnotationScopeMetadataResolver {
    public PackAnnotationScopeMetadataResolver() {
        setScopeAnnotationType(PackScope.class);
    }
}

@PackScope(proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class A implements InitializingBean {}
</code>

Custom scope annotation and resolver are applied successfully.

Conclusion

The article covered every aspect of the @ComponentScan annotation, including package selection, filter types, lazy initialization, custom bean name generation, scoped proxies, and custom scope resolution, providing a solid foundation for advanced Spring Boot configuration.

Backend DevelopmentSpring BootComponentScanSpring Framework
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.