package com.wcj.simplebeanfactory;
import com.wcj.pojo.Student;
import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
* @author wcj
*
*/
public class SimpleBeanFactory2 {
public static void main(String[] args) {
FileSystemXmlApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:applicationContext.xml");
Student student = applicationContext.getBean("student",Student.class);
student.setAge(18);
student.setName("wcj");
student.printAge();
}
}
package org.springframework.context;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.io.support.ResourcePatternResolver;
/**
* ApplicationContext是spring中较高级的容器。和BeanFactory类似,它可以加载配置文件中定义的bean,将所有的bean集中在一起,当有请求的
* 时候分配bean。 另外,它增加了企业所需要的功能,比如,从属性文件从解析文本信息和将事件传递给所指定的监听器。这个容器在org.springframework.
* context.ApplicationContext接口中定义。ApplicationContext包含BeanFactory所有的功能,一般情况下,相对于BeanFactory,ApplicationContext
* 会被推荐使用。但BeanFactory仍然可以在轻量级应用中使用,比如移动设备或者基于applet的应用程序。
*
* ApplicationContext接口关系
* 1.支持不同的信息源。扩展了MessageSource接口,这个接口为ApplicationContext提供了很多信息源的扩展功能,比如:国际化的实现为多语言版本的应用提供服务。
* 2.访问资源。这一特性主要体现在ResourcePatternResolver接口上,对Resource和ResourceLoader的支持,这样我们可以从不同地方得到Bean定义资源。
* 这种抽象使用户程序可以灵活地定义Bean定义信息,尤其是从不同的IO途径得到Bean定义信息。这在接口上看不出来,不过一般来说,具体ApplicationContext都是
* 继承了DefaultResourceLoader的子类。因为DefaultResourceLoader是AbstractApplicationContext的基类,关于Resource后面会有更详细的介绍。
* 3.支持应用事件。继承了接口ApplicationEventPublisher,为应用环境引入了事件机制,这些事件和Bean的生命周期的结合为Bean的管理提供了便利。
* 4.附件服务。EnvironmentCapable里的服务让基本的Ioc功能更加丰富。
* 5.ListableBeanFactory和HierarchicalBeanFactory是继承的主要容器。
*
* 最常被使用的ApplicationContext接口实现类:
* 1,FileSystemXmlApplicationContext:该容器从XML文件中加载已被定义的bean。在这里,你需要提供给构造器XML文件的完整路径。
* 2,ClassPathXmlApplicationContext:该容器从XML文件中加载已被定义的bean。在这里,你不需要提供XML文件的完整路径,只需正确配置CLASSPATH
* 环境变量即可,因为,容器会从CLASSPATH中搜索bean配置文件。
* 3,WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在XML文件中
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
/**
* 得到这个应用环境的独一无二ID
* @return 得到这个应用独一无二的ID,或者返回一个空值
*/
String getId();
/**
* 得到这个应用的名称
* @return 得到这个应用的名称,或者返回一个空值
*/
String getApplicationName();
/**
* 返回这个应用环境的显示名
* @return 这个应用环境的显示名,或者返回一个空值
*/
String getDisplayName();
/**
* 当这个应用第一次载入时,返回一个时间差(ms)
* @return 返回一个时间差(ms)
*/
long getStartupDate();
/**
* 得到一个父类的环境,或者空值
* @return 返回一个父类的环境,或者空值
*/
ApplicationContext getParent();
/**
* 你可以使用它来自动装配依赖对象,但这是一个非常专业的使用情况下,你在99.99%的时间是不需要他的。
* @return 这个应用环境的AutowireCapableBeanFactory接口
* @throws IllegalStateException 如果这个应用并不支持AutowireCapableBeanFactory接口,抛出异常
*/
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
package org.springframework.context.support;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
/**
* 在FileSystemXmlApplicationContext的设计中,我们看到ApplicationContext的主要功能其实已经在AbstractXmlApplicationContext
* 中完成了,而在FileSystemXmlApplicationContext只需要完成它自身的两个功能。
*
* 一个就是启动Ioc容器的refresh()过程。这个会在下一章进行重点论述。
* 另一个就是加载XML的Bean定义资源,主要是getResourceByPath方法来完成。
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
/**
* 创建FileSystemXmlApplicationContext类
*/
public FileSystemXmlApplicationContext() {
}
/**
* 根据父类,创建FileSystemXmlApplicationContext类
* @param parent 父类的接口
*/
public FileSystemXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
/**
* 根据XML文件名,创建FileSystemXmlApplicationContext类
* @param configLocation BeanDefinition所在的文件路径
* @throws BeansException 如果创建失败就抛出异常
*/
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
/**
* 根据XML文件数组名,创建FileSystemXmlApplicationContext类
* @param configLocations XML文件名,可以指定多个BeanDefinition资源路径
* @throws BeansException 如果创建失败就抛出异常
*/
public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, null);
}
/**
* 根据载入的父类接口,以及XML文件名自动刷新环境以及创建FileSystemXmlApplicationContext类
* @param configLocations XML文件名
* @param parent 父类接口,同时指定自己的双亲容器
* @throws BeansException 如果创建失败就抛出异常
*/
public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
this(configLocations, true, parent);
}
/**
* 根据XML文件名自动刷新环境以及创建FileSystemXmlApplicationContext类
* @param configLocations XML文件名
* @param refresh 是否自动刷新环境
* @throws BeansException 如果创建失败就抛出异常
*/
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
this(configLocations, refresh, null);
}
/**
* 根据XML文件名、父类接口、自动刷新环境以及创建FileSystemXmlApplicationContext类
* 调用父类AbstractRefreshableConfigApplicationContext的方法,设置BeanDefinition定义的资源文件,完成IoC容器Bean定义资源的定位
* FileSystemXmlApplicationContext中最重要的实现方法,其他构建大部分都是基于它,类似的设计也在其他实现类中得以运用
*
* @param configLocations XML文件名
* @param refresh 是否自动刷新环境
* @param parent 父类接口,同时指定自己的双亲容器
* @throws BeansException 如果创建失败就抛出异常
*/
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh(); //Ioc容器的refresh()过程,是个非常复杂的过程,但不同的容器实现这里都是相似的,因此基类中就将他们封装好了
}
}
/**
* 加载XML Bean的给定资源
* 在文件应用中读取XML中的BeanDefinition以应对不同的BeanDefinition读取方式。
*
* @param string 具体路径
* @return Resource 返回一个具体资源
*/
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
}
ApplicationContext容器的入口:refresh()方法,refresh定义在AbstractApplicationContext类中,它详细的描述了整个ApplicationContext的初始化过程,比如:BeanFactory的更新、MessageSource和PostProcessor的注册等。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备刷新容器, 获取容器的当时时间, 同时给容器设置同步标识
prepareRefresh();
// 启动子类的refreshBeanFactory方法.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 为BeanFactory配置容器特性,例如类加载器、事件处理器等.
prepareBeanFactory(beanFactory);
try {
// 设置BeanFactory的后置处理.
postProcessBeanFactory(beanFactory);
// 调用BeanFactory的后处理器, 这些后处理器是在Bean定义中向容器注册的.
invokeBeanFactoryPostProcessors(beanFactory);
// 注册Bean的后处理器, 在Bean创建过程中调用.
registerBeanPostProcessors(beanFactory);
// 初始化上下文中的消息源.
initMessageSource();
// 初始化上下文中的事件机制.
initApplicationEventMulticaster();
// 初始化其它特殊的Bean.
onRefresh();
// 检查并向容器注册监听器Bean.
registerListeners();
// 实例化所有剩余的(non-lazy-init) 单例Bean.
finishBeanFactoryInitialization(beanFactory);
// 发布容器事件, 结束refresh过程.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经创建的单例Bean, 以避免资源占用.
destroyBeans();
// 取消refresh操作, 重置 'active' 标志.
cancelRefresh(ex);
throw ex;
}
finally {
//重置Spring的核心缓存
resetCommonCaches();
}
}
}
public AbstractXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
在AbstractXmlApplicationContext中其实,也已经完成仅仅只是继承一下。
private String[] configLocations;
public AbstractRefreshableConfigApplicationContext(ApplicationContext parent) {
super(parent);
}
public void setConfigLocations(String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
而在AbstractRefreshableConfigApplicationContext中,除了继承父类方法,还有就是FileSystemXmlApplicationContext中setConfigLocations方法的实现,setConfigLocations方法主要用于载入XML。
private DefaultListableBeanFactory beanFactory;
public AbstractRefreshableApplicationContext(ApplicationContext parent) {
super(parent);
}
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory(); //容器开始初始化
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory); //BeanDefinition的载入、解析和注册
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
在AbstractRefreshableApplicationContext类里,核心部分都在实现refreshBeanFactory方法中得到了实现。但是,却不是在这里进行的调用。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
最后在AbstractApplicationContext类中,进行了调用。通过同在AbstractApplicationContext中的refresh调用obtainFreshBeanFactory,进而调用子类中的refreshBeanFactory。至此,容器核心部分也就初始化完成。
内容来源于网络,如有侵权,请联系作者删除!