1

用例:我通过类路径扫描@ComponentScan 配置了我的容器。对于我的测试配置,我需要能够模拟特定的 bean。

由于加载顺序,通过类路径扫描加载的 bean 在使用 @Configuration 时无法正确覆盖。下面的代码示例演示了该问题。BaseExample.java 展示了如何通过配置覆盖 bean。ScanExample.java 显示覆盖通过 @ComponentScan 加载的 bean 被跳过(见最后注释)。

bitbucket上提供了一个演示项目。

// BaseExample.java

package com.glassworks.mock;

import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.google.common.base.Joiner;

public class BaseExample {
    private static final Logger log = LoggerFactory.getLogger(BaseExample.class);
    private static AnnotationConfigApplicationContext ctx;

    public static void main(String args[]) {
        ctx = new AnnotationConfigApplicationContext(Config.class, OverrideConfig.class);

        String beans[] = ctx.getBeanDefinitionNames();
        log.info("{} beans found: {}", beans.length, Joiner.on(",").join(beans));

        for(String bean : beans) {
            log.info("{}: {}", bean, ctx.getBean(bean));
        }
    }

    @Configuration
    public static class Config {
        @Bean
        public AccountDao accountDao() {
            log.debug("Creating accountDao [Config]");
            return new AccountDao();
        }
    }

    @Configuration
    public static class OverrideConfig {
        @Bean
        public Object accountDao() {
            log.debug("Creating accountDao [OverrideConfig]");
            return Mockito.mock(AccountDao.class);
        }
    }

}

输出:21:05 信息 | com.glassworks.mock.BaseExample | accountDao:模拟 AccountDao,hashCode:666537607

[// ScanExample.java

package com.glassworks.mock;

import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import com.google.common.base.Joiner;

public class ScanExample {
    private static final Logger log = LoggerFactory.getLogger(ScanExample.class);
    private static AnnotationConfigApplicationContext ctx;

    public static void main(String args[]) {
        ctx = new AnnotationConfigApplicationContext(Config.class, OverrideConfig.class);

        String beans[] = ctx.getBeanDefinitionNames();
        log.info("{} beans found: {}", beans.length, Joiner.on(",").join(beans));

        for(String bean : beans) {
            log.info("{}: {}", bean, ctx.getBean(bean));
        }
    }

    @Configuration
    @ComponentScan("com.glassworks.services")
    public static class Config {

    }

    @Configuration
    public static class OverrideConfig {
        @Bean
        public AccountDao accountDao() {
            log.debug("Creating accountDao [OverrideConfig]");
            return Mockito.mock(AccountDao.class);
        }
    }

}

输出:21:08 信息 | com.glassworks.mock.ScanExample | accountDao:com.glassworks.services.AccountDao@48805ebb

// AccountDao.java
package com.glassworks.services;

import org.springframework.stereotype.Repository;

@Repository
public class AccountDao {

}

注意 值得注意的是,将日志记录设置为调试时,Spring 表示它正在跳过定义。这似乎是一个错误。

21:09 调试 | oscaConfigurationClassBeanDefinitionReader | 跳过加载 [BeanMethod:name=accountDao,declaringClass=com.glassworks.mock.ScanExample$OverrideConfig] 的 bean 定义:bean 'accountDao' 的定义已经存在。这可能是由于 XML 中的覆盖。

4

0 回答 0