zoukankan      html  css  js  c++  java
  • Spring实战——Profile

      看到Profile这个关键字,或许你从来没有正眼瞧过他,又或者脑海中有些模糊的印象,比如除了这里Springmvc中的Profile,maven中也有Profile的标签。

      从字面意思来看,Profile表示侧面,那什么情况下才会用到侧面这个功能呢,而侧面具体又有什么含义呢

      打一个比方,对于数据库的配置问题,在开发的眼中可以使用嵌入的数据库,并且加载测试数据(后面会给出代码示例)。但是在测试的眼中,可能会配一个数据库连接池类似这样

    @Bean(destroyMethod="close")
    public DataSource dataSource () {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl("jdbc:h2:tcp://dbserver/~/test");
        dataSource.setDriverClassName("org.h2.Driver");
        dataSource.setUsername("sa");
        dataSource.setPassword("password");
        dataSource.setInitialSize(20);
        dataSource.setMaxActive(30);
        return dataSource;  
    }
    

      当然还有产品环境下的配置等等。对于这种百花齐放的配置方式你还能说什么,默默的为这一套套的环境都部署相应的配置文件啊,没有profile这套我们一直都是这么做。

      但是现在有了Profile,我们就多了一种选择,一种更加智能省心的配置方式。通过Profile配置,Spring可以在根据环境在运行阶段来决定bean的创建与否,先举例如下,主要从Profile bean的配置和激活来展开。

    Profile bean的配置

      通过注解@Profile配置

      对于上面比方中的第一种情况,在开发环境中我们配置一个数据源可能是这样的

    @Bean(destroyMethod = "shutdown")
    public DataSource embeddedDataSource() {
        return new EmbeddedDatabaseBuilder()
            .addScript("classpath:schema.sql")
            .addScript("classpath:test-data.sql")
            .build();
      }
    

      这里会使用EmbeddedDatabaseBuilder创建一个嵌入式数据库,模式定义在类文件下的schema.sql文件中

      schema.sql

    create table Things (
      id identity,
      name varchar(100)
    );
    

      这里定义了一张Things表包含了两个字段

      除了模式文件,还需要通过test-data.sql加载测试数据

      test-data.sql

    insert into Things (name) values ('A')
    

      对于这个@Bean完全不知道是放在开发的环境下创建还是产品的环境下。所以我们这里可以使用注解@Profile帮助我们为这个bean打上标识。

      从Spring 3.1版本中就引入了bean profile的功能,可以让你将不同的bean定义到一个或者多个profile里,然后在部署应用时告知要激活那个profile,则相应的bean就会被创建。比如这里

    @Configuration
    @Profile("dev")
    public class DevelopmentProfileConfig {
    
      @Bean(destroyMethod = "shutdown")
      public DataSource embeddedDataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .addScript("classpath:schema.sql")
            .addScript("classpath:test-data.sql")
            .build();
      }
    }

      通过@Profile("dev")为EmbedderDataSource bean标记为dev环境下要创建的bean。

      注意:1. @Profile被加载类级别上,如果dev profile没有被激活,那么类中对应的所有bean就不会被创建

               2. 如果当前是dev环境被激活了,那么对于没有使用@Profile的bean都会被创建,被标记为其他的profile如prod,则不会创建相应的bean

               3. 从3.2开始@Profile不仅仅可以加载类级别上,还可以加载方法上,具体代码如下

    package com.myapp;
    
    import javax.sql.DataSource;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Profile;
    import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
    import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
    import org.springframework.jndi.JndiObjectFactoryBean;
    
    @Configuration
    public class DataSourceConfig {
      
      @Bean(destroyMethod = "shutdown")
      @Profile("dev")
      public DataSource embeddedDataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .addScript("classpath:schema.sql")
            .addScript("classpath:test-data.sql")
            .build();
      }
    
      @Bean
      @Profile("prod")
      public DataSource jndiDataSource() {
        JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
        jndiObjectFactoryBean.setJndiName("jdbc/myDS");
        jndiObjectFactoryBean.setResourceRef(true);
        jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
        return (DataSource) jndiObjectFactoryBean.getObject();
      }
    
    }
    

      

      通过xml配置文件配置

      除了简单的注解方式,我们哈可以通过在xml配置文件中声明的方式,具体配置如下

      datasource-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
      xmlns:jee="http://www.springframework.org/schema/jee" xmlns:p="http://www.springframework.org/schema/p"
      xsi:schemaLocation="
        http://www.springframework.org/schema/jee
        http://www.springframework.org/schema/jee/spring-jee.xsd
        http://www.springframework.org/schema/jdbc
        http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <beans profile="dev">
        <jdbc:embedded-database id="dataSource" type="H2">
          <jdbc:script location="classpath:schema.sql" />
          <jdbc:script location="classpath:test-data.sql" />
        </jdbc:embedded-database>
      </beans>
      
      <beans profile="prod">
        <jee:jndi-lookup id="dataSource"
          lazy-init="true"
          jndi-name="jdbc/myDatabase"
          resource-ref="true"
          proxy-interface="javax.sql.DataSource" />
      </beans>
    </beans>
    

      这里分别声明了两种环境以及对应的profile。

    profile激活

      虽然我们已经配置好了profile,但是如何激活相应的环境呢。这里我们需要两个属性spring.profile.active以及spring.profile.default。

      如果spring.profile.active被赋值了,则spring.profile.default就不会起作用,如果spring.profie.active没有赋值,则使用默认的spring.profile.default设置的值。当然,如果两者都没有设置的话,则只会创建那些定义在相应的profile中的bean。

      设置这两个属性的方式有很多:

        作为DispactcherServlet的初始化参数

        作为Web应用上下文参数

        作为JNDI条目

        作为环境变量

        作为JVM的系统属性

        在集成测试类上,使用@ActiveProfiles注解设置

      比如我们在web.xml中可以声明代码如下

    <?xml version="1.0" encoding="UTF-8"?>
    <web -app version="2.5"
    ...>
    
        //为上下文设置默认的profile
        <context-param>
            <param-name>spring.profile.default</param-name>
            <param-value>dev</param-value>
        </context-param>
    
    ...
    
        <servlet>
            ...
            //为Serlvet设置默认的profile
            <init-param>
                <param-name>spring-profiles.default</param-name>
                <param-value>dev</param-value>
            </init-prama>
    
    ...
    <web-app>
    

      这样就可以指定需要启动那种环境,并准备相应的bean。

      另外对于测试,spring为什么提供了一个简单的注解可以使用@ActiveProfiles,它可以指定运行测试的时候应该要激活那个profile。比如这里的测试类DevDataSourceTest

    package profiles;
    
    import static org.junit.Assert.*;
    
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.List;
    
    import javax.sql.DataSource;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.RowMapper;
    import org.springframework.test.context.ActiveProfiles;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import com.myapp.DataSourceConfig;
    
    public class DataSourceConfigTest {
    
      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(classes=DataSourceConfig.class)
      @ActiveProfiles("dev")
      public static class DevDataSourceTest {
        @Autowired
        private DataSource dataSource;
        
        @Test
        public void shouldBeEmbeddedDatasource() {
          assertNotNull(dataSource);
          JdbcTemplate jdbc = new JdbcTemplate(dataSource);
          List<String> results = jdbc.query("select id, name from Things", new RowMapper<String>() {
            @Override
            public String mapRow(ResultSet rs, int rowNum) throws SQLException {
              return rs.getLong("id") + ":" + rs.getString("name");
            }
          });
          
          assertEquals(1, results.size());
          assertEquals("1:A", results.get(0));
        }
      }
    
      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(classes=DataSourceConfig.class)
      @ActiveProfiles("prod")
      public static class ProductionDataSourceTest {
        @Autowired
        private DataSource dataSource;
        
        @Test
        public void shouldBeEmbeddedDatasource() {
          // should be null, because there isn't a datasource configured in JNDI
          assertNull(dataSource);
        }
      }
      
      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration("classpath:datasource-config.xml")
      @ActiveProfiles("dev")
      public static class DevDataSourceTest_XMLConfig {
        @Autowired
        private DataSource dataSource;
        
        @Test
        public void shouldBeEmbeddedDatasource() {
          assertNotNull(dataSource);
          JdbcTemplate jdbc = new JdbcTemplate(dataSource);
          List<String> results = jdbc.query("select id, name from Things", new RowMapper<String>() {
            @Override
            public String mapRow(ResultSet rs, int rowNum) throws SQLException {
              return rs.getLong("id") + ":" + rs.getString("name");
            }
          });
          
          assertEquals(1, results.size());
          assertEquals("1:A", results.get(0));
        }
      }
    
      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration("classpath:datasource-config.xml")
      @ActiveProfiles("prod")
      public static class ProductionDataSourceTest_XMLConfig {
        @Autowired(required=false)
        private DataSource dataSource;
        
        @Test
        public void shouldBeEmbeddedDatasource() {
          // should be null, because there isn't a datasource configured in JNDI
          assertNull(dataSource);
        }
      }
    
    }
    

     

     运行shouldBeEmbeddedDatasource方法,测试通过

      如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。

  • 相关阅读:
    MAC使用小技巧(二)
    Swift # GET&POST请求 网络缓存的简单处理
    iOS:Block写递归
    Swift # 项目框架
    uva 11665 Chinese Ink (几何+并查集)
    uva 11859 Division Game
    uva 11916 Emoogle Grid (BSGS)
    uva 11754 Code Feat (中国剩余定理)
    hdu 4347 The Closest M Points(KD树)
    2013多校训练赛第四场 总结
  • 原文地址:https://www.cnblogs.com/bigdataZJ/p/SpringInAction4.html
Copyright © 2011-2022 走看看