首先,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的方法剛開始學習,慢慢做積累;