日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

寫在前面

當bean是單實例,并且沒有設置懶加載時,Spring容器啟動時,就會實例化bean,并將bean注冊到IOC容器中,以后每次從IOC容器中獲取bean時,直接返回IOC容器中的bean,不再創建新的bean。

如果bean是單實例,并且使用@Lazy注解設置了懶加載,則Spring容器啟動時,不會實例化bean,也不會將bean注冊到IOC容器中,只有第一次獲取bean的時候,才會實例化bean,并且將bean注冊到IOC容器中。

如果bean是多實例,則Spring容器啟動時,不會實例化bean,也不會將bean注冊到IOC容器中,以后每次從IOC容器中獲取bean時,都會創建一個新的bean返回。

Spring支持按照條件向IOC容器中注冊bean,滿足條件的bean就會被注冊到IOC容器中,不滿足條件的bean就不會被注冊到IOC容器中。接下來,我們就一起來探討Spring中如何實現按照條件向IOC容器中注冊bean。

項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation

@Conditional注解概述

@Conditional注解可以按照一定的條件進行判斷,滿足條件向容器中注冊bean,不滿足條件就不向容器中注冊bean。

@Conditional注解是由 SpringFramework 提供的一個注解,位于 org.springframework.context.annotation 包內,定義如下。

package org.springframework.context.annotation;

import JAVA.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
	Class<? extends Condition>[] value();
}

從@Conditional注解的源碼來看,@Conditional注解可以添加到類上,也可以添加到方法上。在@Conditional注解中,存在一個Condition類型或者其子類型的Class對象數組,Condition是個啥?我們點進去看一下。

package org.springframework.context.annotation;

import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.core.type.AnnotatedTypeMetadata;
@FunctionalInterface
public interface Condition {
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

可以看到,Condition是一個函數式接口,對于函數式接口不了解的同學可以參見【Java8新特性】中的《【Java8新特性】還沒搞懂函數式接口?趕快過來看看吧!》一文。也可以直接查看《Java8新特性專欄》來系統學習Java8的新特性。

所以,我們使用@Conditional注解時,需要一個類實現Spring提供的Condition接口,它會匹配@Conditional所符合的方法,然后我們可以使用我們在@Conditional注解中定義的類來檢查。

@Conditional注解的使用場景如下所示。

  • 可以作為類級別的注解直接或者間接的與@Component相關聯,包括@Configuration類;
  • 可以作為元注解,用于自動編寫構造性注解;
  • 作為方法級別的注解,作用在任何@Bean方法上。

向Spring容器注冊bean

不帶條件注冊bean

如何按照條件向Spring容器中注冊bean?這次我懂了

 

 

我們在PersonConfig2類中新增person01()方法和person02()方法,并為兩個方法添加@Bean注解,如下所示。

@Bean("binghe001")
public Person person01(){
    return new Person("binghe001", 18);
}

@Bean("binghe002")
public Person person02(){
    return new Person("binghe002", 20);
}

那么,這兩個bean默認是否會被注冊到Spring容器中呢,我們新建一個測試用例來測試一下。在SpringBeanTest類中新建testAnnotationConfig6()方法,如下所示。

@Test
public void testAnnotationConfig6(){
    ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class);
    String[] names = context.getBeanNamesForType(Person.class);
    Arrays.stream(names).forEach(System.out::println);
}

我們運行testAnnotationConfig6()方法,輸出的結果信息如下所示。

person
binghe001
binghe002

從輸出結果可以看出,同時輸出了binghe001和binghe002。說明默認情況下,Spring容器會將單實例并且非懶加載的bean注冊到IOC容器中。

接下來,我們再輸出bean的名稱和bean實例對象信息,此時我們在testAnnotationConfig6()方法中添加相應的代碼片段,如下所示。

@Test
public void testAnnotationConfig6(){
    ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class);
    String[] names = context.getBeanNamesForType(Person.class);
    Arrays.stream(names).forEach(System.out::println);

    Map<String, Person> beans = context.getBeansOfType(Person.class);
    System.out.println(beans);
}

再次運行SpringBeanTest類中的testAnnotationConfig6()方法,輸出結果如下所示。

person
binghe001
binghe002
給容器中添加Person....
{person=Person(name=binghe002, age=18), binghe001=Person(name=binghe001, age=18), binghe002=Person(name=binghe002, age=20)}

可以看到,輸出了注冊到容器的bean。

帶條件注冊bean

現在,我們就要提出新的需求了,比如,如果當前操作系統是windows操作系統,則向Spring容器中注冊binghe001;如果當前操作系統是linux操作系統,則向Spring容器中注冊binghe002。此時,我們就需要使用@Conditional注解了。

這里,有小伙伴可能會問:如何獲取操作系統的類型呢,別急,這個問題很簡單,我們繼續向下看。

使用Spring的ApplicationContext接口就能夠獲取到當前操作系統的類型,如下所示。

ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class);
Environment environment = context.getEnvironment();
String osName = environment.getProperty("os.name");
System.out.println(osName);

我們將上述代碼整合到SpringBeanTest類中的testAnnotationConfig6()方法中,如下所示。

@Test
public void testAnnotationConfig6(){
    ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig2.class);
    Environment environment = context.getEnvironment();
    String osName = environment.getProperty("os.name");
    System.out.println(osName);

    String[] names = context.getBeanNamesForType(Person.class);
    Arrays.stream(names).forEach(System.out::println);

    Map<String, Person> beans = context.getBeansOfType(Person.class);
    System.out.println(beans);
}

接下來,我們運行SpringBeanTest類中的testAnnotationConfig6()方法,輸出的結果信息如下所示。

Windows 10
person
binghe001
binghe002
給容器中添加Person....
{person=Person(name=binghe002, age=18), binghe001=Person(name=binghe001, age=18), binghe002=Person(name=binghe002, age=20)}

由于我使用的操作系統是Windows 10操作系統,所以在結果信息中輸出了Windows 10。

到這里,我們成功獲取到了操作系統的類型,接下來,就可以實現:如果當前操作系統是Windows操作系統,則向Spring容器中注冊binghe001;如果當前操作系統是Linux操作系統,則向Spring容器中注冊binghe002的需求了。此時,我們就需要借助Spring的@Conditional注解來實現了。

要想使用@Conditional注解,我們需要實現Condition接口來為@Conditional注解設置條件,所以,這里,我們創建了兩個實現Condition接口的類,分別為WindowsCondition和LinuxCondition,如下所示。

  • WindowsCondition
package io.mykit.spring.plugins.register.condition;


import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * @author binghe
 * @version 1.0.0
 * @description Windows條件,判斷操作系統是否是Windows
 */
public class WindowsCondition implements Condition {
    /**
     * ConditionContext:判斷條件使用的上下文環境
     * AnnotatedTypeMetadata:注釋信息
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //判斷是否是Linux系統
        //1.獲取到IOC容器使用的BeanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //2.獲取類加載器
        ClassLoader classLoader = context.getClassLoader();
        //3.獲取當前的環境信息
        Environment environment = context.getEnvironment();
        //4.獲取bean定義的注冊類,我們可以通過BeanDefinitionRegistry對象查看
        //Spring容器中注冊了哪些bean,也可以通過BeanDefinitionRegistry對象向
        //Spring容器中注冊bean,移除bean,查看bean的定義,查看是否包含某個bean的定義
        BeanDefinitionRegistry registry = context.getRegistry();
        String property = environment.getProperty("os.name");
        return property.contains("Windows");
    }
}
  • LinuxCondition
package io.mykit.spring.plugins.register.condition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * @author binghe
 * @version 1.0.0
 * @description Linux條件,判斷操作系統是否是Linux
 */
public class LinuxCondition implements Condition {
    /**
     * ConditionContext:判斷條件使用的上下文環境
     * AnnotatedTypeMetadata:注釋信息
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //判斷是否是Linux系統
        //1.獲取到IOC容器使用的BeanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //2.獲取類加載器
        ClassLoader classLoader = context.getClassLoader();
        //3.獲取當前的環境信息
        Environment environment = context.getEnvironment();
        //4.獲取bean定義的注冊類,我們可以通過BeanDefinitionRegistry對象查看
        //Spring容器中注冊了哪些bean,也可以通過BeanDefinitionRegistry對象向
        //Spring容器中注冊bean,移除bean,查看bean的定義,查看是否包含某個bean的定義
        BeanDefinitionRegistry registry = context.getRegistry();
        String property = environment.getProperty("os.name");
        return property.contains("linux");
    }
}

接下來,我們就需要在PersonConfig2類中使用@Conditional注解添加條件了。添加注解后的方法如下所示。

@Conditional({WindowsCondition.class})
@Bean("binghe001")
public Person person01(){
    return new Person("binghe001", 18);
}

@Conditional({LinuxCondition.class})
@Bean("binghe002")
public Person person02(){
    return new Person("binghe002", 20);
}

此時,我們再次運行SpringBeanTest類中的testAnnotationConfig6()方法,輸出的結果信息如下所示。

Windows 10
person
binghe001
給容器中添加Person....
{person=Person(name=binghe002, age=18), binghe001=Person(name=binghe001, age=18)}

可以看到,輸出結果中不再含有名稱為binghe002的bean了,說明程序中檢測到當前操作系統為Windows10,沒有向Spring容器中注冊名稱為binghe002的bean。

@Conditional注解也可以標注在類上,標注在類上含義為:滿足當前條件,這個類中配置的所有bean注冊才能生效,大家可以自行驗證@Conditional注解標注在類上的情況

@Conditional的擴展注解

@ConditionalOnBean:僅僅在當前上下文中存在某個對象時,才會實例化一個Bean。
@ConditionalOnClass:某個class位于類路徑上,才會實例化一個Bean。
@ConditionalOnExpression:當表達式為true的時候,才會實例化一個Bean。
@ConditionalOnMissingBean:僅僅在當前上下文中不存在某個對象時,才會實例化一個Bean。
@ConditionalOnMissingClass:某個class類路徑上不存在的時候,才會實例化一個Bean。
@ConditionalOnNotWebApplication:不是web應用,才會實例化一個Bean。
@ConditionalOnBean:當容器中有指定Bean的條件下進行實例化。
@ConditionalOnMissingBean:當容器里沒有指定Bean的條件下進行實例化。
@ConditionalOnClass:當classpath類路徑下有指定類的條件下進行實例化。
@ConditionalOnMissingClass:當類路徑下沒有指定類的條件下進行實例化。
@ConditionalOnWebApplication:當項目是一個Web項目時進行實例化。
@ConditionalOnNotWebApplication:當項目不是一個Web項目時進行實例化。
@ConditionalOnProperty:當指定的屬性有指定的值時進行實例化。
@ConditionalOnExpression:基于SpEL表達式的條件判斷。
@ConditionalOnJava:當JVM版本為指定的版本范圍時觸發實例化。
@ConditionalOnResource:當類路徑下有指定的資源時觸發實例化。
@ConditionalOnJndi:在JNDI存在的條件下觸發實例化。
@ConditionalOnSingleCandidate:當指定的Bean在容器中只有一個,或者有多個但是指定了首選的Bean時觸發實例化。

@Conditional 與@Profile 的對比

Spring3.0 也有一些和@Conditional 相似的注解,它們是Spring SPEL 表達式和Spring Profiles 注解 Spring4.0的@Conditional 注解要比@Profile 注解更加高級。@Profile 注解用來加載應用程序的環境。@Profile注解僅限于根據預定義屬性編寫條件檢查。 @Conditional注釋則沒有此限制。

Spring中的@Profile 和 @Conditional 注解用來檢查"If…then…else"的語義。然而,Spring4 @Conditional是@Profile 注解的更通用法。

  • Spring 3中的 @Profile僅用于編寫基于Environment變量的條件檢查。 配置文件可用于基于環境加載應用程序配置。
  • Spring 4 @Conditional注解允許開發人員為條件檢查定義用戶定義的策略。 @Conditional可用于條件bean注冊。

好了,咱們今天就聊到這兒吧!別忘了給個在看和轉發,讓更多的人看到,一起學習一起進步!!

項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation

分享到:
標簽:Spring
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定