控制反转是spring提供的最基础的功能. 它被视为一种与Gof所不同的设计模式.
简单的说, 当我们在一个类A 中无法做全部的事情, 需要使用另一个类B 时,需要对B有依赖的关系. 这时候我们会通过new对象的方式获取B的对象. 或者使用工厂的方式获取B对象. 这种方式都是正常的控制关系.
而控制反转 改变的就是这个对应关系. 我们通过spring的BeanFactory获取B对象, spring自动给B对象赋值. 我们在我们的类中就失去了对B的控制关系. 这个控制关系转移到了spring中. 通过注解/配置文件的方式,由springframework 来管理这一关系.
这一波操作起到的效果是解耦. 之前被调用的类变成了Spring提供的用户自定义的服务, 放在了自定义的容器里面. 变成了应用的基础服务. 调用者A不知道B什么时候被创建,什么时候被赋值. 他只需要告诉BeanFactory我需要B对象. 剩下的spring会自己处理.
----------------------------------------------------------------------
那么第一个问题来了: 为什么由spring管理依赖关系会降低应用的耦合性呢? 他降低耦合性体现在了哪里?
个人觉得, 我们在应用中存在的大量的服务都是属于不变的操作, 它们的创建,赋值都是一些基础的服务. 对于应用来说,维护他的关系是一件吃力不讨好的事情, 把他当做一个基础服务的模块之后即不需要关系他的生命周期,又可以在外部维护它的具体关系. 本身就是降低耦合性的最大特征
------------------------------------------------------------------------
那么问题又来了: spring是如何维护我们提供的这些自定义服务的呢?
一切从spring的BeanFactory接口开始.
package org.springframework.beans.factory;
import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
public interface BeanFactory {
//转义符“&”用来获取FactoryBean自己
String FACTORY_BEAN_PREFIX = "&";
//根据bean的名字进行获取bean的实例
Object getBean(String var1) throws BeansException;
<T> T getBean(String var1, Class<T> var2) throws BeansException;
<T> T getBean(Class<T> var1) throws BeansException;
Object getBean(String var1, Object... var2) throws BeansException;
<T> T getBean(Class<T> var1, Object... var2) throws BeansException;
boolean containsBean(String var1);
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
String[] getAliases(String var1);
}
它的子类实现如 XmlBeanFactory AplicationContext等实现了获取对象的基本方法.
首先是Ioc容器的初始化. 它分为三个过程: Resource定位, BeanDefinition的载入, 向Ioc容器注册BeanDefinition
资源定位: 文件系统通过FileSystemResource,类路径中的Bean通过ClassPathResource进行载入. 这是一个寻找数据的过程.
载入: 把定义好的Bean转换为IoC容器内部的数据结构. 其实就是解析Xml文件,转为Document树,然后将配置文件中静态的配置信息存放在固定的位置.
注册: 这一步中,把BeanDefinition存储到HashMap中, 这样IoC容器中就拥有了方便管理的Bean对象对应的数据结构 可以在beanDefinitionMap中被检索使用.
容器的作用就是对这些信息进行维护和处理. 这些数据是建立依赖反转关系的基础........
接着就是我们通常会用到的依赖注入.
一般的依赖注入是我们第一次向容器索要对象是进行的. 如果想改变这一过程,需要在配置中指明 lazy-init属性,让容器进行预实例化. (这个默认就是容器预实例化. 如果想要提高项目启动速度,可以将部分不需要预实例化的Bean 的对应值设置为true. )
预实例化就是在启动项目时候完成一次依赖注入.
getBean是依赖注入的起点, creatBean则是依赖注入的实现.
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
if(resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
mbdToUse.prepareMethodOverrides();
} catch (BeanDefinitionValidationException var7) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", var7);
}
Object beanInstance;
try {
beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
if(beanInstance != null) {
return beanInstance;
}
} catch (Throwable var8) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var8);
}
beanInstance = this.doCreateBean(beanName, mbdToUse, args);
if(this.logger.isDebugEnabled()) {
this.logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
创建Bean时, 会获取实例化bean需要的参数,创建bean对象并赋值。
创建Bean对象具体实现方法内, 首先判断是否存在可以实例化的Bean对象。 然后通过ClassLoader进行加载。 如果加载不到则判断有没有对应的工厂类。 通过工厂类的方法进行加载。 接着判断是否可以走构造方法创建,
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
if(beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
} else if(mbd.getFactoryMethodName() != null) {
return this.instantiateUsingFactoryMethod(beanName, mbd, args);
} else {
boolean resolved = false;
boolean autowireNecessary = false;
if(args == null) {
Object var7 = mbd.constructorArgumentLock;
synchronized(mbd.constructorArgumentLock) {
if(mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if(resolved) {
return autowireNecessary?this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null):this.instantiateBean(beanName, mbd);
} else {
Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);
return ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args)?this.instantiateBean(beanName, mbd):this.autowireConstructor(beanName, mbd, ctors, args);
}
}
}
instantiateBean 方法在最后判断是否执行。
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
if(System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return AbstractAutowireCapableBeanFactory.this.getInstantiationStrategy().instantiate(mbd, beanName, AbstractAutowireCapableBeanFactory.this);
}
}, this.getAccessControlContext());
} else {
beanInstance = this.getInstantiationStrategy().instantiate(mbd, beanName, this);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
this.initBeanWrapper(bw);
return bw;
} catch (Throwable var6) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", var6);
}
}
System.getSecurityManager 安全管理器是一个单独的对象,在java虚拟机中,它在访问控制-对于外部资源的访问控制-起到中枢作用 使用native方法doPrivileged 进行授权操作。 否则直接通过java构造器 反射进行实例化并赋值。
在spring3.x中使用了BeanUtils和CGLIB动态字节码方式创建实例。 由于对于 feild method constructer 的invoke方法被优化很多次,CGLIB被完爆。 在加之spring4.x仅能运行在默认增强反射的jdk1.7中, 在spring4.3.9中我们仅仅能看到使用 BeanUtils携带的 构造器反射一种实现方式。
看源码全靠猜。。 鬼知道对不对!