使用spring配置類代替xml配置文件注冊bean類


spring配置類,即在類上加@Configuration注解,使用這種配置類來注冊bean,效果與xml文件是完全一樣的,只是創建springIOC容器的方式不同:

//通過xml文件創建springIOC容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-beans.xml"); //通過配置類創建springIOC容器 ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);

 

0. 傳統的xml配置文件方式注冊bean類

單個注冊

<!--單實例模式-->
<bean id="person" class="cn.monolog.entity.Person" scope="singleton" />
<!--多實例模式-->
<bean id="book" class="cn.monolog.entity.Book" scope="prototype" />

掃描批量注冊,只能注冊加了組件注解(@Repository、@Service、@Controller、@Component)的類

<!--通過掃描批量注冊加了組件注解的bean-->
<context:component-scan base-package="cn.monolog.entity" />

 

1. 使用配置類單個注冊

①在配置類上加@Configuration注解

②在方法上加@Bean注解,bean的id默認為方法名,如果需要自定義id,則在該注解上加value屬性

③如果需要指定bean的作用域,則還要在方法上加@Scope注解,如果不加該注解,則默認為單例模式

該注解的value屬性有如下幾種常用取值(均為字符串格式)

單例模式(singleton): 創建IOC容器時即創建bean對象,以后每次取值都是取的這個bean對象

原型模式(protortype): 創建IOC容器時不創建bean對象,以后每次取值時再分別創建

另外還有request、session、global session

④對於單例模式,還可以加@Lazy注解,即懶加載,表示在創建IOC容器時並不創建bean對象,而是在第一次獲取bean對象時才創建,之后再獲取bean對象時不再創建,因此仍然是單實例

懶加載的作用:加快SpringIOC容器的啟動速度、解決循環依賴的問題

/**
 * springIOC配置容器類
 * 用於代替spring-beans.xml,生成bean對象
 */
@Configuration
public class BeanConfig {

    //生成Person實例
    @Bean(value = "person")
    public Person person() {
        String name = "張三";
        int age = 29;
        return new Person(name, age);
    }

    /**
     * 使用單實例模式生成Book實例
     * 這時,是在springIOC容器啟動時就創建了bean實例,然后每次獲取實例時,直接從容器中拿
     */
    @Bean(value = "singleBook")
    @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
    public Book singleBook() {
        String name = "hello world";
        double price = 29.00D;
        return new Book(name, price);
    }

    /**
     * 使用多實例模式生成Book實例
     * 這時,啟動springIOC容器時並未創建bean實例,而是每次獲取bean實例時再調用該方法去新創建
     */
    @Bean(value = "multipleBook")
    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Book multipleBook() {
        String name = "hello world";
        double price = 29.00D;
        return new Book(name, price);
    }

  /**
     * 使用懶加載模式生成bean實例
     * 懶加載只對單實例模式有效
     * 本來,單實例模式,是在啟動springIOC容器時創建bean實例
     * 使用懶加載后,在啟動springIOC容器時並不創建bean實例,而是在首次獲取bean時才創建
     */
    @Bean(value = "person")
    @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
    @Lazy
    public Person person() {
        return new Person("劉能", 53);
    }  
}

 

2. 使用配置類掃描批量注冊,只能注冊加了組件注解(@Repository、@Service、@Controller、@Component)的類

①在配置類上加@Configuration注解

②在配置類上加@ComponentScan注解,並在其basePackages屬性(字符串數組類型)中寫明要掃描的包,可以寫1個或多個包,如果想排除某些類,可以寫在excludeFilter屬性中

/**
 * 通過掃描批量注冊加了組件注解的bean
 * 並排除Dog類
 */
@Configuration
@ComponentScan(basePackages = {"cn.monolog.entity", "cn.monolog.service", "cn.monolog.dao"},
excludeFilters
= {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {Dog.class})}) public class BeanConfig { }

 

3. 按條件注冊

①在配置類上加@Configuration注解

②在方法上加@Bean注解,bean的id默認為方法名,如果需要自定義id,則在該注解上加value屬性

③在方法上加@Conditional注解,該注解的參數是字節碼數組,什么樣的類的字節碼呢?必須是實現了Condition接口的。使用時,需要自定義1個或多個Condition的實現類,並在其實現方法中定義生效條件,當滿足生效條件時,才會去注冊該bean類

import org.springframework.context.annotation.Condition;

/**
 * springIOC條件注冊中的條件類
 */
public class JuventusCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //獲取bean注冊器
        BeanDefinitionRegistry registry = context.getRegistry();

        //判斷該IOC容器中是否含有id為juventus的組件,如果是,則生效
        if (registry.containsBeanDefinition("juventus")) {
            return true;
        }

        return false;
    }
}
/**
 * 按條件注冊bean類
 */
@Configuration
public class BeanConfig {
    
    /**
     * 按條件生成名字為ronaldo的Person對象
     * 條件為寫在JuventusCondition類中
     */
    @Bean(value = "ronaldo")
    @Scope(value = SCOPE_SINGLETON)
    @Conditional({JuventusCondition.class})
    public Person ronaldo() {
        return new Person("ronaldo", 34);
    }
}

 

4. 使用導入方式注冊

①在配置類上加@Configuration注解

②在配置類上加@Import注解,該注解的value屬性為字節碼數組,可以接收以下三種類的字節碼

要注冊的類;

實現了ImportSelector接口的自定義類,其實現方法的返回值為要注冊的類的全限定名數組;

實現了ImportBeanDefinitionRegistrar的自定義類,在其實現方法中,使用BeanDefinitionRegistry手動注冊,前面兩種方式注冊的bean的id只能是類的全限定名,只有這種方式可以自定義bean的id;

import org.springframework.context.annotation.ImportSelector;

/**
 * 使用import注解注冊bean的選擇器
 * 注意該方法可以返回空數組,但不能返回null,因為在后續源碼中會獲取返回值的長度
 * 而且這里只能用類的全限定名
 */
public class ColorImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        String[] results = {"cn.monolog.entity.Green", "cn.monolog.entity.Pink"};
        return results;
    }
}
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;

/**
 * 使用import注解注冊bean時,自定義bean選擇器
 * 在該類的實現方法中,使用bean注冊器手動注冊
 * 注意,如果多次為同一個id注冊bean,后面的會覆蓋前面的
 */
public class ColorDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //判斷該容器中是否已經存在id為yellow的組件,如果不存在,則手動注冊
        String id = "yellow";
        if (!registry.containsBeanDefinition(id)) {
            //bean的id
            String beanName = "yellow";
            //bean的類型
            BeanDefinition beanDefinition = new RootBeanDefinition(Yellow.class);
            registry.registerBeanDefinition(beanName, beanDefinition);
        }
    }
}
/**
 * springIOC容器配置類
 * 使用import注解注冊bean
 * 該注解可以接收三種參數
 * 1.要注冊的類的字節碼
 * 2.ImportSelector的自定義實現類的字節碼,在其實現方法中,將要注冊的類的全限定名寫入返回數組
 * 3.ImportBeanDefinitionRegistrar的自定義實現類的字節碼,在其實現方法中,使用bean注冊器手動注冊
 * 其中,前兩種方式注冊的bean的id只能是該類的全限定名
 * 第三種方式注冊的bean類可以自定義id
 */
@Configuration
@Import({Red.class, ColorImportSelector.class, ColorDefinitionRegistrar.class})
public class BeanConfig {
}

 

5. 使用工廠模式注冊

工廠模式與第1條(單個注冊)的方法完全相同,唯一的特別之處在於,注冊的是一個"工廠類",即實現了FactoryBean<T>接口的自定義類,這種類的特點是,在IOC容器中直接按id獲取的並不是它本身的對象,而是它內部注冊的bean類的對象。要想獲取它本身的對象,要在id前面拼接"&"符號。

FactoryBean<T>接口有三個方法:

getObject——用於注冊真正的bean類

getObjectType——用於獲取bean類的類型,即泛型T

isSingleton——注冊的bean類是否為單例模式

import org.springframework.beans.factory.FactoryBean;

/**
 * 工廠類
 */
public class ColorFactoryBean implements FactoryBean<Color> {

    //注冊bean
    @Override
    public Color getObject() throws Exception {
        return new Color("#FFF");
    }

    //獲取bean的類型
    @Override
    public Class<?> getObjectType() {
        return Color.class;
    }

    //是否單實例模式
    @Override
    public boolean isSingleton() {
        return true;
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM