bean的创建

bean其实就是一个对象,创建bean的方式

  1. 程序员编写代码new一个对象
  2. Java的SPI发现机制,通过ServiceLoader加载
  3. Spring 加载,用Spring加载,需要把加载的bean的元数据告诉Spring,元数据配置方式有自动装配和显式配置,加载到Spring的元数据,以BeanDefinition形式存在

自动装配

自动发现并创建bean,用Component注解,需要在xml配置组件扫描component-scan
<context:component-scan base-package="${scb-scan-package:org.apache.servicecomb}"/>

自动装配,用AutoWiring注解

显式配置

Java和Xml两种方式

java方式:使用Configuration注解

ApplicationContext

  • 获取类型获取类getBean
    RestProducers restProducers = BeanUtils.getContext().getBean(RestProducers.class);
  • 根据接口获取bean实例:getBeansOfType
    scbEngine.getConsumerProviderManager().getConsumerProviderList().
    addAll(applicationContext.getBeansOfType(ConsumerProvider.class).values());

高级装配:运行时注入值

  • 属性占位符
    使用方式${...}, 自动扫描,需要配合@Value使用
    另外,需要配置一个PropertySourcesPlaceholderConfigrer bean
    如果使用xml的话,配置<context:propertyplaceholder>
    举例,
    <context:component-scan base-package="${scb-scan-package:org.apache.servicecomb}"/>
    冒号表达式,是配置默认值org.apache.servicecomb
  • Spring语言表达式:SpEL
    使用方式#{...},如#{T(System).currentTimeMills()},表达式计算结果是当前毫秒数

资源相关

  • 获取classpath下的properties文件PathMatchingResourcePatternResolver

    private static final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
    
    //locationPattern="classpath*:config/base/log4j.properties"
    resourcePatternResolver.getResources(locationPattern);
    

配置管理

项目有两个配置加载源,一个是serviceComb默认的ConfigurationSpringInitializer,另一个是自己添加的TestConfig,配置源是文件test.properties

test.properties中定义APPLICATION_ID=1111,而serviceComb中microservice.ymal定义APPLICATION_ID: edge

@Configuration
public class TestConfig extends PropertySourcesPlaceholderConfigurer implements EnvironmentAware {

    public TestConfig() {
        try {

            ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resourcePatternResolver.getResources("classpath*:test.properties");
            this.setLocation(resources[0]);
        } catch (Exception e) {
            e.printStackTrace();
        }

        setOrder(Ordered.LOWEST_PRECEDENCE / 2 - 1);

    }
}

那么如下value配置最后取值是什么呢?是edge

@Service
public class Test {

    @Value("${APPLICATION_ID}")
    private String value;

    @Value("v2")
    private String value2;

    public void say() {
        System.out.println(value + " done" + " " + value2);
    }
}

如图,结果却是是edge
image.png

为什么?因为propertySources有两个数据源,一个是environment,一个localProperties;environment是serviceComb的ConfigurationSpringInitializer注入进去APPLICATION_ID: edge,所以返回edge,而不是test.properties的111
image.png

bean的创建

BeanFactoryPostProcessors

通过beanFactory创建
beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)

AbstractApplicationContext

BeanFactoryPostProcessor
注册bean处理器,先执行BeanDefinitionRegistryPostProcessors,再到BeanFactoryPostProcessors,顺序是PriorityOrdered标记接口,Ordered标记接口,无标记接口
BeanFactoryPostProcessor常见使用场景,在普通bean实例化之前,对bean里面的@Value等配置注解进行解析

invokeBeanFactoryPostProcessors方法执行如下操作

  1. First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
  2. Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
  3. Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
  4. Separate between BeanFactoryPostProcessors that implement PriorityOrdered,Ordered, and the rest.

BeanPostProcessor
解析Spring的BeanPostProcessor实现类,并注册到beanFactory中,方便后续创建普通bean,对普通bean进行处理

registerBeanPostProcessors

  1. First, register the BeanPostProcessors that implement PriorityOrdered.
  2. Next, register the BeanPostProcessors that implement Ordered.
  3. Now, register all regular BeanPostProcessors.
  4. Finally, re-register all internal BeanPostProcessors.

普通bean
finishBeanFactoryInitialization
beanFactory.preInstantiateSingletons();
createBeanInstance
populateBean
//bean字段装配包括属性@Value注解解析
AutowiredAnnotationBeanPostProcessor.postProcessProperties
metadata.inject(bean, beanName, pvs);
element.inject(target, beanName, pvs);
AutowiredAnnotationBeanPostProcessor.resolveFieldValue
beanFactory.resolveDependency
//AbstractBeanFactory 遍历this.embeddedValueResolvers解析result,一旦解析成功就返回
resolver.resolveStringValue(result);

Spring三级缓存

spring为什么用三级缓存,只用1/2级也是可以的;网上说用三级缓存是为了方便生成AOP代理类;其实这个不是必须。其实三级缓存是从Spring框架设计的角度去考虑的,做一个框架,最少暴露内部细节(三级缓存解决循环依赖的细节),即迪米特法则LOD,让框架的集成方不需要了解太多框架内部的东西,这样就能够减少耦合;方便框架演进;最少侵入,良好的拓展性和自主演进是判断一个框架是否优秀的重要参考。


ThinkFault
13 声望1 粉丝