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
Component
Controller
Repository
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.
In above example following points are important to notice:
AppConfig is annotated with @ComponentScan("com.logicbig.example.bean")
All beans are annotated with @Component, except for MyService
which is just an interface
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 {
....
ServiceImplA is also annotated with @Lazy so it's @PostConstruct method will only be called when used first time rather than at start up.
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.