@zhuanxu
2017-11-22T13:31:54.000000Z
字数 3895
阅读 2119
Spring
Spring 中的 Bean 都需要 Spring 容器进行管理,方法有两种:
容器获取 Bean 有两种方式:一种是根据 类型来获取(限制是只能有一个类型的获取方法),另一种是根据名字来获取:名字默认是方法名,看下面的例子。
怎么通过名字获取Bean,方法是 getBean(),一个大概的流程如下:
DefaultListableBeanFactory.getBean()
doGetBean()
DefaultSingletonBeanRegistry.getSingleton()
Map<String, Object> singletonObjects.get()
getObjectForBeanInstance() // 处理factory bean
我们会发现DefaultSingletonBeanRegistry.singletonObjects
中已经存在了单例的Bean了,每个Bean都有自己的名字,对于Component注释的,名字默认为类小写
@Component
public class User {
}
对于@Bean
修饰的,名字默认为方法名。
@Bean
User createUser() {
System.out.println("user config createUser");
return new User();
}
下面我们看怎么通过class来获取Bean
DefaultListableBeanFactory.getBean()
resolveNamedBean()
getBeanNamesForType()
doGetBeanNamesForType()
List<String> beanDefinitionNames //遍历所有bean的名字看type是否符合
Map<String, BeanDefinition> beanDefinitionMap.get(beanName) // 判断是否有 BeanDefinition 定义
determinePrimaryCandidate() // 多个Bean存在找 Primary
determineHighestPriorityCandidate() // 多个Bean 找优先级
getPriority()
里面需要注意的是通过classType获取Bean的方式限制是多个bean相同类型的bean存在的时候,需要指定一个Primary。
@Autowired
先看第一种:
@Component
public class User {
@Autowired
ApplicationContext applicationContext;
}
接着第二种:
@Component
public class Bank {
private ApplicationContext applicationContext;
public Bank(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
但是构造函数的限制是如果有多个构造函数,则必须要声明一个默认构造函数,然后还是通过@Autowired的方法来注入属性。
public class Book implements ApplicationContextAware {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
第三种通过实现接口ApplicationContextAware
,那具体是怎么做到的呢?这就要说到BeanPostProcessor
,其接口定义如下:
两个方法的区别是差一个init方法。
BeanPostProcessor
的作用是在 Bean
初始化的时候留出了扩展点。
下面我们看Spring中是怎么使用 BeanPostProcessor
的。
我们在调用Context的时候,Context会去调用refresh方法,然后里面会调用到
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
然后这个 ApplicationContextAwareProcessor
就是实现了 BeanPostProcessor
接口,里面会对每个 Bean 判断是否是 aware,做相应处理:
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
这个是在 context 的 BeanFactory 初始完后调用的。看下具体的代码:
AbstractApplicationContext.refresh()
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
里面可以看到是先调用 BeanFactoryPostProcessor ,然后再调用 BeanPostProcessor。
下面看 BeanDefinitionRegistryPostProcessor
,他是 BeanFactoryPostProcessor 的子类:
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
里面涉及到 BeanDefinitionRegistry
,这个的作用类似于@Component
,将Bean注册进容器里。来看一段实例代码:
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
for(int i=0;i<10;i++){
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(Person.class);
bdb.addPropertyValue("name","admin" + i);
registry.registerBeanDefinition("person"+i,bdb.getBeanDefinition());
}
}
里面我们自己添加进去了bean,在app里面就能访问了。