By WebNest Studio Engineering Team
Spring Framework Tutorial
Spring Beans
A "bean" in Spring is simply an object that the IoC container instantiates, configures, and manages on your behalf, as opposed to an object you create yourself with "new". Beans are the fundamental building blocks of a Spring application — controllers, services, repositories, and configuration objects are all beans once the container is responsible for their lifecycle.
Spring identifies which classes should become beans primarily through stereotype annotations, and it controls how many instances of a bean exist and how long they live through bean scopes. Understanding both of these — stereotypes and scopes — is essential before touching more advanced Spring features, because nearly everything else in the framework (AOP, transactions, MVC controllers) operates on beans that the container already manages.
Stereotype Annotations
Spring provides several specialized annotations that mark a class as a candidate for auto-detection and registration as a bean. All of them are built on top of the generic @Component annotation, but using the more specific one communicates intent and, for some, adds extra behavior.
@Component— the generic stereotype; any class annotated with it becomes a bean during component scanning.@Service— marks a class that holds business logic; semantically identical to @Component but clarifies the layer.@Repository— marks a data-access class; Spring also translates its persistence-related exceptions into Spring's unchecked DataAccessException hierarchy.@Controller/@RestController— marks a class as a Spring MVC web endpoint handler; @RestController combines @Controller with @ResponseBody.
Bean Scopes
A bean's scope determines how many instances of it the container creates and how long each instance lives. The two scopes used in the vast majority of applications are singleton and prototype.
- singleton (default) — exactly one shared instance per Spring container, created once and reused for every injection point.
- prototype — a brand-new instance is created every time the bean is requested from the container or injected elsewhere.
- Web-aware scopes also exist —
request,session, andapplication— but only apply in a web application context.
Declaring Scope Explicitly
Scope is set with the @Scope annotation, most commonly @Scope("singleton") or @Scope("prototype"), applied on the same class as the stereotype annotation. Because singleton beans are shared, they must be designed to be stateless or thread-safe; prototype beans are safer for holding request-specific mutable state, but the container does not manage their destruction callbacks the way it does for singletons.
Example
A singleton service bean and a prototype bean requested twice
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Component
@Scope("prototype")
class ShoppingCart {
// Each injection/lookup gets a new instance.
}
@Service
class CheckoutService {
// Default scope is singleton: one shared instance for the whole app.
}
@Configuration
@ComponentScan(basePackages = "com.webnest.beansdemo")
class AppConfig { }
public class BeanScopeDemo {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ShoppingCart cart1 = context.getBean(ShoppingCart.class);
ShoppingCart cart2 = context.getBean(ShoppingCart.class);
System.out.println("Prototype beans equal? " + (cart1 == cart2));
CheckoutService service1 = context.getBean(CheckoutService.class);
CheckoutService service2 = context.getBean(CheckoutService.class);
System.out.println("Singleton beans equal? " + (service1 == service2));
}
}
Prototype beans equal? false
Singleton beans equal? true
Common Mistakes
- Assuming @Service, @Repository, and @Controller behave completely differently from @Component — functionally they are almost the same, differing mainly in semantics and (for @Repository) exception translation.
- Injecting a prototype-scoped bean into a singleton bean directly and expecting a fresh instance on every use — the singleton only receives the prototype once, at its own creation, unless a proxy or ObjectFactory/Provider is used.
- Storing per-request mutable state in a singleton bean's fields, causing data to leak between unrelated requests or threads.
- Forgetting that prototype beans do not get their @PreDestroy lifecycle callback invoked automatically by the container — cleanup must be handled manually.
Exercise
Using the lesson's A singleton service bean and a prototype bean requested twice example, create a small implementation or design sketch that demonstrates @Component, @Service, @Repository, and @Controller/@RestController are stereotype annotations that register a class as a Spring bean.. Add a test case or scenario that would catch Assuming @Service, @Repository, and @Controller behave completely differently from @Component — functionally they are almost the same, differing mainly in semantics and (for @Repository) exception translation., and describe the expected result.
Show hints
- Start with Stereotype Annotations and compare your approach with A singleton service bean and a prototype bean requested twice. Identify the decision or behavior the lesson recommends.
- Walk through your scenario step by step. Confirm that it follows @Component, @Service, @Repository, and @Controller/@RestController are stereotype annotations that register a class as a Spring bean. and that it would catch the failure described by Assuming @Service, @Repository, and @Controller behave completely differently from @Component — functionally they are almost the same, differing mainly in semantics and (for @Repository) exception translation..
Quick quiz
1. Which choice is a mistake to avoid in Spring Beans?
- A. Injecting a prototype-scoped bean into a singleton bean directly and expecting a fresh instance on every use — the singleton only receives the prototype once, at its own creation, unless a proxy or ObjectFactory/Provider is used.
- B. @Component, @Service, @Repository, and @Controller/@RestController are stereotype annotations that register a class as a Spring bean.
- C. Assuming @Service, @Repository, and @Controller behave completely differently from @Component — functionally they are almost the same, differing mainly in semantics and (for @Repository) exception translation.
Show answer
C. Avoid this approach: Assuming @Service, @Repository, and @Controller behave completely differently from @Component — functionally they are almost the same, differing mainly in semantics and (for @Repository) exception translation. The lesson recommends: @Component, @Service, @Repository, and @Controller/@RestController are stereotype annotations that register a class as a Spring bean.
Interview questions
A teammate is about to make this mistake: Assuming @Service, @Repository, and @Controller behave completely differently from @Component — functionally they are almost the same, differing mainly in semantics and (for @Repository) exception translation. How would you diagnose and correct it using the lesson's guidance?
Show answer
@Component, @Service, @Repository, and @Controller/@RestController are stereotype annotations that register a class as a Spring bean. Apply this in Stereotype Annotations; the example A singleton service bean and a prototype bean requested twice shows one way to do it. Avoid Assuming @Service, @Repository, and @Controller behave completely differently from @Component — functionally they are almost the same, differing mainly in semantics and (for @Repository) exception translation. and explain how your implementation or design prevents that failure.
Key Points to Remember
- @Component, @Service, @Repository, and @Controller/@RestController are stereotype annotations that register a class as a Spring bean.
- Singleton is the default scope: one instance shared across the entire container.
- Prototype scope creates a new instance on every request for that bean.
- Singleton beans must be stateless or thread-safe since they are shared across the whole application.
Practice in the playground
Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.
Run the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
These examples need a JDK project with their libraries on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.
Written by
WebNest Studio Engineering Team
Practical lessons from developers working with Java, Python, React, databases and production systems.
Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering