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,即控制反转
实现方式:
- 将需要创建的对象配置在spring配置文件中的 < bean >标签内
- 通过读取配置文件,拿到ApplicationContext(可以理解为整个应用,恶心的被翻译成上下文环境)
- 调用getBean() 方法获取到ioc中的bean
配置文件:
属性名 | 含义 |
---|---|
id | 对象在ioc中标识符 |
class | 该对象对应的实现类 |
scope | bean 的作用域,默认是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
以下为源码探索部分,不太确定是否合理,暂时每太理清逻辑,暂时先忽略
- 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)));
}
- 如果是单例bean,就从缓存取 // 单例bean 从缓存取
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
} - 如果没有,就创建 //createBeanInstance(beanName, mbd, args)
- spring 底层使用了ConcurrentHashMap,ThreadLocal,这是为了线程安全着想