@zhuanxu
2017-11-22T05:31:54.000000Z
字数 3895
阅读 2429
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注释的,名字默认为类小写
@Componentpublic class User {}
对于@Bean修饰的,名字默认为方法名。
@BeanUser 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存在找 PrimarydetermineHighestPriorityCandidate() // 多个Bean 找优先级getPriority()
里面需要注意的是通过classType获取Bean的方式限制是多个bean相同类型的bean存在的时候,需要指定一个Primary。
@Autowired先看第一种:
@Componentpublic class User {@AutowiredApplicationContext applicationContext;}
接着第二种:
@Componentpublic 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里面就能访问了。