Spring源码分析:IOC依赖注入

Spring源码分析:IOC

  • IOC容器的原理
    • 读取资源文件注册Bean过程
    • 代码编写
      • xml方式
      • 注解方式
        • 实现一个自己的BeanDefinition注册器
        • 添加@Import注解
        • 实现BeanDefinitionRegistryPostProcessor
  • IOC容器的作用
    • 初始化一个Bean工厂
    • 注册Bean到beanDefinitionMap
    • 实例化Bean
      • 注册到单例对象池
      • 选择实例化构造函数
      • 判断是否是FactoryBean

IOC容器的原理

读取资源文件注册Bean过程

加载
读取
注册器
注册
单例对象池
加载
单例对象池
Resource文件
ResourceLoader
BeanDefinitionReader
BeanDefinitionRegistry
Map key是beanName,value是BeanDefinition
Map key是beanName,value是Object
ComponentScan注解,Import注解,ImportSource注解
BeanDefinitionRegistryPostProcessor

代码编写

xml方式

//读取资源文件
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("spring.xml");

//BeanDefinitionRegistry simpleBeanDefinitionRegistry = new SimpleBeanDefinitionRegistry();
//BeanDefinition注册器
BeanDefinitionRegistry simpleBeanDefinitionRegistry = new DefaultListableBeanFactory();
//BeanDefinition读取器
BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(simpleBeanDefinitionRegistry);
//BeanDefinition读取器从资源文件读取BeanDefinition
beanDefinitionReader.loadBeanDefinitions(resource);

//注册BeanDefinition
BeanDefinition rootBeanDefinition = new RootBeanDefinition(IOCConfig.class);
simpleBeanDefinitionRegistry.registerBeanDefinition("test", rootBeanDefinition);

System.out.println(Arrays.toString(simpleBeanDefinitionRegistry.getBeanDefinitionNames()));
System.out.println(((DefaultListableBeanFactory) simpleBeanDefinitionRegistry).getBean("test"));

注解方式

实现一个自己的BeanDefinition注册器

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        BeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class);
        registry.registerBeanDefinition("user", rootBeanDefinition);
    }
}

添加@Import注解

@ComponentScan("gdut.ff.ioc")
@Import(MyImportBeanDefinitionRegistrar.class)
public class TestIoC {
    public static void main(String[] args) {
        //注解方式
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestIoC.class);
        System.out.println(context.getBean(IOCConfig.class));
        System.out.println(context.getBean("user"));
    }
}

实现BeanDefinitionRegistryPostProcessor

注册一个BeanDefinition,并修改BeanDefinition的class类型。

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        BeanDefinition rootBeanDefinition = new RootBeanDefinition(IOCConfig.class);
        registry.registerBeanDefinition("test", rootBeanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("test");
        beanDefinition.setBeanClassName("gdut.ff.ioc.User");
    }
}

IOC容器的作用

初始化一个Bean工厂

AnnotationConfigApplicationContext调用了它自己的无参构造函数,AnnotationConfigApplicationContext继承了GenericApplicationContext类,GenericApplicationContext的无参构造函数是实例化一个DefaultListableBeanFactory对象。DefaultListableBeanFactory就是一个Bean工厂。
Spring源码分析:IOC依赖注入_第1张图片Spring源码分析:IOC依赖注入_第2张图片
Spring源码分析:IOC依赖注入_第3张图片
DefaultListableBeanFactory有以下重要的属性:

//key是bean的名称,value是BeanDefinition对象
private final Map beanDefinitionMap = new ConcurrentHashMap(256);

//以注册的顺序,存放BeanDefinition的名称
private volatile List beanDefinitionNames = new ArrayList(256);

再来看看BeanDefinition接口:
BeanDefinition是用来装配Bean的属性的。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
	void setLazyInit(boolean lazyInit);
	boolean isLazyInit();
	......
}

注册Bean到beanDefinitionMap

//注解方式
 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestIoC.class);
BeanFactory defaultListableBeanFactory = context.getDefaultListableBeanFactory();
BeanDefinition rootBeanDefinition = new RootBeanDefinition(IOCConfig.class);
 ((DefaultListableBeanFactory) defaultListableBeanFactory).registerBeanDefinition("config", rootBeanDefinition);
System.out.println(context.getBean("config"));

实例化Bean

//实例化非懒加载单例Bean
finishBeanFactoryInitialization(beanFactory);

创建bean之前,会先去单例对象池(singletonObjects)中获取

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //先从单例缓存中找
	Object singletonObject = this.singletonObjects.get(beanName);
	//没有找到先判断是否是正在创建的bean
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
		    //earlySingletonObjects保存所有提前曝光(还没有进行属性注入)的实例,
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
			   //如果允许早期依赖,可以尝试从singletonFactories中找到对应的单例工厂
				ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
					singletonObject = singletonFactory.getObject();
					this.earlySingletonObjects.put(beanName, singletonObject);
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

注册到单例对象池

//注册到singletonMap
 ((DefaultListableBeanFactory) defaultListableBeanFactory).registerSingleton("config", new IOCConfig());

进入DefaultListableBeanFactory的registerSingleton方法
Spring源码分析:IOC依赖注入_第4张图片
再进入DefaultSingtonBeanRegistry的registerSingleton方法
Spring源码分析:IOC依赖注入_第5张图片
进入DefaultSingtonBeanRegistry的addSingleton方法,将注册的单例添加到单例对象池中
Spring源码分析:IOC依赖注入_第6张图片

选择实例化构造函数

调用BeanUtils的instantiateClass方法进行反射实例化。
Spring源码分析:IOC依赖注入_第7张图片

判断是否是FactoryBean

@Component
public class MyFactoryBean implements FactoryBean {
    @Override
    public User getObject() throws Exception {
        return new User();
    }

    @Override
    public Class getObjectType() {
        return User.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}
System.out.println(context.getBean("myFactoryBean"));//返回结果是:gdut.ff.ioc.User@c8e4bb0
System.out.println(context.getBean("&myFactoryBean"));//返回结果是:gdut.ff.ioc.MyFactoryBean@6279cee3

为什么FactoryBean的名称前面加个&,返回的就是FactoryBean实例,不加&,返回的就是FactoryBean的Object实例呢?

调用AbstractBeanFactory的getObjectForBeanInstance判断一个Bean是否是FactoryBean。
Spring源码分析:IOC依赖注入_第8张图片
在getObjectForBeanInstance方法中,如果name是以&开头的就直接返回FactoryBean实例。
Spring源码分析:IOC依赖注入_第9张图片
Spring源码分析:IOC依赖注入_第10张图片

String FACTORY_BEAN_PREFIX = "&";

如果不是"&"开头的,调用FactoryBeanRegistrySupport 的doGetObjectFromFactoryBean方法,最后的返回值是FactoryBean的getObject方法的内容。
Spring源码分析:IOC依赖注入_第11张图片

你可能感兴趣的:(Spring)