bean的创建
bean其实就是一个对象,创建bean的方式
- 程序员编写代码new一个对象
- Java的SPI发现机制,通过ServiceLoader加载
- 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
为什么?因为propertySources有两个数据源,一个是environment,一个localProperties;environment是serviceComb的ConfigurationSpringInitializer注入进去APPLICATION_ID: edge,所以返回edge,而不是test.properties的111
bean的创建
BeanFactoryPostProcessors
通过beanFactory创建
beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)
AbstractApplicationContext
BeanFactoryPostProcessor
注册bean处理器,先执行BeanDefinitionRegistryPostProcessors,再到BeanFactoryPostProcessors,顺序是PriorityOrdered标记接口,Ordered标记接口,无标记接口
BeanFactoryPostProcessor常见使用场景,在普通bean实例化之前,对bean里面的@Value等配置注解进行解析
invokeBeanFactoryPostProcessors方法执行如下操作
- First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
- Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
- Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
- Separate between BeanFactoryPostProcessors that implement PriorityOrdered,Ordered, and the rest.
BeanPostProcessor
解析Spring的BeanPostProcessor实现类,并注册到beanFactory中,方便后续创建普通bean,对普通bean进行处理
registerBeanPostProcessors
- First, register the BeanPostProcessors that implement PriorityOrdered.
- Next, register the BeanPostProcessors that implement Ordered.
- Now, register all regular BeanPostProcessors.
- 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,让框架的集成方不需要了解太多框架内部的东西,这样就能够减少耦合;方便框架演进;最少侵入,良好的拓展性和自主演进是判断一个框架是否优秀的重要参考。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。