趁着金九跳槽季,跳槽成功了。从之前的老东家跳入很老的大厂,也算完成了自己的大场梦。按照自己迂腐思想,两三年内应该不会跳槽了。所以希望静下心来搞搞基础,而不再是各种面试突击了。面试突击虽好,但总感觉根基不稳,有些问题面试不问,但在心中却存在疑问。存在未知,便有恐惧,所以想建立专栏,每天花一局王者的时间,夯实基础。当知识串起来之日,面试还会难吗,工资还能不涨吗。
今日疑问点:Spring是容器,到底容的是什么。容器又在哪。
刚工作之初读过Spring源码,因能力有限根本没有理解多少,仅一些皮毛。不懂底层原理,不懂设计模式,只看源码的Java书写,但确实也学到了很多很多东西。Spring的魅力可见一斑。这个专题是自己边学习边总结, 希望和大家一起进步,错误或者不足之处,还望指出。
文章尽量简单,不涉及很细节的源码解析,只想把Spring的世界观建立起来,Spring源码很多,没有思路的看源码,效果也不会很好,先把主体框架弄明白,再抠细节。
废话不多说,进入今日主题。
1 Spring是容器,用来管理bean的容器,那么容得肯定是bean。bean简单说和对象非常类似。那么可以理解为spring就是帮我们管理对象,让我们使用的时候,可以直接获取对象,而不需要去new 一个了,就会省去我们自己new 对象的对属性的set的麻烦操作。(这只是最直观的好处。)。bean从我们使用者角度来看可以分为两种: 一 Spring启动后已经生成的可以直接用的,二 启动的时候不生成,用的时候才去生成的(专业术语叫做懒加载)。
Spring作为一个框架,有万千代码类,这些代码有的是辅助功能,有的是工具功能,那么容器的类在哪?就是BeanFactory类,其内部定义了作为容器需要提供的功能方法。
工作中常用的是DefaultListableBeanFactory
查看类图(IDEA右键类名-->Diagrams -->show Diagram )
可以看到该类是继承了 DefaultSingletonBeanRegistry
下面进行说明。
- DefaultSingletonBeanRegistry:存放具体的bean
- singletonObjects: 存放bean的名称及实例
- singletonFactories: 存放bean的名称及实例创建工厂
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/**
* Internal marker for a null singleton object:
* used as marker value for concurrent Maps (which don't support null values).
*/
protected static final Object NULL_OBJECT = new Object();
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
/** Cache of singleton objects: bean name --> bean instance */
// 生成的bean的名称和实例,Spring中会依靠这个beaName进行查找bean
private final Map<String, Object> 'singletonObjects' = new ConcurrentHashMap<String, Object>(64);
/** Cache of singleton factories: bean name --> ObjectFactory */
// bean名称和产生的工厂
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance */
//省略本次不涉及得到的代码。.......
}
可以看到代码中的singletonObjects就是存放单例bean的容器,就是一个ConcurrentHashMap。暂且不管Spring是怎么把XML配置bean配置文件还是@bean相关的注解怎么转换成bean的。反正最终生成的单例bean是被存放到这个map中了,之后的获取也不管多复杂,多少场景,最后也肯定会是从map中获取bean。
接下来在看DefaultListableBeanFactory:
在生成bean之前,Spring会先将我们定义的bean的信息保存起来,有些bean可能会暂时用不到就设置成懒加载的,先把定义存起来,用的时候直接生成比较快。而且bean的生成流程(各种大牛和面试官称其为bean的生命周期)非常复杂,先保存bean的信息,便于后期进行各种处理,比如 依赖注入,循环依赖等等过程。也就是我们写的@component ,@bean等注解的类,首先会被定义成Spring中的bean类的抽象 也就是BeanDefinition
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.beans.factory.config;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.AttributeAccessor;
import org.springframework.lang.Nullable;
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
void setParentName(@Nullable String var1);
@Nullable
String getParentName();
void setBeanClassName(@Nullable String var1);
@Nullable
String getBeanClassName();
void setScope(@Nullable String var1);
@Nullable
String getScope();
void setLazyInit(boolean var1);
boolean isLazyInit();
void setDependsOn(@Nullable String... var1);
@Nullable
String[] getDependsOn();
void setAutowireCandidate(boolean var1);
boolean isAutowireCandidate();
void setPrimary(boolean var1);
boolean isPrimary();
void setFactoryBeanName(@Nullable String var1);
@Nullable
String getFactoryBeanName();
void setFactoryMethodName(@Nullable String var1);
@Nullable
String getFactoryMethodName();
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !this.getConstructorArgumentValues().isEmpty();
}
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !this.getPropertyValues().isEmpty();
}
void setInitMethodName(@Nullable String var1);
@Nullable
String getInitMethodName();
void setDestroyMethodName(@Nullable String var1);
@Nullable
String getDestroyMethodName();
void setRole(int var1);
int getRole();
void setDescription(@Nullable String var1);
@Nullable
String getDescription();
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
@Nullable
String getResourceDescription();
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
BeanDefinition是对Spring中bean的定义的抽象,假设我们不看上述代码自己考虑我们自己定义bean的定义信息,大体都需要什么信息,
1 bean的class信息:生成一个对象的必须信息
2 bean的作用域信息:在开发中有的对象用完就不想要了,下次会新建新的,有的是一个对象一直用。有的对象是一个请求一个。满足这个功能的话 ,作用域信息也是必不可少的。
3 bean是否懒加载信息:
4 bean的初始化问题:有的对象是直接构造函数new的,有的却是工厂方法生成的,如果是工厂方法生成的话,这个时候是不是就需要把生成对象的方法保存起来呢,告诉Spring生成方法。
当然这只是我能想到的,Spring能想到的肯定更多,适应更多的场景。
总而言之,Spring会将需要生成bean的类进行扫描,然后生成这个bean定义信息,保存起来。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.beans.factory.support;
//省略import信息
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Nullable
private static Class<?> javaxInjectProviderClass;
private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories;
@Nullable
private String serializationId;
private boolean allowBeanDefinitionOverriding = true;
private boolean allowEagerClassLoading = true;
@Nullable
private Comparator<Object> dependencyComparator;
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap(16);
//这个map就是用来存储bean定义的map。
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap(64);
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap(64);
private volatile List<String> beanDefinitionNames = new ArrayList(256);
private volatile Set<String> manualSingletonNames = new LinkedHashSet(16);
@Nullable
private volatile String[] frozenBeanDefinitionNames;
private volatile boolean configurationFrozen = false;
//省略方法。
}
可以看到类中的beanDefinitionMap就是用来存储bean的定义信息的map。
总结: 两个ConcurrentHashMap构成了Spring的容器。(简单才能记住)