一.知识了解
1.Beanfactory和Application,BeanFactory和FactoryBean
内容在Spring基本知识点(一)后半部分可见;
2.BeanDefinition
BeanDefinition是IOC容器体系非常重要的核心数据结构,Spring通过BeanDefinition来管理基于Spring的应用中的各种对象以及他们之间的相互依赖关系,实际就是POJO对象在IOC容器中的抽象。在DefaultListableBeanFactory中使用数据结构ConcurrentHashMap装载,示例如下
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable{ private final Map beanDefinitionMap; public DefaultListableBeanFactory() { //删除了其他代码 beanDefinitionMap = new ConcurrentHashMap();//通过Map持有载入的BeanDefition } }
3.编程式使用IOC容器
方便理解IOC关键类的相互关系,修改上一篇的测试类代码
package RealUse; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.core.io.ClassPathResource; public class Test { public static void main(String[] args) { //ApplicationContext ctx = new FileSystemXmlApplicationContext("bin/applicationContext.xml"); ClassPathResource res = new ClassPathResource("applicationContext.xml");//1.创建IOC配置文件的抽象资源,包含了BeanDefinition的定义信息。资源定位。用的两个不同类路径:ClassPathResource;文件系统:FileSystemResource DefaultListableBeanFactory factory = new DefaultListableBeanFactory();//2.创建一个BeanFactory的容器 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);//3.创建一个载入BeanDefinition的读取器,载入XML形式的BeanDefinition reader.loadBeanDefinitions(res); System.out.println("1.===返回getObject==="+factory.getBean("sample").getClass()+"====="); System.out.println("2.===返回本身==="+factory.getBean("&sample").getClass()+"======"); } }
4.总体步骤
IOC容器初始化(Resource定位、BeanDefinition的载入、IOC容器注册BeanDefinition)--->IOC容器的依赖注入
二.IOC容器的初始化
IOC容器的初始化由AbstractApplicationContext的refresh()启动,若已经有了容器存在那么需要把已有的容器销毁和关闭,保证refresh后使用的是新建立的IOC容器。看下具体代码:
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 准备上下文用于刷新 prepareRefresh(); // 创建BeanFactory,Bean定义的解析与注册 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 为该上下文配置已经生成的BeanFactory prepareBeanFactory(beanFactory); try { // 1.设置BeanFactory的后置处理,加工的是BeanDefinition postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); // 2.注册bean的后处理器。 //!!!区别:工厂后处理器在获取后立即调用,而Bean后处理器在获取后注册到上下文持有的beanfactory中,供以后操作调用 registerBeanPostProcessors(beanFactory); // 3.初始化信息源 initMessageSource(); // 4.初始化事件机制 initApplicationEventMulticaster(); // 5.初始其它特殊Bean onRefresh(); //6.注册事件监听器;(观察者模式中的观察者角色)获取ApplicationListener类型的所有bean,即事件监听器 registerListeners(); // 7.Bean的真正实例化,初始化lazy-init!=true的singleton的Bean finishBeanFactoryInitialization(beanFactory); //发布容器事件,结束Refresh过程 finishRefresh(); } catch (BeansException ex) { destroyBeans(); cancelRefresh(ex); throw ex; } } }
总而言之:创建一个Application上下文持有的一个BeanFactory对象,当这个Beanfactory对象创建完成后,Spring将配置文件的信息解析成为一个个的BeanDefinition对象并装入到容器的Bean定义注册(BeanDefinitionRegistry)中。
1.Resource定位
指的是BeanDefinition的资源定位,由ResourceLoader接口通过统一的Resource接口实现。
ResourceLoader接口:通过该类的实例可以获得一个Resource实例,仅仅包含一个方法 Resource getResource(String location)用于返回一个Resource实例。
package org.springframework.core.io; // Referenced classes of package org.springframework.core.io: // Resource public interface ResourceLoader { public abstract Resource getResource(String s); public abstract ClassLoader getClassLoader(); public static final String CLASSPATH_URL_PREFIX = "classpath:"; }
Resource接口是Spring资源访问的接口,Resource接口有大量的实现类。例如:
- URLResource:访问网络资源
- ClassPathResource:访问类加载路径里资源
- FileSystemResource:访问文件系统里资源的实现类
当Spring应用需要进行资源访问的时候,并不是直接使用以上Resource的实现类,而是调用ResourceLoader实例的getResource方法来获得资源。ResourceLoader将会负责选择Resource的实现类,也就是确定具体的资源访问策略,从而将应用程序和具体的资源访问策略分离开来。Spring会采用与ApplicationContext相同的策略访问资源。这就是设计模式中的策略模式(不同的策略拥有统一的接口,客户决定使用哪个策略类)
2.BeanDefinition的载入和解析
把用户定义好的Bean成IOC容器内部的数据结构,完成后IOC容器BeanDefinition中存在的还只是一些静态的配置信息。
解析是一个很复杂的过程,以XML文件对象为例,在读取器XmlBeanDefinitionReader中得到代表XML文件的Resource,然后按照Spring的Bean的定义规则解析XML的文档树。具体的解析在BeanDefinitionParserDelegate中完成,不再详述,打算自己写一个简单的XML解析代码。
3.向IOC容器注册BeanDefinition的过程,通过调用BeanDefinitionRegistry的实现来完成。
就是把解析得到的BeanDefinition设置到HashMap中。例如,DefaultListableBeanFactory实现了BeanDefinitionRegistry,该接口的实现完成了注册。
DefaultListableBeanFactory类中registerBeanDefinition如下
public void registerBeanDefinition(String beanName,BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "'beanName' must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException( beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } //加上synchronized synchronized (beanDefinitionMap) { //检查是否有同名BeanDefinition存在 Object oldBeanDefinition = beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!allowBeanDefinitionOverriding) throw new BeanDefinitionStoreException( beanDefinition.getResourceDescription(), beanName, (new StringBuilder( "Cannot register bean definition [")) .append(beanDefinition) .append("] for bean '").append(beanName) .append("': There is already [") .append(oldBeanDefinition) .append("] bound.").toString()); if (logger.isInfoEnabled()) logger.info((new StringBuilder( "Overriding bean definition for bean '")) .append(beanName).append("': replacing [") .append(oldBeanDefinition).append("] with [") .append(beanDefinition).append("]").toString()); } else { beanDefinitionNames.add(beanName); frozenBeanDefinitionNames = null; } beanDefinitionMap.put(beanName, beanDefinition);//BeanName为key值,beanDefinition是value值 resetBeanDefinition(beanName); } }
三.IOC容器的依赖注入
一般发生在getBean的时候也可以在预实例化的时候,流程图如下
1.分析下getBean--->doGetBean的代码
public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException { return doGetBean(name, requiredType, args, false); } //这里是实际取得Bean的地方,也是触发依赖注入的地方 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; // 先从缓存中获取Bean,处理那些已经被创建过的单件模式的Bean,对这种Bean的请求不需要重复创建 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 + "'"); } } //FactoryBean相关处理,用来取得FactoryBean生产结果 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. //对BeanDefinition是否存在进行检查。检查能否在当前工厂取到想要的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 { //根据Bean名字获取BeanDefinition final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. //保证这些Bean依赖的Bean全部被初始化,可能会触发递归调用,直到取到无任何依赖的Bean为止! String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dependsOnBean : dependsOn) { if (isDependent(beanName, dependsOnBean)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'"); } registerDependentBean(dependsOnBean, beanName); getBean(dependsOnBean); } } // Create bean instance. if (mbd.isSingleton()) { //通过createBean方法创建SingleTon Bean实例,有一个回调函数getObject,会在getSingleTon中调用ObjectFactory的createBean sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } //创建protoType的Bean 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. //检查Bean的类型是不是需要的类型,如果是,就返回Bean,这个Bean已经是包含了依赖关系的Bean了。 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; }
2.有两种实例化Java对象的方法:
- 通过BeanUtils,使用了JVM的反射功能
- 通过CGLIB(一个常用的字节码生成器的类库)生成、
public Object instantiate(RootBeanDefinition beanDefinition,String beanName, BeanFactory owner) { //1.若没有配置lookup-method采用JVM的反射功能 if (beanDefinition.getMethodOverrides().isEmpty()) { //取得指定的构造器或者是生成对象的工厂方法来对Bean进行实例化 Constructor constructorToUse = (Constructor) beanDefinition.resolvedConstructorOrFactoryMethod; if (constructorToUse == null) { final Class clazz = beanDefinition.getBeanClass(); if (clazz.isInterface()) throw new BeanInstantiationException(clazz,"Specified class is an interface"); try { if (System.getSecurityManager() != null) constructorToUse = (Constructor) AccessController.doPrivileged(new PrivilegedExceptionAction() { public Constructor run() throws Exception { return clazz.getDeclaredConstructor(null); } public volatile Object run()throws Exception { return run(); } final SimpleInstantiationStrategy this$0; private final Class val$clazz; { this$0 = SimpleInstantiationStrategy.this; clazz = class1; super(); } }); else constructorToUse = clazz.getDeclaredConstructor(null);//利用反射获取构造函数 beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Exception ex) { throw new BeanInstantiationException(clazz,"No default constructor found", ex); } } return BeanUtils.instantiateClass(constructorToUse, new Object[0]); } else {//2.如果配置了lookup-method使用CGLIB来实例化对象 return instantiateWithMethodInjection(beanDefinition, beanName, owner); } }
3.lookup-method的应用
如果一个singleton的调用者A依赖于一个prototype实例B,初始化singleton的时候会先实例化prototype,但是以后每次通过singleton调用prototype的时候,调用的永远是最开始的prototype。怎么解决呢?这种时候就要采用方法注入,即使用lookup-method的方法。Spring会采用运行时动态增强的方式CGLIB实现lookup-method。
如下实例,Singleton的A依赖prototype的B。
普通
被依赖的Aprototype
package Sample; public class Aprototype { private double a=0d; public Aprototype(){ a=Math.random(); } public void getRandom(){ System.out.println("Prototype输出:"+a); } }
Bsingleton(依赖Aprototype)
package Sample; public class Bsingleton { private Aprototype aprototype; public void setAprototype(Aprototype aprototype){ this.aprototype=aprototype; } //public abstract Aprototype getAprototype(); public void usePrototype(){ aprototype.getRandom(); } }
测试类
public class Test { public static void main(String[] args) { ApplicationContext ctx = new FileSystemXmlApplicationContext("bin/applicationContext.xml"); System.out.println("=====第一次调用Bsingleton======"); Bsingleton b=(Bsingleton) ctx.getBean("bsingleton"); b.usePrototype(); System.out.println(); System.out.println("=====第二次调用Bsingleton======"); Bsingleton c=(Bsingleton) ctx.getBean("bsingleton"); c.usePrototype(); } }
配置文件
<bean id="bsingleton" class="Sample.Bsingleton"> <property name="aprototype" ref="aprototype" /> </bean> <bean id="aprototype" class="Sample.Aprototype" scope="prototype"></bean>
结果:
=====第一次调用Bsingleton======
Prototype输出:0.6096473576637916
=====第二次调用Bsingleton======
Prototype输出:0.6096473576637916
分析:每次输出的结果一样,可见调用的始终是初始的prototype
采用lookup-method
Aprototype不变,测试类不变
Bsingleton添加抽象方法,修改为抽象类
package Sample; public abstract class Bsingleton { //private Aprototype aprototype; //public void setAprototype(Aprototype aprototype){ //this.aprototype=aprototype; //} public abstract Aprototype getAprototype(); public void usePrototype(){ getAprototype().getRandom(); } }
修改配置文件,改为lookup-method
<bean id="bsingleton" class="Sample.Bsingleton"> <lookup-method name="getAprototype" bean="aprototype" /> </bean> <bean id="aprototype" class="Sample.Aprototype" scope="prototype"></bean>
步骤:
- 定义Bsingleton为抽象类,在Bsingleton中添加一个抽象的方法,该方法用于获取被依赖的Bean
- 设置目标Bean为prototype
- 在Bsingleton的Bean中添加<lookup-method
name="XX" bean="BB" />,name是需要让Spring实现的方法,bean指定该方法实现的返回值。
结果:
=====第一次调用Bsingleton======
Prototype输出:0.7520596008690802
=====第二次调用Bsingleton======
Prototype输出:0.8769954010509483
分析:可以看到每次获取的值是不一样的,而不是始终是最初的prototype
文章参考资料:《Spring 技术内幕》