千家信息网

如何理解容器Spring IOC

发表于:2025-01-31 作者:千家信息网编辑
千家信息网最后更新 2025年01月31日,本篇内容介绍了"如何理解容器Spring IOC"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!构造b
千家信息网最后更新 2025年01月31日如何理解容器Spring IOC

本篇内容介绍了"如何理解容器Spring IOC"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

构造bean工厂类

/** * Create a new XmlBeanFactory with the given resource, * which must be parsable using DOM. * @param resource the XML resource to load bean definitions from * @throws BeansException in case of loading or parsing errors */public XmlBeanFactory(Resource resource) throws BeansException {        this(resource, null);}/** * Create a new XmlBeanFactory with the given input stream, * which must be parsable using DOM. * @param resource the XML resource to load bean definitions from * @param parentBeanFactory parent bean factory * @throws BeansException in case of loading or parsing errors */public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {        super(parentBeanFactory);        this.reader.loadBeanDefinitions(resource);}

我们使用的就是第一个构造,但是第一个构造调用了第二个,第二个构造只有两步。我们继续往下看

再来看XmlBeanFactory初始化的源码

  • super(parentBeanFactory):用来初始化父类

  • this.reader.loadBeanDefinitions(resource):spring初始化资源加载的真正实现

我们先来看看"super(parentBeanFactory):用来初始化父类"这一步做了什么吧

/** * 先是调用DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory)带参构造方法 */public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {        super(parentBeanFactory);}/** * 调用父类AbstractAutowireCapableBeanFactory */public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {        this();        setParentBeanFactory(parentBeanFactory);}/** * 调用AbstractAutowireCapableBeanFactory()无参构造方法 */public AbstractAutowireCapableBeanFactory() {        super();        ignoreDependencyInterface(BeanNameAware.class);        ignoreDependencyInterface(BeanFactoryAware.class);        ignoreDependencyInterface(BeanClassLoaderAware.class);}/**  * 在初始化XmlBeanFactory容器 */public void setParentBeanFactory(@Nullable BeanFactory parentBeanFactory) {        if (this.parentBeanFactory != null && this.parentBeanFactory != parentBeanFactory) {                throw new IllegalStateException("Already associated with parent BeanFactory: " + this.parentBeanFactory);        }        this.parentBeanFactory = parentBeanFactory;}

到这里是不是比较明了的知道了这一步具体做了什么?其实看完super(parentBeanFactory)的源码发现就做了两件事:获取添加需要忽略指定接口实现类的自动装配和初始化。那我们的第二步具体做了什么呢?

this.reader.loadBeanDefinitions(resource)分析

之前我们说了我们应该是根据配置文件找到对应的类,那源码是这样吗?看看这句代码的实现就知道了。

/** * 先是调用loadBeanDefinitions(Resource resource) */public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {        return loadBeanDefinitions(new EncodedResource(resource));}/** * 这个方法正是我们之前推测的实现 * 从xml配置文件中加载bean */public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {        Assert.notNull(encodedResource, "EncodedResource must not be null");        if (logger.isTraceEnabled()) {                logger.trace("Loading XML bean definitions from " + encodedResource);        }        Set currentResources = this.resourcesCurrentlyBeingLoaded.get();        if (currentResources == null) {                currentResources = new HashSet<>(4);                this.resourcesCurrentlyBeingLoaded.set(currentResources);        }        if (!currentResources.add(encodedResource)) {                throw new BeanDefinitionStoreException(                                "Detected cyclic loading of " + encodedResource + " - check your import definitions!");        }        try {                InputStream inputStream = encodedResource.getResource().getInputStream();                try {                        InputSource inputSource = new InputSource(inputStream);                        if (encodedResource.getEncoding() != null) {                                inputSource.setEncoding(encodedResource.getEncoding());                        }                        return doLoadBeanDefinitions(inputSource, encodedResource.getResource());                }                finally {                        inputStream.close();                }        }        catch (IOException ex) {                throw new BeanDefinitionStoreException(                                "IOException parsing XML document from " + encodedResource.getResource(), ex);        }        finally {                currentResources.remove(encodedResource);                if (currentResources.isEmpty()) {                        this.resourcesCurrentlyBeingLoaded.remove();                }        }}

当我们贴完代码之后,是不是可以明显的看到我们之前推测的实际证据?

ClassPathResource和InputStream

我们从上面的源码看到,我们定义的类在xml中,源码里面有InputStream。但是传入的只有一个ClassPathResource。那他是怎么封装进入ClassPathResource的呢?

其实这里的关联比较简单。我们不妨来看看这些类的类结构图

到这里是不是就已经很明了了我们的InputStream是怎么将内容传递进入ClassPathResource

真正获取bean

获取bean才是我们这一段操作的最关键的地方,那bean又是怎么获取出来的呢?这里贴一下主代码吧

protected  T doGetBean(final String name, @Nullable final Class requiredType,                @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {        final String beanName = transformedBeanName(name);        Object bean;        // Eagerly check singleton cache for manually registered singletons.        Object sharedInstance = getSingleton(beanName);        if (sharedInstance != null && args == null) {                if (logger.isTraceEnabled()) {                        if (isSingletonCurrentlyInCreation(beanName)) {                                logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +                                                "' that is not fully initialized yet - a consequence of a circular reference");                        }                        else {                                logger.trace("Returning cached instance of singleton bean '" + beanName + "'");                        }                }                bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);        }        else {                // Fail if we're already creating this bean instance:                // We're assumably within a circular reference.                if (isPrototypeCurrentlyInCreation(beanName)) {                        throw new BeanCurrentlyInCreationException(beanName);                }                // Check if bean definition exists in this factory.                BeanFactory parentBeanFactory = getParentBeanFactory();                if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {                        // Not found -> check parent.                        String nameToLookup = originalBeanName(name);                        if (parentBeanFactory instanceof AbstractBeanFactory) {                                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(                                                nameToLookup, requiredType, args, typeCheckOnly);                        }                        else if (args != null) {                                // Delegation to parent with explicit args.                                return (T) parentBeanFactory.getBean(nameToLookup, args);                        }                        else if (requiredType != null) {                                // No args -> delegate to standard getBean method.                                return parentBeanFactory.getBean(nameToLookup, requiredType);                        }                        else {                                return (T) parentBeanFactory.getBean(nameToLookup);                        }                }                if (!typeCheckOnly) {                        markBeanAsCreated(beanName);                }                try {                        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);                        checkMergedBeanDefinition(mbd, beanName, args);                        // Guarantee initialization of beans that the current bean depends on.                        String[] dependsOn = mbd.getDependsOn();                        if (dependsOn != null) {                                for (String dep : dependsOn) {                                        if (isDependent(beanName, dep)) {                                                throw new BeanCreationException(mbd.getResourceDescription(), beanName,                                                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");                                        }                                        registerDependentBean(dep, beanName);                                        try {                                                getBean(dep);                                        }                                        catch (NoSuchBeanDefinitionException ex) {                                                throw new BeanCreationException(mbd.getResourceDescription(), beanName,                                                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);                                        }                                }                        }                        // Create bean instance.                        if (mbd.isSingleton()) {                                sharedInstance = getSingleton(beanName, () -> {                                        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;                                        }                                });                                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);                        }                        else if (mbd.isPrototype()) {                                // It's a prototype -> create a new instance.                                Object prototypeInstance = null;                                try {                                        beforePrototypeCreation(beanName);                                        prototypeInstance = createBean(beanName, mbd, args);                                }                                finally {                                        afterPrototypeCreation(beanName);                                }                                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);                        }                        else {                                String scopeName = mbd.getScope();                                final Scope scope = this.scopes.get(scopeName);                                if (scope == null) {                                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");                                }                                try {                                        Object scopedInstance = scope.get(beanName, () -> {                                                beforePrototypeCreation(beanName);                                                try {                                                        return createBean(beanName, mbd, args);                                                }                                                finally {                                                        afterPrototypeCreation(beanName);                                                }                                        });                                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);                                }                                catch (IllegalStateException ex) {                                        throw new BeanCreationException(beanName,                                                        "Scope '" + scopeName + "' is not active for the current thread; consider " +                                                        "defining a scoped proxy for this bean if you intend to refer to it from a singleton",                                                        ex);                                }                        }                }                catch (BeansException ex) {                        cleanupAfterBeanCreationFailure(beanName);                        throw ex;                }        }        // Check if required type matches the type of the actual bean instance.        if (requiredType != null && !requiredType.isInstance(bean)) {                try {                        T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);                        if (convertedBean == null) {                                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());                        }                        return convertedBean;                }                catch (TypeMismatchException ex) {                        if (logger.isTraceEnabled()) {                                logger.trace("Failed to convert bean '" + name + "' to required type '" +                                                ClassUtils.getQualifiedName(requiredType) + "'", ex);                        }                        throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());                }        }        return (T) bean;}

仅从代码量上就能看出来bean的加载经历了一个相当复杂的过程,其中涉及各种各样的考虑。

我们将上面的内容大致总结一下:

  • 转换对应beanName。

  • 尝试从缓存中加载单例。

  • bean的实例化。

  • 原型模式的依赖检查。

  • 检测parentBeanFactory。

  • 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition。

  • 寻找依赖。

  • 针对不同的scope进行bean的创建。

  • 类型转换。(强转)

"如何理解容器Spring IOC"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

0