Spring註解學習之:@Import

首先,Spring往IOC容器中註冊Bean的方法有以下幾種:

1、通過包掃描+註解的方式;如@Controller,@Service,@Reposity,@Component;

2、通過@Bean的形式;

3、通過@Import的形式;

4、通過BeanFactory的形式進行註冊;

前2點在上面的有所記錄過,今天就主要記錄一下在學習如何使用@Import和BeanFactory進行組件註冊;首先看一下@Import;

一、@Import

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

	/**
	 * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
	 * or regular component classes to import.
	 */
	Class<?>[] value();

}

首先可以看到@Improt需要傳入一個泛型數組,也就是說@Import({XXX.class,BBBB.class});其次,還有2個注意的地方,一個叫做ImportSelector(選擇器)和ImportBeanDefinitionRegistrar(Bean定義註冊器)。ImportSelector和ImportBeanDefinitionRegistrar都是兩個接口;換句話說就是@Import可以使用自定義組件注入,也可以使用實現ImportSelector或者是ImportBeanDefinitionRegistrar的方式進行注入;

(1)、@Import({XXX.class,BBBB.class})的方式

定義一個Animal類,Dog類,Pig類。然後通過@Import({XXX.class,BBBB.class})的方式,進行注入,上代碼;

MyConfig.class

@Configuration
@Import({Dog.class,Person.class})
public class Myconfig {
}

--------------------------------------
測試類代碼
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringTrainApplicationTests {

    @Test
    public void contextLoads() {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Myconfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }

}

結果如下:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myconfig
com.snail.tool.bean.Dog
com.snail.tool.bean.Person

可以看到,Dog和Person都有進入到IOC容器中,這裏有一點需要注意到,就是通過@Import注入的Bean,它的id默認是全類名;

(2)、ImportSelector選擇器情況

首先ImportSelector是一個接口,需要進行實現改接口,新建一個AnimalImportSelector 類,實現ImportSelector接口,如下代碼:

public class AnimalImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.snail.tool.bean.Pig","com.snail.tool.bean.Cat"};
    }
}

注意:
1、AnnotationMetadata 就是標註了@Import的當前類,可以通過該參數,拿出當前類的一些屬性;
2、selectImports方法,返回的是一個數組;
3、@Import方式注入的Bean,id默認是全類名;如果不是全類名,會報錯上下文無法找到;

運行結果:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myconfig
com.snail.tool.bean.Dog
com.snail.tool.bean.Person
com.snail.tool.bean.Pig
com.snail.tool.bean.Cat


可以看到,com.snail.tool.bean.Pig和com.snail.tool.bean.Cat已經在IOC容器中了

(3)、ImportBeanDefinitionRegistrar;同樣的,這也是一個藉口,先一個PersonImportBeanDefinitionRegistrar類來實現它,代碼如下:


public class PersonImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        
    }
}

注意:
1、AnnotationMetadata:還是被@Import註解的當前類,可以通過該參數,拿到當前類的一些屬性;
2、BeanDefinitionRegistry:Bean定義註冊器,是一個接口,接口中過的方法如下:
    void registerBeanDefinition(String var1, BeanDefinition var2) ;

    void removeBeanDefinition(String var1) throws NoSuchBeanDefinitionException;

    BeanDefinition getBeanDefinition(String var1) throws NoSuchBeanDefinitionException;

    boolean containsBeanDefinition(String var1);

    String[] getBeanDefinitionNames();

    int getBeanDefinitionCount();

    boolean isBeanNameInUse(String var1);
    
    主要用到的是registerBeanDefinition這個方法,這個方法中,有一個BeanDefinition,用於定義作用域等屬性,var1是Bean的id可以自定義;
MyConfig.class

@Configuration
@Import({Dog.class,Person.class,AnimalImportSelector.class,PersonImportBeanDefinitionRegistrar.class})
public class Myconfig {
}

---------------------------------
測試類
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringTrainApplicationTests {

    @Test
    public void contextLoads() {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Myconfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }

}

運行結果:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myconfig
com.snail.tool.bean.Dog
com.snail.tool.bean.Person
com.snail.tool.bean.Pig
com.snail.tool.bean.Cat
Student


可以看到,Student是被註冊進來的;

springboot源碼中,大量使用的都是@ImportSelector進行組件注入;通過ImportBeanDefinitionRegistrar,可以讓開發者自定義組件信息;

二、BeanFactory,Bean工廠類;通過實現FactoryBean<T>的方法,進行Bean的設定,其中T代表泛型;這裏創建一個類型爲Teacher的PersonBeanFactory類;


public class PersonBeanFactory implements FactoryBean<Teacher> {

    //返回bean對象
    @Override
    public Teacher getObject() throws Exception {
        return new Teacher();
    }

    //返回bean的類型
    @Override
    public Class<?> getObjectType() {
        return Teacher.class;
    }

    //設置作用於範圍
    @Override
    public boolean isSingleton() {
        return false;
    }
}

然後在配置類中進行配置,測試類中進行測試,代碼如下:

Myconfig.class
@Configuration
public class Myconfig {

    @Bean
    public PersonBeanFactory personBeanFactory(){
        return new PersonBeanFactory();
    }
}

-------------------------------------
測試類
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringTrainApplicationTests {

    @Test
    public void contextLoads() {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Myconfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }

}

運行結果:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myconfig
personBeanFactory


可以看到有一個叫做personBeanFactory的Bean。

我們的BeanFactory是泛型指定,那看看personBeanFactory這個Bean的類型是什麼?測試類代碼:

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringTrainApplicationTests {

    @Test
    public void contextLoads() {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Myconfig.class);
        Object personBeanFactory = applicationContext.getBean("personBeanFactory");
        System.out.println(personBeanFactory.getClass() );
    }

}

運行結果:
class com.snail.tool.bean.Teacher

以上便是4中方式,往IOC容器中註冊Bean的方法剛開始學習,慢慢做積累;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章