《深入浅出Spring》Spring注解(@Scope、@DependsOn、@ImportResource、@Lazy)

本文详细介绍了Spring框架中的四个重要注解:@Scope用于定义bean的作用域,@DependsOn用于指定bean的依赖关系,@ImportResource用于在配置类中导入bean定义的XML配置文件,@Lazy实现bean的延迟初始化。每个注解的用法和应用场景都通过实例进行了说明。

@Scope 指定bean的作用域

@Scope用来配置bean的作用域,等效于bean xml中的bean元素中的scope属性。

@Target({
   
   ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
   
   
    @AliasFor("scopeName")
    String value() default "";
    @AliasFor("value")
    String scopeName() default "";
    ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}

@Scope可以用在类上和方法上
参数:value和scopeName效果一样,用来指定bean作用域名称,如:singleton、prototype

常见2种用法

  • 和@Compontent一起使用在类上
  • 和@Bean一起标注在方法上

和@Compontent一起使用在类上

@Component
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)//@1
public class ServiceA {
   
   
}

上面定义了一个bean,作用域为单例的。
@1:ConfigurableBeanFactory接口中定义了几个作用域相关的常量,可以直接拿来使用,如:
String SCOPE_SINGLETON = “singleton”;
String SCOPE_PROTOTYPE = “prototype”;

和@Bean一起标注在方法上

@Bean标注在方法上,可以通过这个方法来向spring容器中注册一个bean,在此方法上加上@Scope可以指定这个bean的作用域,如:

@Configurable
public class MainConfig2 {
   
   
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public ServiceA serviceA() {
   
   
        return new ServiceA
<think>好的,我现在需要回答用户关于Spring框架中@Bean注解方法在启动时是否会自动执行的问题。用户之前已经询问过配置类以及@Configuration和@Bean的作用,现在他想知道@Bean方法在Spring启动时是否会被自动执行。首先,我需要回顾之前提供的资料和用户的引用内容。根据引用[2]和[3],@Bean注解用于将方法返回的对象注册为SpringBean,默认是单例的。同时,引用[4]中的示例使用了AnnotationConfigApplicationContext来加载配置类,并获取Bean,这说明配置类中的@Bean方法会被Spring容器处理。但用户的问题是这些方法是否在启动时自动执行,而不仅仅是注册Bean。 接下来,我需要分析@Bean方法的执行时机。通常,Spring在启动时会初始化容器,处理所有配置类中的@Bean方法,创建Bean实例并纳入容器管理。所以,@Bean方法在启动时会被执行,以便创建Bean实例。这一点可以从引用[4]的示例中得到验证,当加载配置类时,会执行其中的@Bean方法来获取Bean。但是,用户提到的引用[1]中提到,某些情况下需要排除自动配置类,比如Redis、MQ等,避免自定义的Bean被自动配置覆盖。这可能涉及到@Bean方法的执行顺序或条件化配置的问题。如果自动配置类中的@Bean方法先执行,可能会覆盖用户自定义的Bean,因此需要排除自动配置类,确保用户自定义的@Bean方法得到执行。此外,引用[5]指出,@Bean方法可以是实例方法或静态方法,但要注意配置类的模式(full或lite)。在@Configuration注解的配置类中,@Bean方法默认使用CGLIB代理,确保多次调用方法时返回同一个实例(单例)。而在@Component等lite模式下,每次调用方法都会创建新实例。这可能影响@Bean方法的执行次数,但不会改变启动时执行的事实。 用户的问题核心是@Bean方法是否在启动时自动执行。答案是肯定的,Spring容器在启动阶段会处理所有配置类,执行其中的@Bean方法,将返回的对象注册为Bean。但需要注意自动配置与自定义配置的冲突,可能需要排除某些自动配置类,如引用[1]所示,通过exclude属性确保自定义的@Bean方法优先执行。 另外,@Bean方法中的初始化逻辑(如数据库连接配置)会在方法执行时完成,因此这些代码确实会在启动时运行。例如,在DatabaseConfig类中的dataSource()方法创建HikariDataSource实例时,相关的配置代码会在Spring启动时执行。总结:@Bean方法在Spring启动时会被自动执行,以创建Bean实例并注册到容器中。需要注意排除可能冲突的自动配置类,确保自定义Bean的正确注册。同时,@Bean方法的执行次数和作用域受配置类模式及@Scope注解的影响。</think>### Spring @Bean 方法在启动时的执行机制 #### 一、核心结论 **@Bean 注解的方法会在 Spring 容器启动时自动执行**,其目的是创建 Bean 实例并注册到 IOC 容器中[^2][^4]。具体行为特征如下: 1. **执行时机**:容器初始化阶段(如 `AnnotationConfigApplicationContext.refresh()` 被调用时) 2. **执行次数**: - 单例模式(默认):仅执行一次 - 原型模式(@Scope("prototype")):每次获取 Bean 时执行 3. **执行顺序**:受 `@DependsOn`、`@Order` 等注解控制 #### 二、执行原理分析 1. **配置类解析** Spring 容器会扫描所有 `@Configuration` 类,通过 CGLIB 代理增强配置类[^5],确保: ```java @Configuration public class AppConfig { @Bean public ServiceA serviceA() { // 实际会被代理拦截 return new ServiceA(serviceB()); // 保证单例唯一性 } @Bean public ServiceB serviceB() { return new ServiceB(); } } ``` 2. **Bean 创建流程** ```mermaid graph TD A[启动容器] --> B[解析@Configuration类] B --> C[遍历@Bean方法] C --> D{是否已存在Bean?} D -->|否| E[执行方法创建对象] D -->|是| F[直接获取现有Bean] E --> G[注册Bean到容器] ``` #### 三、关键验证场景 1. **简单 Bean 注册** ```java @Configuration public class DemoConfig { @Bean public String demoBean() { System.out.println("Bean方法被执行!"); // 启动时输出 return "Hello Spring"; } } ``` - 启动日志中会显示输出语句,证明方法确实执行[^4] 2. **依赖注入场景** ```java @Bean public DataSource dataSource(Environment env) { // 参数自动注入 HikariConfig config = new HikariConfig(); config.setJdbcUrl(env.getProperty("spring.datasource.url")); return new HikariDataSource(config); // 启动时即完成连接池初始化 } ``` #### 四、特殊注意事项 1. **避免自动配置冲突** 当自定义 Bean 与 Spring Boot 自动配置冲突时,需排除自动配置类[^1]: ```java @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) public class MyApp { public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } } ``` 2. **条件控制执行** 通过 `@Conditional` 系列注解控制是否执行: ```java @Bean @ConditionalOnProperty(name = "cache.enabled", havingValue = "true") public CacheManager cacheManager() { return new RedisCacheManager(); // 仅当配置存在时执行 } ``` 3. **延迟初始化** 使用 `@Lazy` 注解延迟执行: ```java @Bean @Lazy // 首次获取Bean时才执行方法 public ExpensiveService expensiveService() { return new ExpensiveService(); } ``` --- ### 常见问题解答 #### Q1:@Bean 方法中的代码会重复执行吗? - **单例 Bean**:仅首次创建时执行一次 - **原型 Bean**:每次获取时都会执行 - **静态 @Bean 方法**:始终只执行一次(与作用域无关)[^5] #### Q2:如何验证 @Bean 方法的执行顺序? 使用 `@DependsOn` 明确依赖关系: ```java @Bean @DependsOn("databaseInitializer") // 确保先执行databaseInitializer public Service service() { return new ServiceImpl(); } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值