注释 @ActiveProfile 在 Spring 应用程序中不起作用

Posted

技术标签:

【中文标题】注释 @ActiveProfile 在 Spring 应用程序中不起作用【英文标题】:Annotations @ActiveProfile doesn't work in a Spring app 【发布时间】:2021-08-25 21:15:32 【问题描述】:

我没有在这个应用程序中使用 spring-boot。 我正在测试配置文件以在集成测试中使用不同的数据源。

我有如下实体用户:

@Table(name = "user_inf")
@Entity
@NamedQuery(name="User.findById", query="select u from User u where u.id=:id")
public class User implements Serializable 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;

    @Column(name = "userName", length = 25)
    private String userName;

    @Column(name = "userEmail", unique = true, length = 320)
    private String userEmail;

对于那个实体,我有服务和 dao(服务只调用 dao 方法)

用户道:

@Repository
@Transactional
public class UserDaoImpl implements UserDao 

    @PersistenceContext
    private EntityManager entityManager;
    @Override
    public User findById(Long id) 
        TypedQuery<User> query = entityManager.createNamedQuery("User.findById", User.class);
        query.setParameter("id", id);
        return query.getSingleResult();
    

用户服务:

@Service
public class UserServiceImpl implements UserService
    @Autowired
    private UserDao userDao;
    @Override
    public User getUser(Long id) 
        return userDao.findById(id);
    


@Configuration
@PropertySource(value = "classpath:database/jdbc.properties")
@EnableTransactionManagement
@ComponentScan("com.example.test.repository", "com.example.test.service")
public class SpringConfig 

    private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
    private static final String PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH = "hibernate.max_fetch_depth";
    private static final String PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE = "hibernate.jdbc.fetch_size";
    private static final String PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE = "hibernate.jdbc.batch_size";
    private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
    private static final String ENTITY_MANAGER_PACKAGES_TO_SCAN = "com.example.test.entity";

    @Autowired
    private Environment env;


    @Bean
    public DataSource dataSource() 
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
        dataSource.setUrl(env.getProperty("jdbc.url"));
        dataSource.setUsername(env.getProperty("jdbc.username"));
        dataSource.setPassword(env.getProperty("jdbc.password"));
        return dataSource;
    

    @Bean
    @Profile("test")
    public DataSource dataSourceForTest() 
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
        dataSource.setUrl(env.getProperty("jdbc.test.url"));
        dataSource.setUsername(env.getProperty("jdbc.username"));
        dataSource.setPassword(env.getProperty("jdbc.password"));
        return dataSource;
    

    @Bean
    public PlatformTransactionManager jpaTransactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) 
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactoryBean.getObject());
        return transactionManager;
    

    private HibernateJpaVendorAdapter vendorAdaptor() 
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setShowSql(true);
        return vendorAdapter;
    

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource mainDataSource) 
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setJpaVendorAdapter(vendorAdaptor());
        entityManagerFactoryBean.setDataSource(mainDataSource);
        entityManagerFactoryBean.setPackagesToScan(ENTITY_MANAGER_PACKAGES_TO_SCAN);
        entityManagerFactoryBean.setJpaProperties(jpaHibernateProperties());
        return entityManagerFactoryBean;
    

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() 
        return new PersistenceExceptionTranslationPostProcessor();
    

    private Properties jpaHibernateProperties() 
        Properties properties = new Properties();
        properties.put(PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH, env.getProperty(PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH));
        properties.put(PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE, env.getProperty(PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE));
        properties.put(PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE, env.getProperty(PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE));
        properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
        properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
        properties.put("hibernate.hbm2ddl.auto", "none");
        return properties;
    


用于数据源和休眠的属性文件(jdbc.properties)包含以下内容:

jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/testdatabase
jdbc.username=Bruce
jdbc.password=givanchy

jdbc.test.url=jdbc:mysql://localhost:3306/testdatabase1

hibernate.max_fetch_depth = 3
hibernate.jdbc.fetch_size = 50
hibernate.jdbc.batch_size = 10
hibernate.show_sql = true
hibernate.dialect = org.hibernate.dialect.MySQL8Dialect

申请入口:

public class EntryClass 
    public static void main(String[] args) 
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService = applicationContext.getBean("userServiceImpl", UserServiceImpl.class);
        User user =userService.getUser(1L);
        System.out.println("userName is "+user.getUserName());
    

它可以正常工作。 但在测试源 我只有一项服务测试来了解配置文件的工作原理

@SpringJUnitConfig(SpringConfig.class)
@ActiveProfiles("test")
class UserServiceImplTest 
    @Autowired
    private UserService userService;

    @Test
    void getUser() 
        User user = userService.getUser(5L);
        Assertions.assertEquals("Vector", user.getUserName());
    

我得到“没有合格的 bean”异常,因为有两个数据源类型的 bean,但我设置了它应该使用哪个配置文件?你能解释为什么它不起作用吗?

【问题讨论】:

只是为了确定。您是否使用spring.profiles.active 作为test 启动运行时?如果没有,spring 会自动默认为default @shinjw 我想如果我在测试类中设置@ActiveProfiles 它会起作用。同样在主源中它可以正常工作,因为我不需要数据源进行测试,所以如果我将spring.profiles.active 设置为test 它只适用于测试类? 【参考方案1】:

正常启动时,不会创建带有“test”配置文件的数据源 bean。 (因为没有设置测试配置文件。)

当您将其作为测试运行时,会创建两个数据源 bean。默认创建是因为它没有任何条件,另一个是因为它带有测试配置文件的注释。

只需将@Profile("!test") 添加到默认bean。这样,只有在测试配置文件未激活时才会创建它。

【讨论】:

以上是关于注释 @ActiveProfile 在 Spring 应用程序中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Jackson Object Mapper 在提供扩展配置时不工作,但在 Spring Boot 中提供类级别/字段级别注释时工作

springboot 初识

Sprin Boot无RunWith注解解决办法

我正在尝试在我的 sprin 启动应用程序中应用 auth0 安全性,但它会引发错误

Sprin中Bean的顺序

cas完全是sprin框架写的么