首先创建一个Springdemo项目
结构如下:
编写一个接口IAnimal
package com.example.spring.springdemo.animal;
public interface IAnimal {
/**
* 动物叫唤
* @return
*/
String call();
}
两个实现类Cat,Dog除了名字,内部实现都一样。
package com.example.spring.springdemo.animal.animalImpl;
import com.example.spring.springdemo.animal.IAnimal;
/**
* @program my_study_test
* @author: jan
* @create: 2020/11/28 20:25
*/
public class Cat implements IAnimal {
private String call;
public Cat(String call) {
this.call = call;
}
public String call() {
return call;
}
}
主类SpringDemoApplication
package com.example.spring.springdemo;
import com.example.spring.springdemo.animal.IAnimal;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringDemoApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
IAnimal cat = (IAnimal) context.getBean("cat");
System.out.println(cat.call());
}
}
在resources中创建application.xml文件,spring将会加载这个xml为我们创建两个bean,id唯一,将会用来获取bean实例,这里使用构造方法传入call的值。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dog" class="com.example.spring.springdemo.animal.animalImpl.Dog">
<constructor-arg name="call" value="wang!!!"/>
</bean>
<bean id="cat" class="com.example.spring.springdemo.animal.animalImpl.Dog">
<constructor-arg name="call" value="miao!!!"/>
</bean>
</beans>
启动流程:
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
这里使用ClassPathXmlApplicationContext创建一个context对象,在ClassPathXmlApplicationContext的构造方法中:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);//未指定parent
setConfigLocations(configLocations);//存放我们将要解析的xml文件名
if (refresh) {
refresh();//主要工作在这里做的
}
}
refresh()
做了主要的工作,直接跳到了AbstractApplicationContext类,多层继承shift+option+command+u查看继承实现关系图:
看看refresh()
方法里面都做了什么:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// 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);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
里面的内容太多,主要看两个方法:
obtainFreshBeanFactory();
finishBeanFactoryInitialization(beanFactory);
单拿出来看obtainFreshBeanFactory()
获取新的工厂实例,这一步涵盖了非常多的内容,其中就包括我们xml的解析以及bean的构建保存。
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
进入方法内部这里又调用了AbstractApplicationContext类
的refreshBeanFactory();
方法。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();//子类实现
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
进入子类AbstractRefreshableApplicationContext
中,方法内部:
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();//DefaultListableBeanFactory beanFactory 将会存放Spring 创建的Bean描述对象
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);//主要看这里
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
loadBeanDefinitions(beanFactory);
在AbstractXmlApplicationContext
中,做了非常多的事情,重载了很多种,太长了就不全部截取了。
在XmlBeanDefinitionReader类
的loadBeanDefinitions
方法调用doLoadBeanDefinitions
方法
其中做了两件事:
Document doc = doLoadDocument(inputSource, resource);
通过JAXP
解析xml
文件,将其转换成Document
对象,return registerBeanDefinitions(doc, resource);
便是将解析的xml
转化成BeanDefinition
对象保存。
令人所迷惑的xml
到对象的转变就是发生在这里,不过值得注意的是,这里的转换只是生成了对象的描述BeanDefinition,也就说该怎么创建它,实际的生成在后面。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
}
....
👉回到refresh()
方法,前面经过了obtainFreshBeanFactory()
方法,获取了工厂实例,里面已经有了spring要为我们创建bean的id以及描述BeanDefinition。
真正创建xml bean的方法是 finishBeanFactoryInitialization(beanFactory);
,实际调用了DefaultListableBeanFactory
的 preInstantiateSingletons();
,
前面obtainFreshBeanFactory()
解析后的BeanDefinition存放在这里
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
...
beanFactory.preInstantiateSingletons();
}
在DefaultListableBeanFactory
的preInstantiateSingletons()
方法调用了AbstractBeanFactory类
的getBean(beanName);
public void preInstantiateSingletons() throws BeansException {
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
...
if (isEagerInit) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
...
直接调了AbstractBeanFactory
中doGetBean()
方法,调用DefaultSingletonBeanRegistry
中的getSingleton()
.
不过会先调用AbstractAutowireCapableBeanFactory
的createBean(beanName, mbd, args);
方法,在方法中进行了实例化 Instantiation、属性赋值 Populate、初始化 Initialization。
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
在DefaultSingletonBeanRegistry
调用addSingleton(beanName, singletonObject);
这里便是bean实例保存的最后一步了,bean将会被保存在 singletonObjects
的ConcurrentHashMap
中。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
到此,bean从xml描述到实例化就结束了,当我们使用IAnimal cat = (IAnimal) context.getBean("cat");
会通过AbstractBeanFactory
到达DefaultSingletonBeanRegistry
获取之前存在singletonObjects
中的实例。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
...
虽然极力想描述清楚,但是里面涉及的细节太多,简单的说可以是如下流程:obtainFreshBeanFactory()
解析xml,finishBeanFactoryInitialization(beanFactory);
完成注入。
全文是依据打断点截取关键部分阐述,省略许多if判断描述。
以上内容虽然没有多少养分,但是,从中能了解到Spring的一些思想:
IoC:控制翻转,控制权从应用程序转意到框架,Spring帮我们处理这些资源(解析xml,创建实例等)
DI:依赖注入
其特点:
不需要手动去new,有IoC容器帮我们创建,被动实例化。
不需要主动装配对象直接的依赖关系,而是描述需要什么,IoC容器会帮你装配。
最少知识原则,不依赖具体实现,只知道需要提供某类服务的对象,松散耦合,一个对象应当对其他对象尽可能少的了解。
关于bean的生命周期
这一块内容错综复杂,穿插在上文的整个启动流程中,简单说来就是获取BeanDefinition
,然后进行
实例化 Instantiation
属性赋值 Populate
初始化 Initialization
销毁 Destruction
其中对应到上面的具体代码是在AbstractAutowireCapableBeanFactory类
的doCreateBean
方法中
createBeanInstance() -> 实例化
populateBean() -> 属性赋值
initializeBean() -> 初始化
具体代码位置如下,怎么来到这里还得回看refresh()
中的finishBeanFactoryInitialization()
方法中,忘记了点这里👉[一键传送]
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);//这里,实例化
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);//这里,属性填充
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);//这里,初始化
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
至于销毁,是在容器关闭时调用的,详见ConfigurableApplicationContext#close()
此外,这其中还穿插了BeanPostProcessor
以及子类InstantiationAwareBeanPostProcessor
等类的如postProcessBeforeInstantiation
、postProcessAfterInstantiation
各种后处理器拓展点切入。这里面涉及就比较细节了,详细的话有4个后处理器,可以参考一下博客:
关于Aware,Aware类型的接口的作用就是让我们能够拿到Spring容器中的一些资源。
在前面AbstractAutowireCapableBeanFactory
中doCreateBean
方法中进行实例化,属性赋值,初始化,在初始化方法initializeBean
中调用了invokeAwareMethods(beanName, bean);
判断当前创建的Bean是否实现了相关的Aware方法,如果实现了会调用回调方法将资源传递给Bean。
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
关于依赖注入:
A 创建过程中需要 B,于是 A 将自己放到(addSingletonFactory()方法
)三级缓(DefaultSingletonBeanRegistry类
)里面 ,去实例化 B
B 实例化的时候发现需要 A,于是 B 先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了!
然后把三级缓存里面的这个 A 放到二级缓存里面,并删除三级缓存里面的 A
B 顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态)
然后回来接着创建 A,此时 B 已经创建结束,直接从一级缓存里面拿到 B ,然后完成创建,并将自己放到一级缓存里面。
1.Spring 如何解决循环依赖的问题?
2.spring是如何解决循环依赖的?
3.明明一级缓存就够用,为什么要使用多级缓存?