【Spring】Spring 中的注解(Annotation)

Posted by 西维蜀黍 on 2025-07-21, Last Modified on 2025-07-22

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() {}

Reference