Spring是bean的容器,那么到底bean是什么,容器又在哪里。(bean存在spring的哪里)

      趁着金九跳槽季,跳槽成功了。从之前的老东家跳入很老的大厂,也算完成了自己的大场梦。按照自己迂腐思想,两三年内应该不会跳槽了。所以希望静下心来搞搞基础,而不再是各种面试突击了。面试突击虽好,但总感觉根基不稳,有些问题面试不问,但在心中却存在疑问。存在未知,便有恐惧,所以想建立专栏,每天花一局王者的时间,夯实基础。当知识串起来之日,面试还会难吗,工资还能不涨吗。

今日疑问点: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的容器。(简单才能记住)

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值