The usual way
In Spring applications we usually create Beans using the annotations @Component, @Service, @Repository or @Controller. Classes having one of these annotations are detected by Spring and instantiated as Spring Beans with all dependency injection taking place.
@Service
class MySuperService {
...
}
The same is true for custom annotations which are themselves annotated with @Component.
@Component
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyBeanAnnotation {}
Using @ComponentScan
When defining a configuration class, we can configure in which packages (and sub-packages) Spring should search for Beans. By default all the classes with the above mentioned annotations are found.
@Configuration
@ComponentScan(basePackages = {"de.mindstack.mypackage.beans"})
public class MyConfiguration {}
If we want to exclude the standard beans we have to set the parameter useDefaultFilters to false.
@Configuration
@ComponentScan(
  basePackages = {"de.mindstack.mypackage.beans"},
  useDefaultFilters = false)
public class MyConfiguration {}
IncludeFilters
With the default filters deactivated, we can now define our own filters to find classes we want to instantiate as Beans. There a five types of filters available:
- ANNOTATION - classes having a specific annotation
 - ASSIGNABLE_TYPE - classes which derive from a specific class or implement a specific interface
 - REGEX - classes which match a given regular expression
 - ASPECTJ - classes which match complex AspectJ patterns
 - CUSTOM - custom filter implementation
 
FilterType.ANNOTATION
When we created a custom annotation and want all classes with this annotation to be instantiated as beans, we can use this filter.
// Declaring an annotation to be used with class that should be instantiated as beans
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyBeanAnnotation {}
// Class annotated with custom annotation will be instantiated as bean
@MyBeanAnnotation
public class MyClass {}
@Configuration
@ComponentScan(
  basePackages = {"de.mindstack.mypackage.beans"},
  useDefaultFilters = false,
  includeFilters = @ComponentScan.Filter(
    type = FilterType.ANNOTATION,
    classes = MyBeanAnnotation.class)
public class MyConfiguration {}
FilterType.ASSIGNABLE_TYPE
When we base class and want all subclasses or implementation of an interface to be instantiated as beans, we can use this filter.
interface MyBaseClass {}
// This class implements MyBaseClass and will be instantiated as bean
public class SubClassA implements MyBaseClass {}
// This class implements MyBaseClass and will be instantiated as bean
public class SubClassB implements MyBaseClass {}
@Configuration
@ComponentScan(
  basePackages = {"de.mindstack.mypackage.beans"},
  useDefaultFilters = false,
  includeFilters = @ComponentScan.Filter(
    type = FilterType.ASSIGNABLE_TYPE,
    classes = MyBaseClass.class)
public class MyConfiguration {}
FilterType.REGEX
We can select class names by matching regular expressions agains simple and fully-qualified class names.
// This class name matches the regex and will be instantiated as bean
public class MyMatchedClass {}
// This class name does not match the regex and will not be instantiated as bean
public class IgnoredClass {}
@Configuration
@ComponentScan(
  basePackages = {"de.mindstack.mypackage.beans"},
  useDefaultFilters = false,
  includeFilters = @ComponentScan.Filter(
    type = FilterType.REGEX,
    pattern = "Match")
public class MyConfiguration {}
FilterType.ASPECTJ
We can select classes by matching aspectj expressions.
// This class name matches the expression and will be instantiated as bean
public class MyMatchedClass {}
// This class name does not match the expression and will not be instantiated as bean
public class IgnoredClass {}
@Configuration
@ComponentScan(
  basePackages = {"de.mindstack.mypackage.beans"},
  useDefaultFilters = false,
  includeFilters = @ComponentScan.Filter(
    type = FilterType.ASPECTJ,
    pattern = "de.mindstack.mypackage.beans.My*")
public class MyConfiguration {}
FilterType.CUSTOM
We can implement our own filters by implementing TypeFilter inrerface. This way, we can create combined filters.
// This class name matches the expression and will be instantiated as bean
@MyBeanAnnotation
public class MyMatchedClass implements MyBaseClass {}
// This class name does not match the expression and will not be instantiated as bean
@MyBeanAnnotation
public class IgnoredClass {}
@Configuration
@ComponentScan(
  basePackages = {"de.mindstack.mypackage.beans"},
  useDefaultFilters = false,
  includeFilters = @ComponentScan.Filter(
    type = FilterType.CUSTOM,
    classes = CombinedFilter.class)
public class MyConfiguration {}
public class CombinedFilter implements TypeFilter {
  private final AssignableTypeFilter assignableTypeFilter;
  private final AnnotationTypeFilter annotationTypeFilter;
  public CombinedFilter() {
    assignableTypeFilter = new AssignableTypeFilter(MyBaseClass.class);
    annotationTypeFilter = new AnnotationTypeFilter(MyBeanAnnotation.class);
  }
  @Override
  public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
    return annotationTypeFilter.match(metadataReader, metadataReaderFactory)
        && assignableTypeFilter.match(metadataReader, metadataReaderFactory);
  }
}