關(guān)于Spring的編譯可以看我之前寫的文章,該文展示了在Mac下編譯Spring 5的流程
本文內(nèi)容主要基于Spring的注解開(kāi)發(fā)
如何將Bean導(dǎo)入容器
首先準(zhǔn)備一個(gè)POJO:
public class User {
private String name;
public User(String name) {
this.name = name;
}
}
接著公般,一般使用Spring我們需要準(zhǔn)備一份配置文件,但是基于注解開(kāi)發(fā)就不需要了胡桨。只要準(zhǔn)備一個(gè)注解配置類即可:
@Configuration
public class BeanConfig {
@Bean
public User user(){
return new User("Q");
}
}
將配置類傳入AnnotationConfigApplicationContext類:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
這樣官帘,我們就獲得了Spring的容器抽象接口ApplicationContext。
想要從容器中獲取被Spring接管的Bean昧谊,我們可以調(diào)用ApplicationContext#getBean
Object user = applicationContext.getBean("user");
好樣的刽虹,恭喜你成功已經(jīng)學(xué)會(huì)了Spring框架的使用。
@Bean
通過(guò)第一個(gè)例子可以看出呢诬,在@Configuration
注解標(biāo)注的配置類中可以通過(guò)@Bean
注解標(biāo)注方法進(jìn)而將方法返回值導(dǎo)入容器涌哲。
@ComponentScan
批量導(dǎo)入,@ComponentScan
注解也是一個(gè)不錯(cuò)的選擇尚镰,它可以將指定包下的所有@Component
@Service
@Repository
@Controller
注解標(biāo)注的類加入容器阀圾,這里就不多說(shuō)了。
@Import
@Import
注解主要提供配置類導(dǎo)入的功能狗唉。
準(zhǔn)備一個(gè)配置類:
@Configuration
public class ForImport {
@Bean
public User user(){
return new User("Q");
}
}
使用@Import
導(dǎo)入該配置:
@Import(ForImport.class)
public class ImportConfig {
}
測(cè)試:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ImportConfig.class);
Object user = applicationContext.getBean("user");
System.out.println(user);
結(jié)果:
User{name='Q'}
這只是其中一種用法初烘。
@Import
注解還可以直接將普通類作為Bean導(dǎo)入到容器。
準(zhǔn)備一個(gè)類:
public class Dog {
}
修改之前的ImportConfig類:
@Import({ForImport.class, Dog.class})
public class ImportConfig {
}
測(cè)試:
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ImportConfig.class);
printBeans(applicationContext);
}
public static void printBeans(ApplicationContext applicationContext) {
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
結(jié)果:
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
importConfig
top.hellooooo.blog.config.ForImport
user
top.hellooooo.blog.bean.Dog
可以看到分俯,通過(guò)@Import
導(dǎo)入的類作為Bean在容器中的名字是類的全限定路徑加上類名肾筐。
你以為這就是@Import
的全部功能了嗎?Too young缸剪,too naive
打開(kāi)Spring關(guān)于Import注解的接口源碼
/**
* {@link Configuration @Configuration}, {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
*/
Class<?>[] value();
除去Configuration
吗铐,還有ImportSelector
以及ImportBeanDefinitionRegistrar
。
ImportSelector
ImportSelector
接口有兩個(gè)方法杏节,我們看第一個(gè):
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
* @return the class names, or an empty array if none
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
一目了然唬渗,將返回的字符串代表的類導(dǎo)入讥此。
下面實(shí)現(xiàn)我們自己的ImportSelector
:
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"top.hellooooo.blog.bean.Dog"};
}
}
修改ImportConfig
:
@Import({ForImport.class, MyImportSelector.class})
public class ImportConfig {
}
結(jié)果:
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
importConfig
top.hellooooo.blog.config.ForImport
user
top.hellooooo.blog.bean.Dog
ImportBeanDefinitionRegistrar
Import
注解源碼里出現(xiàn)過(guò)ImportBeanDefinitionRegistrar,一看這名字就懂了谣妻,肯定是直接將BeanDefinition
導(dǎo)入容器。
這是ImportBeanDefinitionRegistrar
的一個(gè)默認(rèn)方法
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
BeanNameGenerator importBeanNameGenerator) {
registerBeanDefinitions(importingClassMetadata, registry);
}
AnnotationMetadata接口可以獲取@Import
類上的所有注解信息卒稳,BeanDefinitionRegistry接口則用來(lái)注冊(cè)Bean蹋半。
來(lái)一個(gè)例子:
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Set<String> annotationTypes = importingClassMetadata.getAnnotationTypes();
for (String annotationType : annotationTypes) {
System.out.println("---->" + annotationType);
}
BeanDefinition dog = new RootBeanDefinition(Dog.class);
registry.registerBeanDefinition("dog", dog);
}
}
同樣,修改ImportConfig
:
@Import({ForImport.class, MyImportBeanDefinitionRegistrar.class})
public class ImportConfig {
}
結(jié)果:
---->org.springframework.context.annotation.Import
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
importConfig
top.hellooooo.blog.config.ForImport
user
dog
嗯充坑,不錯(cuò)减江。
不過(guò),針對(duì)復(fù)雜類的導(dǎo)入捻爷,Spring還提供了FactoryBean
接口辈灼,我們來(lái)看看。
FactoryBean
FactoryBean
總共含有3個(gè)方法:
public Cat getObject() throws Exception;
public Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
getObject返回實(shí)例(返回此工廠創(chuàng)建的對(duì)象的實(shí)例也榄。實(shí)例是否可以共享巡莹,具體取決于該工廠是否返回單例或原型。)甜紫,getObjectType返回由getObject()方法返回的對(duì)象類型降宅;如果類型未知,則返回null囚霸。
就不舉例了腰根,獲取FactoryBean生成的Bean和普通Bean一樣,getBean即可拓型,如果要獲取FactoryBean本身的話额嘿,傳入getBean的字符串前加上"&"即可。
"&"在BeanFactory中被定義:
String FACTORY_BEAN_PREFIX = "&";