一、BeanFactory和ApplicationContext的关系
首先看下类图:
由上图可知,BeanFactory是ApplicationContex的接口,主要是生成、获取bean;而ApplicationContex又拓展了许多高级特性,比如国际化、访问资源文件、事件发布、AOP等。
二、Spring解决循环依赖的代码位置
AbstractApplicationContext#finishBeanFactoryInitialization
->DefaultListableBeanFactory#preInstantiateSingletons
->AbstractBeanFactory#doGetBean
->DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
三、AOP生成代理的代码位置(Bean实例化之前)
AbstractApplicationContext#finishBeanFactoryInitialization
->DefaultListableBeanFactory#preInstantiateSingletons
->AbstractBeanFactory#doGetBean
->AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])
->AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
->AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
而AOP是基于AnnotationAwareAspectJAutoProxyCreator类实现的,它又实现了BeanPostProcessor接口,所以当Spring加载这个Bean时会在实例化前调用其postProcessAfterInitialization方法,此方法就是AOP创建代理。具体的调用链如下
AbstractAutoProxyCreator#postProcessAfterInitialization
->AbstractAutoProxyCreator#createProxy
->DefaultAopProxyFactory#createAopProxy
DefaultAopProxyFactory#createAopProxy类的代码实现截图如下:
四、Spring容器实现拓展的重要接口-BeanFactoryPostProcessor
以Spring整合Mybatis为例,Mybatis只定义了mapper接口,无实现类,但spring却可以完成自动注入!这就是通过实现BeanFactoryPostProcessor接口,将mapper接口和mapper.xml文件以MapperFactoryBean的类型注册到Spring中的,当从Spring中获取Mapper接口时,将会调用对应的MapperFactoryBean的getObjects方法,该方法返回值即为对应的MapperProxyFactory创建的MapperProxy动态代理对象。Spring整合Mybatis就是用MapperScannerConfigurer这个类来实现BeanFactoryPostProcessor的,下面是MapperScannerConfigurer类的继承关系图:
调用链如下:
MapperScannerConfigurer#postProcessBeanDefinitionRegistry
-> ClassPathMapperScanner#doScan
-> ClassPathMapperScanner#processBeanDefinitions
接下来再进入ClassPathMapperScanner的processBeanDefinitions方法,看下ClassPathMapperScanner是如何偷梁换柱,将mapper接口和mapper.xml文件以MapperFactoryBean的类型注册到Spring中的!
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
if (logger.isDebugEnabled()) {
logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()
+ "' and '" + definition.getBeanClassName() + "' mapperInterface");
}
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
/**
就是此处将Mapper接口Bean的Class类型改成MapperFactoryBean,
此FactoryBean的getObjects就是生动态代理的地方
**/
definition.setBeanClass(this.mapperFactoryBean.getClass());
definition.getPropertyValues().add("addToConfig", this.addToConfig);
boolean explicitFactoryUsed = false;
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
if (!explicitFactoryUsed) {
if (logger.isDebugEnabled()) {
logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
}
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
}
五、AbstractApplicationContext的onRefresh()方法
AbstractApplicationContext的onRefresh()方法是个空的模板方法,并没有具体的业务逻辑。而在springboot中其子类EmbeddedWebApplicationContext重写了该方法,springboot内置的容器(如Tomcat)正是在此方法中创建的!
先看下类的继承关系:
调用链如下:
AbstractApplicationContext#refresh
->AbstractApplicationContext#onRefresh
->EmbeddedWebApplicationContext#onRefresh
->EmbeddedWebApplicationContext#createEmbeddedServletContainer
->TomcatEmbeddedServletContainerFactory#getEmbeddedServletContainer
接下来再进入TomcatEmbeddedServletContainerFactory#getEmbeddedServletContainer()方法看下Tomcat是如何创建的。
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory
: createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatEmbeddedServletContainer(tomcat);
}
六、AbstractApplicationContext#finishRefresh()方法
Spring容器已经大致刷新完成,此时会调用AbstractApplicationContext#publishEvent(ApplicationEvent)方法进行上下文刷新完成事件广播,Dubbo的服务暴露就是在此时执行的!
我们知道,< dubbo:service > 标签会被解析成 ServiceBean,ServiceBean 实现了 ApplicationListener,在 Spring 容器初始化的时候会调用 onApplicationEvent 方法。ServiceBean 重写了 onApplicationEvent 方法,实现了服务暴露的功能。
ServiceBean#onApplicationEvent
public void onApplicationEvent(ContextRefreshedEvent event) {
if (!isExported() && !isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
// 暴露服务
export();
}
}