[关闭]
@zhuanxu 2017-11-22T05:31:54.000000Z 字数 3895 阅读 805

Spring 扩展分析

Spring


Spring 中的 Bean 都需要 Spring 容器进行管理,方法有两种:

容器获取 Bean 有两种方式:一种是根据 类型来获取(限制是只能有一个类型的获取方法),另一种是根据名字来获取:名字默认是方法名,看下面的例子。

怎么通过名字获取Bean,方法是 getBean(),一个大概的流程如下:

  1. DefaultListableBeanFactory.getBean()
  2. doGetBean()
  3. DefaultSingletonBeanRegistry.getSingleton()
  4. Map<String, Object> singletonObjects.get()
  5. getObjectForBeanInstance() // 处理factory bean

我们会发现DefaultSingletonBeanRegistry.singletonObjects中已经存在了单例的Bean了,每个Bean都有自己的名字,对于Component注释的,名字默认为类小写

  1. @Component
  2. public class User {
  3. }

对于@Bean修饰的,名字默认为方法名。

  1. @Bean
  2. User createUser() {
  3. System.out.println("user config createUser");
  4. return new User();
  5. }

下面我们看怎么通过class来获取Bean

  1. DefaultListableBeanFactory.getBean()
  2. resolveNamedBean()
  3. getBeanNamesForType()
  4. doGetBeanNamesForType()
  5. List<String> beanDefinitionNames //遍历所有bean的名字看type是否符合
  6. Map<String, BeanDefinition> beanDefinitionMap.get(beanName) // 判断是否有 BeanDefinition 定义
  7. determinePrimaryCandidate() // 多个Bean存在找 Primary
  8. determineHighestPriorityCandidate() // 多个Bean 找优先级
  9. getPriority()

里面需要注意的是通过classType获取Bean的方式限制是多个bean相同类型的bean存在的时候,需要指定一个Primary。

注入方法

  1. 注释 @Autowired
  2. 参数构造函数
  3. 实现特定的Aware接口

先看第一种:

  1. @Component
  2. public class User {
  3. @Autowired
  4. ApplicationContext applicationContext;
  5. }

接着第二种:

  1. @Component
  2. public class Bank {
  3. private ApplicationContext applicationContext;
  4. public Bank(ApplicationContext applicationContext) {
  5. this.applicationContext = applicationContext;
  6. }
  7. }

但是构造函数的限制是如果有多个构造函数,则必须要声明一个默认构造函数,然后还是通过@Autowired的方法来注入属性。


  1. public class Book implements ApplicationContextAware {
  2. private ApplicationContext applicationContext;
  3. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  4. this.applicationContext = applicationContext;
  5. }
  6. }

第三种通过实现接口ApplicationContextAware,那具体是怎么做到的呢?这就要说到BeanPostProcessor,其接口定义如下:

BeanPostProcessor

两个方法的区别是差一个init方法。

BeanPostProcessor 原理

BeanPostProcessor 的作用是在 Bean 初始化的时候留出了扩展点。
下面我们看Spring中是怎么使用 BeanPostProcessor 的。
我们在调用Context的时候,Context会去调用refresh方法,然后里面会调用到

  1. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

然后这个 ApplicationContextAwareProcessor 就是实现了 BeanPostProcessor 接口,里面会对每个 Bean 判断是否是 aware,做相应处理:

  1. private void invokeAwareInterfaces(Object bean) {
  2. if (bean instanceof Aware) {
  3. if (bean instanceof EnvironmentAware) {
  4. ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
  5. }
  6. if (bean instanceof EmbeddedValueResolverAware) {
  7. ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
  8. }
  9. if (bean instanceof ResourceLoaderAware) {
  10. ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
  11. }
  12. if (bean instanceof ApplicationEventPublisherAware) {
  13. ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
  14. }
  15. if (bean instanceof MessageSourceAware) {
  16. ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
  17. }
  18. if (bean instanceof ApplicationContextAware) {
  19. ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
  20. }
  21. }
  22. }

BeanFactoryPostProcessor

这个是在 context 的 BeanFactory 初始完后调用的。看下具体的代码:

  1. AbstractApplicationContext.refresh()
  2. // Allows post-processing of the bean factory in context subclasses.
  3. postProcessBeanFactory(beanFactory);
  4. // Invoke factory processors registered as beans in the context.
  5. invokeBeanFactoryPostProcessors(beanFactory);
  6. // Register bean processors that intercept bean creation.
  7. registerBeanPostProcessors(beanFactory);

里面可以看到是先调用 BeanFactoryPostProcessor ,然后再调用 BeanPostProcessor。

BeanDefinitionRegistryPostProcessor

下面看 BeanDefinitionRegistryPostProcessor,他是 BeanFactoryPostProcessor 的子类:

  1. public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
  2. void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
  3. }

里面涉及到 BeanDefinitionRegistry ,这个的作用类似于@Component,将Bean注册进容器里。来看一段实例代码:

  1. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
  2. for(int i=0;i<10;i++){
  3. BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(Person.class);
  4. bdb.addPropertyValue("name","admin" + i);
  5. registry.registerBeanDefinition("person"+i,bdb.getBeanDefinition());
  6. }
  7. }

里面我们自己添加进去了bean,在app里面就能访问了。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注