springBoot學習(二)配置環境動態切換和部分註解的運用

SpringBoot配置環境動態切換

創建第一個配置文件(springBoot默認讀取的文件)application.propertiesphp

test.name=default
test.defaultAge=12

創建第二個配置文件(開發環境)application-dev.propertiesjava

test.name=dev
test.devAge=13

創建第三個配置文件(用戶驗收測試環境)application-uat.propertiesspring

test.name=uat
test.uatAge=14

1.添加啓動參數(--spring.profiles.active=),測試結果讀取application.properties的值express

2.添加啓動參數(--spring.profiles.active=dev),測試結果讀取application-dev.properties的值apache

3.添加啓動參數(--spring.profiles.active=uat),測試結果讀取application-uat.properties的值springboot

4.添加啓動參數(--spring.profiles.active=uat,dev),測試結果讀取application-dev.properties的值微信

5.添加啓動參數(--spring.profiles.active=dev,uat),測試結果讀取application-uat.properties的值app

6.添加啓動參數(--spring.profiles.active=dev),能夠讀到application.properties的(test.defaultAge)值,讀不到uat的(test.uatAge)值。less

7.添加啓動參數(--spring.profiles.active=uat),能夠讀到application.properties的(test.defaultAge)值,讀不到dev的(test.devAge)值。ide

8.添加啓動參數(--spring.profiles.active=),能夠讀到application.properties的值,讀取不到其餘配置文件的值

重點

  • 添加啓動參數--spring.profiles.active=「環境表明參數」(此值爲文件名「-」與「.」中間的值,此處即爲dev或者uat)

  • 能夠添加多個參數,經過英文逗號(,)分割

  • 若是添加多個參數,有重複key,值會被覆蓋,(配置文件加載順序詳見官方文檔:24. Externalized Configuration)

  • 也能夠直接在application.properties配置文件中添加spring.profiles.active=「環境表明參數」 來替代啓動時候添加的參數

springBoot自動配置bean

首先看一個正常配置的bean與打印

創建一個接口

package com.yxj.spring;

/**
 * @ProjectName: springBootDemo
 * @Package: com.yxj.spring
 * @Description:
 * @Author:     阿杰
 * @CreateDate: 2019/1/22 22:08
 * @UpdateUser: 暫無
 * @UpdateDate: 2019/1/22 22:08
 * @UpdateRemark: The modified content
 * @Version: 1.0
 */

public interface MakeApp {
}

創建兩個實現-第一個

package com.yxj.spring;

/**
 * @ProjectName: springBootDemo
 * @Package: com.yxj.spring
 * @Description:
 * @Author: 阿杰
 * @CreateDate: 2019/1/22 22:13
 * @UpdateUser: 暫無
 * @UpdateDate: 2019/1/22 22:13
 * @UpdateRemark: The modified content
 * @Version: 1.0
 */

public class Wechat implements MakeApp {
}

創建兩個實現-第二個

package com.yxj.spring;

/**
 * @ProjectName: springBootDemo
 * @Package: com.yxj.spring
 * @Description:
 * @Author: 阿杰
 * @CreateDate: 2019/1/22 22:14
 * @UpdateUser: 暫無
 * @UpdateDate: 2019/1/22 22:14
 * @UpdateRemark: The modified content
 * @Version: 1.0
 */

public class PipiXia implements MakeApp {
}

經過@SpringBootConfiguration與@Bean加載bean

package com.yxj.spring;

import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;

/**
 * @ProjectName: springBootDemo
 * @Package: com.yxj.spring
 * @Description:  @SpringBootConfiguration繼承自@Configuration
 * 兩者功能也一致,標註當前類是配置類,
 * 並會將當前類內聲明的一個或多個以@Bean註解標記的方法的實例歸入到spring容器中,
* 而且實例名就是方法名。
 * @Author: 阿杰
 * @CreateDate: 2019/1/22 22:14
 * @UpdateUser: 暫無
 * @UpdateDate: 2019/1/22 22:14
 * @UpdateRemark: The modified content
 * @Version: 1.0
 */

@SpringBootConfiguration
public class LoadMyBean {

    @Bean
    public MakeApp createWechat(){
        return new Wechat();
    }


    @Bean
    public MakeApp createPipiXia(){
        return new PipiXia();
    }
}

springBoot啓動類測試

package com.yxj.spring;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;

import java.util.List;

/**
 * @ProjectName: springBootDemo
 * @Package: com.yxj.spring
 * @Description:
 * @Author: 楊小杰
 * @CreateDate: 2019/1/18 20:18
 * @UpdateUser: 暫無
 * @UpdateDate: 2019/1/18 20:18
 * @UpdateRemark: The modified content
 * @Version: 1.0
 */

@SpringBootApplication
public class SpringBootTestRun {

    /**
     * getBeansOfType(MakeApp.class)會裝配bean類型是MakeApp的全部實例
     * @param args
     */

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(SpringBootTestRun.class, args);
        System.out.println("------------------分割線------------------");
        System.out.println(run.getBeansOfType(MakeApp.class));
    }
}

測試結果

------------------分割線------------------
{createWechat=com.yxj.spring.Wechat@5cad8b7d, createPipiXia=com.yxj.spring.PipiXia@7b02e036}
能夠看到結果把經過@Bean加載的兩個MakeApp實現類對象所有打印出來了
瞭解Condition接口,實現自定義bean的加載

源代碼

/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package org.springframework.context.annotation;

import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * A single {@code condition} that must be {@linkplain #matches matched} in order
 * for a component to be registered.
 *
 * <p>Conditions are checked immediately before the bean-definition is due to be
 * registered and are free to veto registration based on any criteria that can
 * be determined at that point.
 *
 * <p>Conditions must follow the same restrictions as {@link BeanFactoryPostProcessor}
 * and take care to never interact with bean instances. For more fine-grained control
 * of conditions that interact with {@code @Configuration} beans consider the
 * {@link ConfigurationCondition} interface.
 *
 * @author Phillip Webb
 * @since 4.0
 * @see ConfigurationCondition
 * @see Conditional
 * @see ConditionContext
 */

@FunctionalInterface
public interface Condition {

    /**
     * Determine if the condition matches.
     * @param context the condition context
     * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
     * or {@link org.springframework.core.type.MethodMetadata method} being checked
     * @return {@code true} if the condition matches and the component can be registered,
     * or {@code false} to veto the annotated component's registration
     */

    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

上訴代碼描述了matches返回值若是是ture就會再加bean,反之則反

實現自定義Condition

新建Wechat自定義Condition,默認返回false(不裝配bean)

package com.yxj.spring;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.StringUtils;

/**
 * @ProjectName: springBootDemo
 * @Package: com.yxj.spring
 * @Description:
 * @Author: 阿杰
 * @CreateDate: 2019/1/22 22:35
 * @UpdateUser: 暫無
 * @UpdateDate: 2019/1/22 22:35
 * @UpdateRemark: The modified content
 * @Version: 1.0
 */

public class WechatCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return false;
    }
}

新建PipiXia自定義Condition,默認返回true(裝配bean)

package com.yxj.spring;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.StringUtils;

/**
 * @ProjectName: springBootDemo
 * @Package: com.yxj.spring
 * @Description:
 * @Author: 阿杰
 * @CreateDate: 2019/1/22 22:35
 * @UpdateUser: 暫無
 * @UpdateDate: 2019/1/22 22:35
 * @UpdateRemark: The modified content
 * @Version: 1.0
 */

public class PipiXiaCondition implements Condition {

    /**
     *當name不爲空的時候,判斷若是name中包含appName的時候返回true
     * @param context
     * @param metadata
     * @return
     */

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return true;
    }
}

在@Bean所在的類中添加自定義條件,配合@Conditional註解來實現

package com.yxj.spring;

import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;

/**
 * @ProjectName: springBootDemo
 * @Package: com.yxj.spring
 * @Description:  @SpringBootConfiguration繼承自@Configuration
 * 兩者功能也一致,標註當前類是配置類,
 * 並會將當前類內聲明的一個或多個以@Bean註解標記的方法的實例歸入到spring容器中,
* 而且實例名就是方法名。
 * @Author: 阿杰
 * @CreateDate: 2019/1/22 22:14
 * @UpdateUser: 暫無
 * @UpdateDate: 2019/1/22 22:14
 * @UpdateRemark: The modified content
 * @Version: 1.0
 */

@SpringBootConfiguration
public class LoadMyBean {

    @Bean
    @Conditional(WechatCondition.class)
    public MakeApp createWechat(){
        return new Wechat();
    }


    @Bean
    @Conditional(PipiXiaCondition.class)
    public MakeApp createPipiXia(){
        return new PipiXia();
    }
}

再次測試,測試結果

------------------分割線------------------
{createPipiXia=com.yxj.spring.PipiXia@420bc288}
能夠看到只打印了一個pipixia實例bean,微信沒有裝配進來
SpringBoot中自帶的Condition實現

能夠看到這個是繼承了@Conditional註解,傳了自定義的class對象,變成了一個新的註解
經常使用@Conditional註解使用,能夠查看大佬博客https://blog.csdn.net/u012437781/article/details/78626617


@Import註解

用處
  • @Import其實就是引入一個或多個配置,能夠導入普通類,也能夠導入配置類(上述的LoadMyBean爲配置類,主要經過@Bean生成bean給spring管理)

  • @Import用來導入一個或多個類(會被spring容器管理),或者配置類(配置類裏的@Bean標記的類也會被spring容器管理)

測試

仍是以上的例子,去掉配置類(LoadMyBean)中的@SpringBootConfiguration註解

package com.yxj.spring;

import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;

/**
 * @ProjectName: springBootDemo
 * @Package: com.yxj.spring
 * @Description:  @SpringBootConfiguration繼承自@Configuration
 * 兩者功能也一致,標註當前類是配置類,
 * 並會將當前類內聲明的一個或多個以@Bean註解標記的方法的實例歸入到spring容器中,
* 而且實例名就是方法名。
 * @Author: 阿杰
 * @CreateDate: 2019/1/22 22:14
 * @UpdateUser: 暫無
 * @UpdateDate: 2019/1/22 22:14
 * @UpdateRemark: The modified content
 * @Version: 1.0
 */

public class LoadMyBean {

    @Bean
    @Conditional(WechatCondition.class)
    public MakeApp createWechat(){
        return new Wechat();
    }


    @Bean
    @Conditional(PipiXiaCondition.class)
    public MakeApp createPipiXia(){
        return new PipiXia();
    }
}

修改springboot啓動類,添加@Import註解

package com.yxj.spring;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.*;

import java.util.List;

/**
 * @ProjectName: springBootDemo
 * @Package: com.yxj.spring
 * @Description:
 * @Author: 楊小杰
 * @CreateDate: 2019/1/18 20:18
 * @UpdateUser: 暫無
 * @UpdateDate: 2019/1/18 20:18
 * @UpdateRemark: The modified content
 * @Version: 1.0
 */

@SpringBootApplication
@Import(LoadMyBean.class)
public class SpringBootTestRun {

    /**
     * getBeansOfType(MakeApp.class)會裝配bean類型是MakeApp的全部實例
     * @param args
     */

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(SpringBootTestRun.class, args);
        System.out.println("------------------分割線------------------");
        System.out.println(run.getBeansOfType(MakeApp.class));
    }
}

測試結果

------------------分割線------------------
{createPipiXia=com.yxj.spring.PipiXia@6548bb7d}
測試結果代表了,雖然配置類沒有加入@SpringBootConfiguration,@Component,@Service,@Controller等交給spring管理的註解,可是經過啓動類添加@Import引入方式,仍然能夠在spring進行依賴注入,交由spring管理

若是你感受文章對你有幫助,就掃描二維碼關注我吧!

長按識別二維碼,瞭解更多


掃描二維碼加入技術交流羣!


本文分享自微信公衆號 - 亂敲代碼(lqcoder)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索