对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过程
代码编写
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方法的内容。