Annotations in Spring Framework
Spring Framework:
- @Component, @Service, @Repository: Declare components for Spring to manage.
- @Autowired: Enables dependency injection.
- @RequestMapping, @GetMapping, @PostMapping: Define web endpoints.
@Service, @Controller, @Component, and @Repository
In Spring Framework, the annotations @Service, @Controller, @Component, and @Repository are stereotype annotations used to define Spring-managed beans and indicate the role or responsibility of a class in the application architecture. All of them are detected during classpath scanning via @ComponentScan.
All these annotations are meta-annotated with @Component, meaning:
@Service => @Component
@Controller => @Component
@Repository => @Component
So they all register the class as a Spring bean, but their semantic meaning is different.
Detailed Explanation
Annotation | Purpose | Typical Layer | Additional Behavior |
---|---|---|---|
@Component | Generic stereotype for any Spring-managed component | Any layer | None specific |
@Service | Marks a service class that holds business logic | Service layer | None, semantic only |
@Repository | Marks DAO (Data Access Object) classes that interact with databases | Persistence layer | Enables exception translation (Spring wraps JDBC/ORM exceptions into DataAccessException) |
@Controller | Marks a web controller class that handles HTTP requests | Web layer (MVC) | Enables Spring MVC processing (e.g., routing, @RequestMapping, response rendering) |
@Component
public class UtilityBean {
// General-purpose component
}
@Service
public class UserService {
// Business logic, called by controllers
}
@Repository
public class UserRepository {
// DAO layer, typically using JPA or JDBC
}
@Controller
public class UserController {
// Handles HTTP requests and maps routes
}
Best Practices
- Use @Component only when a class doesn’t clearly fit into @Service, @Repository, or @Controller.
- Use @Repository if your class interacts with the database (enables Spring’s exception translation).
- Use @Service to mark classes that implement business logic.
- Use @Controller for Spring MVC controllers (handling web requests).
@Autowired
@Autowired 是 Spring Framework 中用于 依赖注入(Dependency Injection) 的注解。它可以自动将 Spring 容器中管理的 Bean 注入到目标类的字段、构造函数或 setter 方法中。
常见用法
1.字段注入(不推荐)
@Component
public class MyService {
@Autowired
private MyRepository myRepository;
}
- Spring 会自动查找并注入一个 MyRepository 类型的 Bean。
- 缺点:不利于单元测试和类的解耦。
2. 构造函数注入(推荐方式 ✅)
@Component
public class MyService {
private final MyRepository myRepository;
@Autowired // 可省略,Spring 4.3+ 如果类只有一个构造函数,会自动注入
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
}
- 最推荐的方式,便于测试和提升代码的可维护性。
Why it’s recommended
- Immutability: Dependencies are final and assigned once, ensuring your class is immutable after construction.
- Clarity: It is immediately obvious what dependencies a class needs — you must provide them to construct the object.
- Testability: Makes unit testing easier — just pass mocks into the constructor.
- Avoids hidden dependencies: Unlike field injection (@Autowired private …), you can’t forget a required bean — your class won’t compile without it.
3. Setter 方法注入
@Component
public class MyService {
private MyRepository myRepository;
@Autowired
public void setMyRepository(MyRepository myRepository) {
this.myRepository = myRepository;
}
}
- 某些需要可选注入或循环依赖处理时可以使用。
与 @Qualifier 搭配使用
- 如果存在多个 Bean,可以配合 @Qualifier 指定名称:
@Autowired
@Qualifier("myRepositoryImpl")
private MyRepository myRepository;
@Configuration
What is @Configuration?
@Configuration is a class-level annotation that marks the class as a source of Spring bean definitions.
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
}
Key Characteristics
Feature | Description |
---|---|
Meta-annotated with @Component | So it is picked up by component scanning |
Declares @Bean methods | Those methods produce beans for the Spring container |
Beans are singletons by default | Even if you call @Bean methods multiple times |
Ensures proper proxying of methods | To avoid multiple instances of the same bean |
Example
@Configuration
public class AppConfig {
@Bean
public Engine engine() {
return new Engine();
}
@Bean
public Car car() {
return new Car(engine()); // same Engine instance injected
}
}
Even though it looks like engine() is called twice, Spring ensures that both the Engine and Car beans share the same singleton instance.
⚠️ Without @Configuration
If you just use @Component instead of @Configuration, the @Bean methods become regular methods, and each call returns a new instance.
@Component
public class AppConfig {
@Bean
public Engine engine() {
return new Engine();
}
@Bean
public Car car() {
return new Car(engine()); // different instance of Engine!
}
}
To enable proper singleton scoping and proxying, you must use @Configuration.
@Bean
@Bean tells Spring, “create and manage this object as a Spring bean.”
It’s used inside a @Configuration class to define beans programmatically.
What is @Bean?
@Bean tells Spring, “create and manage this object as a Spring bean.”
It’s used inside a @Configuration class to define beans programmatically.
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
}
This is equivalent to defining the bean in XML:
<bean id="myService" class="com.example.MyService"/>
Characteristics of @Bean
Feature | Description |
---|---|
Method-based | You define a bean by returning an object from a method |
Customization | Full control over how the object is created, configured, or wired |
Registered in Spring context | Registered using the method name as the bean ID by default |
Can define dependencies manually | Call other @Bean methods or inject parameters |
@Bean vs @Component
Aspect | @Bean | @Component |
---|---|---|
Usage | Method-based | Class-based |
Location | In a @Configuration class | On class directly |
Control | Full manual control | Auto-detected via scanning |
Suitable for | External libs, complex config | Your own app classes |
@Transactional Pitfalls
In a Spring Boot application, the @Transactional annotation may not take effect due to several common reasons. Here are the main ones, categorized by root cause:
✅ 1. Method visibility — must be public
- Spring AOP (proxy-based) requires the transactional method to be public.
- Won’t work: private, protected, or package-private methods.
@Transactional // Won't work
private void doSomething() { ... }
✅ 2. Self-invocation
- Calling a @Transactional method from within the same class bypasses the proxy and the transaction will not apply.
@Service
public class MyService {
@Transactional
public void methodA() {
// transaction applies here
}
public void methodB() {
methodA(); // ❌ No transaction – self-invocation skips proxy
}
}
Fix: Move the transactional method to a separate bean or call through the Spring context proxy.
✅ 3. Not a Spring-managed bean
- @Transactional only works if the class is a Spring bean (e.g. annotated with @Service, @Component, etc., and managed by the container).
✅ 4. Exception type not triggering rollback
- By default, Spring only rolls back on unchecked exceptions (RuntimeException, Error).
- Checked exceptions (e.g., IOException) won’t trigger rollback unless explicitly specified.
@Transactional(rollbackFor = Exception.class) // If you want to rollback for checked exceptions
✅ 5. Wrong proxy mode / AOP misconfiguration
- Spring uses proxies (JDK or CGLIB). Misconfigured proxy mode might prevent transaction from applying.
- If using interface-based (JDK dynamic proxy), methods must be declared in the interface.
- Can force class-based proxying:
@EnableTransactionManagement(proxyTargetClass = true)
✅ 6. Missing @EnableTransactionManagement
- Although Spring Boot includes this by default via @SpringBootApplication, if manually configuring, ensure this is enabled:
@Configuration
@EnableTransactionManagement
public class AppConfig {}
✅ 7. Database doesn’t support transactions
- Some operations (e.g., on MyISAM in MySQL) or certain NoSQL stores don’t support transactions.
✅ 8. Propagation or isolation settings interfere
- If using Propagation.NEVER, NOT_SUPPORTED, or similar, the transaction might be skipped.
- Double-check @Transactional attributes.
✅ 9. Misuse in @PostConstruct or constructor
- Transactions don’t work inside constructors or @PostConstruct methods because the proxy isn’t initialized yet.
@PostConstruct
@Transactional // ❌ Won’t work here
public void init() {}