ioc到底做了些什么

IOC 是inversion of control
控制反转,但是反转了什么?
一般来说:我们创建对象是这样的;

Object obj=new Object();

但是逐渐感觉,这样的劳动重复性太高,能否减少这些无意义的重复劳动 。
ioc就是做这件事的。
来用测试代码体验一下:
大致逻辑:
现在有接口BookService.java,和实现了接口的BookServiceImpl.java
接口 BookService:

package top.forethought.framework.ioc;

public interface BookService {
    void addBook();
}

实现类:

package top.forethought.framework.ioc;

public class BookServiceImpl implements BookService {
    @Override
    public void addBook() {
        System.out.println(" addBook @ BookServiceImpl");
    }
    public BookServiceImpl(){
        System.out.println("constructor BookServiceImpl");
    }
}

不使用IOC

测试类:

@Test
    public void noneIoc(){
        BookService bookService=new BookServiceImpl();
        bookService.addBook();
    }

输出:
在这里插入图片描述

使用ioc:

思路:将创建对象的控制权交给spring,即控制反转
实现方式:

  1. 将需要创建的对象配置在spring配置文件中的 < bean >标签内
  2. 通过读取配置文件,拿到ApplicationContext(可以理解为整个应用,恶心的被翻译成上下文环境)
  3. 调用getBean() 方法获取到ioc中的bean

配置文件:

属性名含义
id对象在ioc中标识符
class该对象对应的实现类
scopebean 的作用域,默认是singleton,还有一种是 prototype,每次getBean 都是得到新的对象
property这是给bean中的 成员属性注入值时使用(基本的值,可以使用 ),如果需要引用其他bean,需要使用 < property name=“xx” ref=“otherBeanId”>(注意:对应属性需要在实现类中需要由setter方法)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation=
               "http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context.xsd
     http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="bookServiceId" class="top.forethought.framework.ioc.BookServiceImpl" ></bean>
</beans>

测试类;

 @Test
    public void byIoc(){
        String xmlPath="top/forethought/framework/configs/ioc-config.xml";
        ApplicationContext context= new ClassPathXmlApplicationContext(xmlPath);
         BookService bookService= (BookService) context.getBean("bookServiceId");
        bookService.addBook();
        for(int i=0;i<10;i++){
            bookService= (BookService) context.getBean("bookServiceId");
            System.out.println(bookService.hashCode());
        }
    }

scope=“singleton” 时输出:每次获取都是同一个bean
在这里插入图片描述
scope=“prototype” 时输出:每次获取,都是得到一个新的bean
在这里插入图片描述

ioc 底层是如何实现的?

暂时猜测是通过工厂模式创建对象:
追踪源码看看,全部是beanFactory 结尾的,仅仅是从名字就可以看出用到的设计模式 Factory+反射

BeanFactory:BeanFactory,以Factory结尾,表示它是一个工厂类(接口),用于管理Bean的一个工厂(产物是任意bean)。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖)
FactoryBean: 以Bean结尾,表示它是一个特殊的Bean,它是实现了FactoryBean接口的Bean,具有工厂生产对象的能力,只能生产特定的对象,(T 类型的对象),比如ThreadPoolExecutorFactoryBean 是返回 ExecutorService 类型的对象

 ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport
		implements FactoryBean<ExecutorService>, InitializingBean, DisposableBean

在这里插入图片描述


以下为源码探索部分,不太确定是否合理,暂时每太理清逻辑,暂时先忽略


  1. AbstractBeanFactory.class:
    getBean(String name) 方法:返回一个共享的(单例模式)或者是独立的对象(原型模式)
    在这里插入图片描述
    getBean 调用了doGetBean 方法

doGetBean 代码逻辑:

protected <T> T doGetBean(
			final String name, final Class<T> requiredType, 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.isDebugEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.debug("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.
			// 检查当前工厂是否有这个bean 的定义,如果没有,从父工厂查找
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
				if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}

			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);
                //确保被依赖项先初始化
				// Guarantee initialization of beans that the current bean depends on.
			  //  dependOn 是 bean 的依赖项
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
					// 如果beanName 是dep的依赖项 ,这说明出现循环依赖,抛出异常
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// 将 beanName 依赖的dep 注册
						//Register a dependent bean for the given bean
						registerDependentBean(dep, beanName);
						getBean(dep);//这相当于执行了dep 类型的对象的创建
					}
				}

//   创建当前需要创建的bean
				// Create bean instance.
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
						@Override
						public Object getObject() throws BeansException {
							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, new ObjectFactory<Object>() {
							@Override
							public Object getObject() throws BeansException {
								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 && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
			try {
				return getTypeConverter().convertIfNecessary(bean, requiredType);
			}
			catch (TypeMismatchException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}

	@Override
	public boolean containsBean(String name) {
		String beanName = transformedBeanName(name);
		if (containsSingleton(beanName) || containsBeanDefinition(beanName)) {
			return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));
		}
		// Not found -> check parent.
		BeanFactory parentBeanFactory = getParentBeanFactory();
		return (parentBeanFactory != null && parentBeanFactory.containsBean(originalBeanName(name)));
	}

  1. 如果是单例bean,就从缓存取 // 单例bean 从缓存取
    if (mbd.isSingleton()) {
    instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
    }
  2. 如果没有,就创建 //createBeanInstance(beanName, mbd, args)
  3. spring 底层使用了ConcurrentHashMap,ThreadLocal,这是为了线程安全着想

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值