Spring源码分析:IOC依赖注入

对IOC的理解

IoC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。

IOC容器是用来管理对象依赖关系的,对IOC容器来说,BeanDefinition就是对依赖反转模式中管理的对象依赖关系的数据抽象,也是容器实现依赖反转功能的核心数据结构,依赖反转功能是围绕BeanDefinition完成的。

IOC容器

BeanFactory

BeanFactory提供最基本的IOC容器的功能:

//判断容器是否含有指定名字的Bean。
boolean containsBean(String name); 

//查询指定名字的Bean是否是Singleton类型的Bean,对应Singleton属性,可以
在BeanDefinition指定。
boolean isSingleton(String name) throws NoSuchBeanDefinitionException; 

//查询指定名字的Bean是否是prototype类型的Bean,对应prototype属性,可以在BeanDefinition指定。
boolean isPrototype(String name) throws NoSuchBeanDefinitionException; 

//查询指定名字的Bean的Class类型是否是特定的Class类型。
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException; 

//查询指定名字的Bean的Class类型。
Class<?> getType(String name) throws NoSuchBeanDefinitionException;

//查询指定名字的Bean的所有别名。
String[] getAliases(String name);

XmlBeanFactory

public class XmlBeanFactory extends DefaultListableBeanFactory {

	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

    public XmlBeanFactory(Resource resource) throws BeansException {
		this(resource, null);
	}

    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);
	}
}

XmlBeanFactory在继承了DefaultListableBeanFactory容器功能时,提供读取以XML文件方式定义的BeanDefinition的功能。XmlBeanFactory定义了一个XmlBeanDefinitionReader读取xml资源文件

ApplicationContext

继承MessageSource接口,支持不同的信息源;
继承ResourceLoader接口,可以从不同地方得到Bean定义资源;
继承ApplicationEventPublisher,可以在上下文中引入事件机制;

FileSystemXmlApplicationContext

FileSystemXmlApplicationContext的主要功能在基类AbstractXmlApplicationContext实现,如果直接使用FileSystemXmlApplicationContext,需要实例化ApplicationContext,启动IOC容器的refresh过程。

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
	super(parent);
	setConfigLocations(configLocations);
	if (refresh) {
		refresh();
	}
}

从文件系统读取资源文件

protected Resource getResourceByPath(String path) {
	if (path != null && path.startsWith("/")) {
		path = path.substring(1);
	}
	return new FileSystemResource(path);
}

AnnotationConfigApplicationContext

创建一个AnnotationConfigApplicationContext实例,从给定的带注解的类派生bean定义,并自动刷新上下文。

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
	this();
	register(annotatedClasses);
	refresh();
}

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工厂。
在这里插入图片描述

调用父类构造函数

在这里插入图片描述DefaultListableBeanFactory有以下重要的属性:一个是存放Bean定义的集合,一个是存放bean定义名称的集合。

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

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

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

如果lazt-init(延迟加载)的值为true,依赖注入发生在容器初始化结束之后,第一次向容器发出getBean时;优点是解约内存,启动快(不需要提前初始化Bean). 缺点是运行的时候比较慢(用的时候先要初始化才能用).

如果lazy-init(延迟加载)的值是false,依赖注入发生在容器初始化的过程中,会对beanDefinitionMap中所有的Bean进行依赖注入,这样在初始化过程结束以后,容器执行getBean得到的就是已经准备好的Bean,不需要进行依赖注入。优点是运行的时候比较快(提前初始化了,直接用). 缺点是启动慢和占用内存,因为要初始化很多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();
	......
}

可以通过以下方式修改lazy-init的值:

XML 配置:<bean lazy-init=”true” … />
Java 注解:@Lazy 默认值是true

调用本类无参构造函数

无参构造函数初始化了一个AnnotatedBeanDefinitionReader,读取注解形式的Bean定义。
在这里插入图片描述
AnnotationConfigApplicationContext实现了AnnotationConfigRegistry接口。AnnotationConfigRegistry接口有两个方法:一个是注册Bean定义;另一个是扫描包;

void register(Class<?>... annotatedClasses);
void scan(String... basePackages);

在这里插入图片描述
AnnotationConfigUtis.registerAnnotationConfigProcessors是用来注册所有的注解后处理器。BeanPostProcessor是一个接口类,有两个接口方法:
一个是postProcessBeforeInitialization 在Bean的初始化前提供回调入口;
一个是postProcessAfterInitialization 在Bean的初始化后提供回调入口;
在这里插入图片描述

注册Bean定义

循环遍历注册带有注解的Class,
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
先实例化一个AnnotatedGenericBeanDefinition对象,获取bean的名称,BeanDefinitionHolder是BeanDefinition对象的封装类,封装了BeanDefinition,Bean的名字和别名。用它来完成向IOC容器注册。

public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
	AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
	if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
		return;
	}

	ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
	abd.setScope(scopeMetadata.getScopeName());
	String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
	AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
	if (qualifiers != null) {
		for (Class<? extends Annotation> qualifier : qualifiers) {
			if (Primary.class == qualifier) {
				abd.setPrimary(true);
			}
			else if (Lazy.class == qualifier) {
				abd.setLazyInit(true);
			}
			else {
				abd.addQualifier(new AutowireCandidateQualifier(qualifier));
			}
		}
	}

	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

BeanDefinitionReaderUtils的registerBeanDefinition方法,会注册Bean定义,同时注册别名。
在这里插入图片描述

注册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);

DefaultSingletonBeanRegistry的getSingleton方法,先从单例对象池中根据bean的名称获取对象,如果获取的对象为空,且对象正在创建,对单例对象池进行同步加锁,从提前曝光的单例对象池中根据bean的名称获取对象,如果对象还是为空,就到单例工厂根据bean的名称,获取对象工厂,如果对象工厂不为空,就获取对象工厂返回的对象,将该bean加入到提前曝光的单例对象池,从单例工厂中移出该bean。最后判断获得的单例对象是否为空,如果为空,返回Null,否则,返回单例对象。

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方法,然后调用DefaultSingtonBeanRegistry的registerSingleton方法。如果Bean开始创建,对beanDefinitionMap进行同步加锁,如果beanDefinitionMap的不存在指定的Bean,将该Bean添加到已经更新的单例对象池中。
在这里插入图片描述
再进入DefaultSingtonBeanRegistry的registerSingleton方法
在这里插入图片描述
进入DefaultSingtonBeanRegistry的addSingleton方法,将注册的单例添加到单例对象池中,把单例从单例工厂和提前曝光的单例对象池中移出,已经注册的单例集合中添加该单例。
在这里插入图片描述

选择实例化构造函数

调用BeanUtils的instantiateClass方法进行反射实例化。
在这里插入图片描述

判断是否是FactoryBean

@Component
public class MyFactoryBean implements FactoryBean<User> {
    @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。
在这里插入图片描述
在getObjectForBeanInstance方法中,如果name是以&开头的就直接返回FactoryBean实例。
在这里插入图片描述
在这里插入图片描述

String FACTORY_BEAN_PREFIX = "&";

如果不是"&"开头的,调用FactoryBeanRegistrySupport 的doGetObjectFromFactoryBean方法,最后的返回值是FactoryBean的getObject方法的内容。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/u012734723/article/details/107574806