Spring - JavaConfig with Component Scan

[Updated: Aug 30, 2016, Created: Jan 2, 2016]

To configure Spring container with our beans, we can mix XML's <context:component-scan> with JavaConfig configuration. We can even avoid XML altogether by using @ComponentScan. There too we can mix the factory approach along with scan approach. In factory approach we annotate classes with @Configuration having methods annotated with @Bean which return bean instances). For component scanning to work we must annotate our beans with one of the stereotype annotations

  1. Component
  2. Controller
  3. Repository
  4. Service

Classes annotated with one of the above are candidate for spring container registration when using scanning. The most important is Component annotation. The rest are specialization of Component. Each one is annotated with Component itself. They represent the roles in the overall application design.

you can annotate your component classes with @Component, but by annotating them with @Repository, @Service, or @Controller instead, your classes are more properly suited for processing by tools or associating with aspects. For example, these stereotype annotations make ideal targets for pointcuts. It is also possible that @Repository, @Service, and @Controller may carry additional semantics in future releases of the Spring Framework. Thus, if you are choosing between using @Component or @Service for your service layer, @Service is clearly the better choice.

Along with above annotations we can tag our beans with any of @Lazy, @DependsOn, @Scope etc to specify their specific behavior (as we saw in previous examples)



Example Project

In this example we are going to demonstrate component scanning along with various concepts we have learnt so far.

Dependencies and Technologies Used :

  • Spring Context 4.2.3.RELEASE: Spring Context.
  • JDK 1.8
  • Maven 3.0.4

Component Scanning Example Select All Download
  • component-scanning-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • app
                • bean

In above example following points are important to notice:

  1. AppConfig is annotated with @ComponentScan("com.logicbig.example.bean")
  2. All beans are annotated with @Component, except for MyService which is just an interface
  3. There are two implementations of MyService : ServiceImplA and ServiceImplB. So to avoid ambiguity, we named ServiceImplA by using @Component("basic-service") . We could have used @Qualifier instead for naming the bean component:
    @Component
    @Qualifier("basic-service")
    public class ServiceImplA implements MyService {
    
    ....
  4. ServiceImplA is also annotated with @Lazy so it's @PostConstruct method will only be called when used first time rather than at start up.
  5. MyPrototypeBean is annotated with @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) and also has dependency of MyService. Notice the usual use of @Autowired and @Qualifier. We could have used just @Resource("basic-service") instead.

On running AppConfig, we get the expected output:

initializing MySingletonBean
initializing at start up ServiceImplB
Spring container started and is ready
initializing lazily ServiceImplA
Message from ServiceImplA


Spring Stereotype Annotations are not Inherited

None of the stereotype annotations are tagged with @Inherited. That means we cannot expect sub classes to inherit the stereotype annotations. We have to add them explicitly to each sub classes. Same is true for other annotations like Scope, Lazy etc. As per general Java concept, we can make use of method/fields/constructor level annotation from super classes, i.e. we don't have to repeat them in subclasses. In case of method overriding (typically setters in Spring), we have to explicitly add annotations in overridden methods, even though they are already present in the original super class methods.

See Also