Spring Bean的加载依赖于BeanFactory,但实际使用时不会直接使用BeanFactory,而是采用ApplicationContext这个在BeanFactory基础上提供了扩展的接口:
1 2 3 public interface ApplicationContext extends EnvironmentCapable , ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
ApplicationContext接口具体的实现类常用的有:FileSystemXmlApplicationContet (从文件系统中读入Bean定义资源文件)、ClassPathXmlApplicationContext (从Classpath类路径中读入Bean定义资源文件)和XmlWebApplicationContext (从Web容器如Tomcat等中读入Bean定义资源文件)等。
以FileSystemXmlApplicationContext为例,通过分析FileSystemXmlApplicationContext及其父类的源码来分析IoC容器定位Bean定义资源文件的实现过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext { public FileSystemXmlApplicationContext() { } public FileSystemXmlApplicationContext(ApplicationContext parent) { super(parent); } //configLocation是Bean定义资源文件路径 public FileSystemXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); } public FileSystemXmlApplicationContext(String... configLocations) throws BeansException { this(configLocations, true, null); } public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException { this(configLocations, true, parent); } public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException { this(configLocations, refresh, null); } public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); //调用父类AbstractRefreshableConfigApplicationContext的方法, //设置Bean定义的资源文件,完成IoC容器Bean定义资源的定位 setConfigLocations(configLocations); if (refresh) { //调用父类AbstractApplicationContext的refresh() //函数启动载入Bean定义的过程,是Ioc容器载入Bean定义的入口 refresh(); } } @Override protected Resource getResourceByPath(String path) { if (path != null && path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path); } }
通过代码可以知道,在创建FileSystemXmlApplicationContext容器时,首先,调用父类容器的构造方法super(parent)方法为容器设置好Bean资源加载器。然后,再调用setConfigLocations(configLocations)方法设置Bean定义资源文件的定位路径。
Spring IoC容器对Bean定义资源的载入是从refresh()函数开始的,FileSystemXmlApplicationContext通过调用其父类AbstractApplicationContext的refresh()函数开始整个IoC容器对Bean定义的载入过程。AbstractApplicationContext#refresh()载入Bean定义过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public void refresh () throws BeansException, IllegalStateException { synchronized (this .startupShutdownMonitor) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } catch (BeansException ex) { destroyBeans(); cancelRefresh(ex); throw ex; } } }
refresh()方法主要为IoC容器Bean的生命周期管理提供条件,Spring IoC容器载入Bean定义资源文件从其子类容器的refreshBeanFactory()方法启动,所以refresh()中obtainFreshBeanFactory()是载入过程的开始:
1 2 3 4 5 6 7 8 9 10 protected ConfigurableListableBeanFactory obtainFreshBeanFactory () { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
AbstractApplicationContext的obtainFreshBeanFactory()方法调用refreshBeanFactory()方法,启动容器载入Bean定义资源文件的过程。AbstractApplicationContext类中只抽象定义了refreshBeanFactory()方法,容器真正调用的是其子类AbstractRefreshableApplicationContext#refreshBeanFactory(),方法的源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 protected final void refreshBeanFactory () throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this .beanFactoryMonitor) { this .beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException ("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
refreshBeanFactory()方法的作用是:在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化,对Bean定义资源进行载入。 createBeanFactory()是创建了DefaultListableBeanFactory工厂,载入BeanDefinition的方法loadBeanDefinitions只是AbstractRefreshableApplicationContext类中的抽象方法。 AbstractRefreshableApplicationContext的子类有XmlWebApplicationContext、AnnotationConfigWebApplicationContext。看类名就大概知道分别是解析哪种类型的配置。 解析好的BeanDefinition,由 BeanDefinitionReaderUtils.registerBeanDefinition() 注册到DefaultListableBeanFactory中的beanDefinitionMap:
1 2 3 /** Map of bean definition objects, keyed by bean name */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
注意上里的BeanDefinition只是解析后的类Bean定义的相关数据,并没进行依赖注入,依赖注入在以下两种情况发生:
(1)用户第一次通过getBean方法向IoC容索要Bean时,IoC容器触发依赖注入。 (2)当用户在Bean定义资源中为<Bean>元素配置了lazy-init属性,即让容器在解析注册Bean定义时进行预实例化,触发依赖注入。
AbstractApplicationContext#refresh()方法中obtainFreshBeanFactory()执行完后所有的BeanDefinition已经初始化好了。之后会涉及到BeanFactoryPostProcessor、BeanPostProcessor的调用,先不细入分析代码,只是大概介绍一下调用的先后顺序:
在上面的过程中,会调用beanFactory#getBean()来取得bean,来看下getBean()方法,我们知道BeanFactory接口中定义了几个getBean方法,就是向IoC容器索取管理的Bean的方法,在getBean时会完成对应bean的初始化。由于调用的层次比较复杂,最终调用了AbstractBeanFactory#getBean()方法,该方法实际上是调用了其AbstractBeanFactory#doGetBean()方法。
在doGetBean()方法中,如果Bean定义的单态模式(Singleton),则容器在创建之前先从缓存中查找,以确保整个容器中只存在一个实例对象。如果Bean定义的是原型模式(Prototype),则容器每次都会创建一个新的实例对象。除此之外,Bean定义还可以扩展为指定其生命周期范围。具体的Bean实例对象的创建过程由createBean()方法完成,其具体的实现类是AbstractAutowireCapableBeanFactory,最终的bean的创建是AbstractAutowireCapableBeanFactory#doCreateBean:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 protected Object doCreateBean (final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException { BeanWrapper instanceWrapper = null ; if (mbd.isSingleton()) { instanceWrapper = this .factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null ) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null ); Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null ) { exposedObject = initializeBean(beanName, exposedObject, mbd); } } return exposedObject; }
createBeanInstance()方法是根据XML的定义调用bean的有参或无参构造函数。跟踪该方法,我们最终会发现有个getInstantiationStrategy()方法,该方法的作用是获得实例化的策略对象,也就是指通过哪种方案进行实例化的过程,Spring当中提供了两种实例化方案:BeanUtils和CGLIB方式。BeanUtils实现机制是通过Java的反射机制,Cglib是一个第三方类库采用的是一种字节码加强方式机制。 populateBean()方法会获得BeanDefinition中设置的property信息,对这些property进行赋值,即依赖注入的过程。在这个方法里完成对属性的注入,比如setXxx()方法的调用、属性的注解注入。
对于initializeBean()方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 protected Object initializeBean (final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() != null ) { AccessController.doPrivileged(new PrivilegedAction <Object>() { @Override public Object run () { invokeAwareMethods(beanName, bean); return null ; } }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException ( (mbd != null ? mbd.getResourceDescription() : null ), beanName, "Invocation of init method failed" , ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
invokeAwareMethods()方法判断是BeanNameAware、BeanFactoryAware之类的Aware类型,如果是的话就执行对应方法。 applyBeanPostProcessorsBeforeInitialization()方法是如果实现了BeanPostProcessor接口,这里会执行postProcessBeforeInitialization方法。 invokeInitMethods()方法中,先判断是否实现了InitializingBean接口,如果是执行afterPropertiesSet()方法,然后如果配置了init-method就执行initMethod方法。 applyBeanPostProcessorsAfterInitialization()方法是如果实现了BeanPostProcessor接口,这里会执行postProcessAfterInitialization方法。 到此为止一个BeanFactoryPostProcessor的Bean就初始化完成了。
于是就可以通过BeanFactoryPostProcessor的postProcessBeanFactory()的调用,来修改某些beanDefinition的值,示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Override public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException { String[] beanNames = beanFactory.getBeanDefinitionNames(); for (String beanName : beanNames) { BeanDefinition bd = beanFactory.getBeanDefinition(beanName); System.out.println(bd.getBeanClassName()); PropertyValue[] pvArray = bd.getPropertyValues().getPropertyValues(); for (PropertyValue pv : pvArray) { System.out.println(pv.getName() + "---" + pv.getValue()); } ConstructorArgumentValues cas = bd.getConstructorArgumentValues(); for (ConstructorArgumentValues.ValueHolder valueHolder : cas.getIndexedArgumentValues().values()) { System.out.println(valueHolder.getName() + "---" + valueHolder.getValue()); } for (ConstructorArgumentValues.ValueHolder valueHolder : cas.getGenericArgumentValues()) { System.out.println(valueHolder.getName() + "---" + valueHolder.getValue()); } } }
Spring中的PropertyPlaceholderConfigurer正是通过这种方式来实现了配置宏替换。
需要注意的是,BeanPostProcessor在源码注释已经表述了,只有当其它非实现BeanPostProcessor的bean且在同一个容器的bean在初始化的时候,才会回调BeanPostProcessor重写的那些方法,所以一个继承了BeanPostProcessor的类初始化会发现是不会有override方法的回调的。
执行顺序:Constructor > @PostConstruct > InitializingBean > init-method,@PostConstruct优先于后者是因为CommonAnnotationBeanPostProcessor这个类,它继承自InitDestroyAnnotationBeanPostProcessor,用于处理@PostConstruct这类注解的BeanPostProcessor,所以先于InitializingBean执行。
转载自:http://blog.csdn.net/chjttony/article/details/6248682 http://blog.csdn.net/chjttony/article/details/6263347 http://blog.csdn.net/chjttony/article/details/6278627