spring源码浅析 - IOC
===========================================
原文链接: spring源码浅析——IOC 转载请注明出处!
===========================================
在读之前应该明白其重点:读spring读的不是其具体的技术实现,读的是其系统层面的结构和设计! spring漂亮就漂亮在她的结构,包括接口和抽象类的灵活使用!
IOC模块只是spring框架中的一个模块,这里只对该模块进行分析(使用版本:spring-framework-4.0.0.RELEASE-dist)。
IOC(Inversion of Control,控制反转),“控制对象的创建或销毁不再由调用处进行控制,而是由spring容器进行管理和控制”,“控制”就是指对程序中的对象实体的生命周期的控制。“反转”本来是由调用处进行控制的,现在调用处不管了,反倒由spring进行管理,所以叫做bean的管理“反转”了,合在一起也就是所谓的“控制反转”。很不喜欢这四个字来描述!刚接触spring的朋友对这个概念比较难以理解,我当时接触的时候就感觉无法理解,直到后来一遍一遍的琢磨之后才理解其含义。
IOC涉及到的类比较多,结构较为复杂,在分析之前需要先抓住九个关键的类系(之所以用类系来形容是因为下面所列出来的不是某个具体的实现类,而是从接口到抽象类等一些系列相关类/接口):
BeanFactory:bean的管理工厂,所有的bean都在该对象中进行创建、存储和销毁。
DefaultListableBeanFactory:beanFactory具体实现类
Resource:spring的配置信息,该信息可能来源于xml文件,可能来源于网络,也可能来源于数据流中。不管他从哪里来的,都封装为Resource对象。
BeanDefinition:bean的所有信息在该对象中进行封装,包括bean的参数值、方法名、是否懒加载、是否为单例等各种信息
BeanDefinitionReader:见名知意,构建BeanDefinition的reader,也就是通过该Reader从Resource中读取信息封装为BeanDefinition。
ApplicationContext:俗称“上下文”和“控制反转”一样晦涩难懂,据我猜测之所以这样命名,是因为context继承了太多的接口,具有各种各样的功能,可以称为万能的上帝。并且所有的需要用到的bean都可以在其中取到,起到沟通上下的桥梁的作用,所以叫做“上下文”。这里可以看出其特性是:实现了各种功能接口,封装了各种bean对象。
Environment:运行环境配置信息,也就是一些配置属性,来源于:properties文件,JVM properties,system环境变量,JNDI, servlet context parameters上下文参数,专门的Properties对象,Maps等等
Document:从xml文件文件中抽取出来的本文对象。
Element:从Document中取出的node节点
上面的描述暂时理解不了没关系,只要心里面有这几个模块的概念就可以,在进行分析代码的时候能够意识到相关bean的功能即可,如需深入理解相关类系,需要深入对代码进行剖析。
下面我们就从一个小例子进入对IOC模块的分析。
Spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="person" class="com.zpj.bean.Person">
<property name="name" value="xingoo" />
<property name="age" value="12" />
</bean>
</beans>
程序入口
public class SpringTest {
public static void main(String[] args) {
//获取context上下文对象,该上下文是ClassPathXmlApplicationContext类
ApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
//从容器中取出名为"person"的对象
Person person = context.getBean("person", Person.class);
//调用person.info()方法。
person.info();
}
}
在进入ClassPathXmlApplicationContext构造方法之后,一直调用this()找到被重载的构造方法
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
//this()进入重载的构造方法
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
第一个super()一直向上找到AbstractApplicationContext,该类中实现了大部分的标准操作。
public AbstractApplicationContext(ApplicationContext parent) {
this();
setParent(parent);
}
//先看this方法,this()进入该方法对resourcePatternResolver进行赋值
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
//这里需要注意的是getResourcePatternResolver()中返回的是PathMatchingResourcePatternResolver对象,并把this作为参数赋值给resolver中的resourceLoader。
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
//在PathMatchingResourcePatternResolver中,this被赋值给resourceLoader。上面传进来的是context,怎么用resourceLoader进行接收了呢?
//因为Context实现了ResourceLoader的接口(这里需要记住)
private final ResourceLoader resourceLoader;//resourceLoader的定义
public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
this.resourceLoader = resourceLoader;
}
//************************分析完this(),下面看setParent(parent);(这里parent是个null值,这里我们进入看看都进行了哪些操作)**************************************************************
@Override
public void setParent(ApplicationContext parent) {
this.parent = parent;
if (parent != null) {
//注意这里,说明是从AbstractApplicationContext中取得的EnvEnvironment对象
Environment parentEnvironment = parent.getEnvironment();
if (parentEnvironment instanceof ConfigurableEnvironment) {
//merge()对取得的parentEnvironment和当前的Environment进行合并。
getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
}
}
}
// 再AbstractApplicationContext中,如果存在则直接返回,如果不存在则进行创建操作
// 注意该方法,后面有多次进行获取environment
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
//这里创建同时保存在了当前类AbstractApplicationContext中
this.environment = createEnvironment();
}
return this.environment;
}
//创建的时候返回以StandardEnvironment实现类进行创建
protected ConfigurableEnvironment createEnvironment() {
return new StandardEnvironment();
}
// 至此,ClassPathXmlApplicationContext构造方法中super()的操作结束
这里对ClassPathXmlApplicationContext构造方法的super操作进行汇总:
1、AbstractApplicationContext中对resourcePatternResolver设值,并把自身当做resourceLoader设置给resourcePatternResolver。
2、AbstractApplicationContext中对environment进行了设值
3、把parent的environment和自己的environment进行了合并
这里需要注意的是,进行到这一步environment和resourcePatternResolver都已经有值了,在后面就可以进行get使用了。
下面进入到setConfigLocations(configLocations) 操作
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {
super(parent);
//对该方法进行分析,这里configLocations的值为[springConfig.xml]
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
//进入void org.springframework.context.support.AbstractRefreshableConfigApplicationContext.setConfigLocations(String... locations)
public void setConfigLocations(String... locations) {
if (locations != null) {
//这句断言攒在的意义是什么?上面已经进行了不为空判断,如果为null根本就执行不到这一步
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
//该方法主要目的就是对configLocations进行解析设值
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
// 进入resolvePath,这里调用了Environment的resolveRequiredPlaceholders方法(上面已经说过Environment已经进行了设值)
protected String resolvePath(String path) {
return getEnvironment().resolveRequiredPlaceholders(path);
}
// 该方法全名为:String org.springframework.core.env.AbstractEnvironment.resolveRequiredPlaceholders(String text) throws IllegalArgumentException
//是实现在StandardEnvironment的父类AbstractEnvironment中
@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
// 这里又进行了调用
return this.propertyResolver.resolveRequiredPlaceholders(text);
}
// 这里的需要注意的是propertyResolver的实例化在哪里进行的。
// 在该类中有三个全局变量:
protected final Log logger = LogFactory.getLog(getClass());
private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);
private final ConfigurablePropertyResolver propertyResolver =new PropertySourcesPropertyResolver(this.propertySources);
// 所以propertyResolver在生成new StandEnvironment()的时候就同时创建了
// 这里不再继续进行跟进去,this.propertyResolver.resolveRequiredPlaceholders(text);主要是对占位符进行了替换操作,把${name}替换为其实际值。
// 至此setConfigLocations()操作结束
这里对ClassPathXmlApplicationContext构造方法的setConfigLocations(configLocations) 操作进行汇总:
1、xml对配置文件名称进行了解析,解析之后存储在String[] org.springframework.context.support.AbstractRefreshableConfigApplicationContext.configLocations数组中。
到这一步,xml配置文件路径已经进行了存储,下面就该对xml进行读取,加载、解析等操作。
下面进入到void org.springframework.context.support.AbstractApplicationContext.refresh() throws BeansException, IllegalStateException操作
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//对context的刷新进行准备操作
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//告诉子类刷新内部bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//对beanFactory进行准备操作,以便于context的后续使用
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//在对beanFactory进行标准化处理之后,允许子类对beanFactory进行后处理操作,子类覆写该方法进行特殊操作
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//在上下文中调用作为bean注册的工厂处理器。
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//注册拦截bean创建的bean处理器,这里只是进行注册操作
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//为上下文初始化message,即对国际化资源文件进行初始化
initMessageSource();
// Initialize event multicaster for this context.
//初始化应用消息广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//子类覆写该方法,进行自己的初始化操作
onRefresh();
// Check for listener beans and register them.
//查找所用已经注册过的listener bean并注册到广播器中
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//初始化剩下的单实例(非惰性)
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//最后一步:完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent事件,通知其他监听者
finishRefresh();
}
catch (BeansException ex) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
// Destroy already created singletons to avoid dangling resources.
//发生异常销毁已经创建的单利bean
destroyBeans();
// Reset 'active' flag.
//关闭刷新操作
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
beanFactory的创建和初始化操作都在该方法中进行,下面逐个方法进行分析
// 进入void org.springframework.context.support.AbstractApplicationContext.prepareRefresh()
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
//留给子类覆写,实现其特有的占位符初始化操作,这里方法体为空
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
//验证系统所必须的关键性配置参数是否已经加载到environment中,如果没有则抛出MissingRequiredPropertiesException异常
getEnvironment().validateRequiredProperties();
}
/**
* void org.springframework.context.support.AbstractApplicationContext.prepareRefresh()汇总:
* 1、让子类进行自身特有的占位符初始化操作
* 2、验证必须的配置参数是否已经加载
*/
// 进入ConfigurableListableBeanFactory org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory()
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新beanFactory
refreshBeanFactory();
//获取beanFactory并进行返回
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
//这里进行刷新操作,该方法实现于:void org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {// 判断方式:return (this.beanFactory != null);
//如果已经存在则进行销毁同时关闭,至于怎么销毁和关闭的就不详解
destroyBeans();
closeBeanFactory();
}
try {
//创建beanFactory,该方法直接return new DefaultListableBeanFactory(getInternalParentBeanFactory());这里需要注意的是beanFactory的实现类是DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
//设置序列化唯一id
beanFactory.setSerializationId(getId());
//设置beanFactory相关属性,是否允许覆盖同名称的不同定义的对象、是否允许循环依赖,可以被子类进行覆写
customizeBeanFactory(beanFactory);
//重点!!!加载beanDefinition 加载分两步:1、解析Document 2、注册BeanDefinition
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
// 这里进入关键方法loadBeanDefinitions,该方法实现于:void org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
//这里是使用xml文件进行配置的,所以这里使用的是XmlBeanDefinitionReader作为beanDefinitionReader,
//这里beanFactory作为BeanDefinitionRegistry实例传入beanDefinitionReader.XmlBeanDefinitionReader.XmlBeanDefinitionReader(BeanDefinitionRegistry registry);
//注意beanDefinitionReader中的registry
//提醒:还记得文章开始部分定义的BeanDefinition是什么吗?bean的所有信息在该对象中进行封装,包括bean的参数值、方法名、是否懒加载、是否为单例等各种信息
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
//注意这个ResourceLoader参数,此处的this指的是AbstractXmlApplicationContext,而AbstractBeanDefinitionReader.setResourceLoader(ResourceLoader resourceLoader)中接收的是ResourceLoader
//所以说AbstractXmlApplicationContext实现了ResourceLoader接口(上面已经说过)
beanDefinitionReader.setResourceLoader(this);
//设置实体解析器,该ResourceEntityResolver还是用ResourceLoader接收的this
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
//对defintionReader进行初始化操作,运训子类进行覆盖,然后开始进行实际加载bean definition
initBeanDefinitionReader(beanDefinitionReader);
//重点!!!进行BeanDefinitions的加载操作
loadBeanDefinitions(beanDefinitionReader);
}
// 这里进入关键方法loadBeanDefinitions,该方法实现于:void org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//取得ClassPathResource并进行加载
Resource[] configResources = getConfigResources();
if (configResources != null) {
//标识位置:loadBeanDefinitions_Resource
reader.loadBeanDefinitions(configResources);
}
//取得ConfigLocations并进行加载(这里的ConfigLocations就是上面解析出来的String[] configLocations,存储着配置文件的路径)
String[] configLocations = getConfigLocations();
if (configLocations != null) {
//标识位置:loadBeanDefinitions_String
reader.loadBeanDefinitions(configLocations);
}
}
// 这里的loadBeanDefinitions_String和loadBeanDefinitions_Resource进行加载的方法是一样的,都是调用int org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException
// 进行加载。只是loadBeanDefinitions_String在进行加载之前多了一步操作,把String转化为Resource,然后进行加载,这里就从loadBeanDefinitions_String跟进去
// 进入loadBeanDefinitions方法,该方法实现于:int org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
for (String location : locations) {
//循环对locations进行加载
counter += loadBeanDefinitions(location);
}
return counter;
}
//进入loadBeanDefinitions,该方法实现于:int org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(String location) throws BeanDefinitionStoreException
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
//继续调用加载
return loadBeanDefinitions(location, null);
}
//进入loadBeanDefinitions,该方法实现于: int org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//还记得这个resourceLoader什么时候赋值的吗?赋值的又是谁呢?AbstractXmlApplicationContext
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
//这里根据resourceLoader进行划分,不同的resourceLoader从不同的源加载resource。
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
//把resource进行缓存
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
//只能加载从绝对URL加载单例资源,xml走的是这里,进入之后区分类路径资源、URL资源和文件系统资源(xml属于该种),这里不再对封装resource进行分析
Resource resource = resourceLoader.getResource(location);
//进行记载definition,这里调用的方法和标识位置:loadBeanDefinitions_Resource调用的加载方法就相同了
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
//把resource进行缓存
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
//进入loadBeanDefinitions,该方法实现于:int org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException
//当前进行加载的resources存储于这个ThreadLocal线程局部变量中
private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded = new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded");
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
//操作之前先把currentResources放在resourcesCurrentlyBeingLoaded中,注意下面加载操作完成之后进行了remove
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
//这里把encodedResource放进currentResources中,后面依旧会remove
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//获取inputStream
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
//封装为InputSource
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
//为inputSource设置resource的编码方式
inputSource.setEncoding(encodedResource.getEncoding());
}
//这里才是真正进行BeanDefinitions的加载操作,前面的都是进行预处理封装inputSource
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
//操作之后把currentResources从resourcesCurrentlyBeingLoaded中移除出去,注意上面加载操之前的add
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
// 进入doLoadBeanDefinitions,该方法实现于:int org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//关键方法两步:取得Document;注册BeanDefinition
//这里就不再解析怎么加载Document的了,Spring是使用SAX进行xml解析的,可以自己详细了解
Document doc = doLoadDocument(inputSource, resource);
//把BeanDefinition注册到context中
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
// 进入registerBeanDefinitions,该方法实现于: int org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建documentReader这里返回的是 return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(this.getEnvironment());
//这个countBefore是为了统计从Document中加载的beanDefinition的个数
int countBefore = getRegistry().getBeanDefinitionCount();
//进行注册BeanDefinition操作
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
// 进入registerBeanDefinitions,该方法实现于:void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
//取出root节点,从root节点遍历所有节点进行注册
doRegisterBeanDefinitions(root);
}
// 进入doRegisterBeanDefinitions,该方法实现于:void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element root)
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(this.readerContext, root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
Assert.state(this.environment != null, "Environment must be set for evaluating profiles");
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
//为子类预留,覆写进行解析之前的特殊操作
preProcessXml(root);
//通过代理进行解析
parseBeanDefinitions(root, this.delegate);
//为子类预留,覆写进行解析之后的特殊操作
postProcessXml(root);
this.delegate = parent;
}
// 进入postProcessXml,该方法实现于:void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
//循环所有的Element节点进行解析
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
// 进入postProcessXml,该方法实现于: void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//对“import”标签进行解析注册
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//对“alias”标签进行解析注册
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//对“bean”标签进行解析注册,这里从这里面进去分析,这里的分支思路大同小异
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//对“beans”标签进行解析注册
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
// 进入processBeanDefinition,该方法实现于: void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//对ele进行解析,把id、name、aliases进行封装
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//如果需要则使用bdHolder的代理进行操作
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
//对definition的最终注册,注意该方法的第二个参数:Registry
//设置readerContext位置:documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//设置Registry位置(第五个参数this):return new XmlReaderContext(resource, this.problemReporter, this.eventListener,this.sourceExtractor, this, getNamespaceHandlerResolver());
//该this指代的是XmlBeanDefinitionReader实例
//而他的Registry设置位置是:XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//所以该Registry就是beanFactory
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
//发送注册event给监听者
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
// 进入BeanDefinitionReaderUtils.registerBeanDefinition,该方法实现于: void org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {
// Register bean definition under primary name.
//取得beanName注册beanDefinition
String beanName = definitionHolder.getBeanName();
//注册beanDefinition
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
//取得对该beanName注册aliases,这里关联的是aliases--beanName,所以通过aliase进行取值的时候需要先由aliase找到beanName,然后根据beanName找到beanDefinition
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String aliase : aliases) {
registry.registerAlias(beanName, aliase);
}
}
}
// 进入registerBeanDefinition.registerBeanDefinition,该方法实现于:void org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException
//注意该方法的实现位置:DefaultListableBeanFactory
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name 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);
}
}
BeanDefinition oldBeanDefinition;
//加锁同步
//注意该上面的beanDefinitionMap
synchronized (this.beanDefinitionMap) {
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
//如果已经存在该beanDefinition则判断是否允许覆盖
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
" with a framework-generated bean definition ': replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {
//如果不存在该bean则注册beanName
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
//把bean加入缓存beanDefinitionMap,这里完成注册
this.beanDefinitionMap.put(beanName, beanDefinition);
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
//重置该beanDefinition的所有缓存 Reset all bean definition caches for the given bean
resetBeanDefinition(beanName);
}
}
//至此,beanFactory构建完成, ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();结束。
beanFactory创建完成之后,缓存中已经存储有配置bean的beanDefinition。
在void org.springframework.context.support.AbstractApplicationContext.refresh() throws BeansException, IllegalStateException中的其他方法是对beanFactory以及context的其他操作,主要是为子类覆写一些方法、注册一些监听、处理一下国际化资源文件等,这里就不再进行详细分析。
至此,该方法中的context 创建完成。
public class SpringTest {
public static void main(String[] args) {
//获取context上下文对象,该上下文是ClassPathXmlApplicationContext类
ApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
//从容器中取出名为"person"的对象
Person person = context.getBean("person", Person.class);
//调用person.info()方法。
person.info();
}
}
spring用着方便,但是实现起来确实很复杂,里面涉及了大量的设计模式,装饰模式、代理模式、工厂模式、模板方法等,对于学习系统设计有很大的帮助。
文章中只简单的介绍了一下beanFactory的创建,其中忽略了大量的细节,比如对单利bean的管理,beanDefinition到bean的创建,此外,对beanFactory的后期处理,Listeners的添加、MessageSource的初始化等。有兴趣的朋友可以深入研究一下,这里就不再继续分析,能力有限,很多东西我也不是太明白,还需要继续学习。建议刚接触该模块源码的朋友一定要多进行debug读源码,对源码进行分析,如果能在熟练使用sping的基础上读源码效果会更好,最好自己亲自绘制一下该模块的类图,这样可以对该模块的整体结构有一个比较清晰的认识,对上面的九个关键的类系就能够有更好的理解。
在学习的过程中遇到一本讲解比较详细的书,这里分享给大家,里面还有绘制的相关类图,用powerdesigner进行打开。
链接在此:学习资源分享 文件名分别为:spring源码深度解析 spring-IOC相关类图
------over
转:https://www.cnblogs.com/PerkinsZhu/p/6500837.html
原文链接: spring源码浅析——IOC 转载请注明出处!
===========================================
在读之前应该明白其重点:读spring读的不是其具体的技术实现,读的是其系统层面的结构和设计! spring漂亮就漂亮在她的结构,包括接口和抽象类的灵活使用!
IOC模块只是spring框架中的一个模块,这里只对该模块进行分析(使用版本:spring-framework-4.0.0.RELEASE-dist)。
IOC(Inversion of Control,控制反转),“控制对象的创建或销毁不再由调用处进行控制,而是由spring容器进行管理和控制”,“控制”就是指对程序中的对象实体的生命周期的控制。“反转”本来是由调用处进行控制的,现在调用处不管了,反倒由spring进行管理,所以叫做bean的管理“反转”了,合在一起也就是所谓的“控制反转”。很不喜欢这四个字来描述!刚接触spring的朋友对这个概念比较难以理解,我当时接触的时候就感觉无法理解,直到后来一遍一遍的琢磨之后才理解其含义。
IOC涉及到的类比较多,结构较为复杂,在分析之前需要先抓住九个关键的类系(之所以用类系来形容是因为下面所列出来的不是某个具体的实现类,而是从接口到抽象类等一些系列相关类/接口):
BeanFactory:bean的管理工厂,所有的bean都在该对象中进行创建、存储和销毁。
DefaultListableBeanFactory:beanFactory具体实现类
Resource:spring的配置信息,该信息可能来源于xml文件,可能来源于网络,也可能来源于数据流中。不管他从哪里来的,都封装为Resource对象。
BeanDefinition:bean的所有信息在该对象中进行封装,包括bean的参数值、方法名、是否懒加载、是否为单例等各种信息
BeanDefinitionReader:见名知意,构建BeanDefinition的reader,也就是通过该Reader从Resource中读取信息封装为BeanDefinition。
ApplicationContext:俗称“上下文”和“控制反转”一样晦涩难懂,据我猜测之所以这样命名,是因为context继承了太多的接口,具有各种各样的功能,可以称为万能的上帝。并且所有的需要用到的bean都可以在其中取到,起到沟通上下的桥梁的作用,所以叫做“上下文”。这里可以看出其特性是:实现了各种功能接口,封装了各种bean对象。
Environment:运行环境配置信息,也就是一些配置属性,来源于:properties文件,JVM properties,system环境变量,JNDI, servlet context parameters上下文参数,专门的Properties对象,Maps等等
Document:从xml文件文件中抽取出来的本文对象。
Element:从Document中取出的node节点
上面的描述暂时理解不了没关系,只要心里面有这几个模块的概念就可以,在进行分析代码的时候能够意识到相关bean的功能即可,如需深入理解相关类系,需要深入对代码进行剖析。
下面我们就从一个小例子进入对IOC模块的分析。
Spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="person" class="com.zpj.bean.Person">
<property name="name" value="xingoo" />
<property name="age" value="12" />
</bean>
</beans>
程序入口
public class SpringTest {
public static void main(String[] args) {
//获取context上下文对象,该上下文是ClassPathXmlApplicationContext类
ApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
//从容器中取出名为"person"的对象
Person person = context.getBean("person", Person.class);
//调用person.info()方法。
person.info();
}
}
在进入ClassPathXmlApplicationContext构造方法之后,一直调用this()找到被重载的构造方法
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
//this()进入重载的构造方法
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
第一个super()一直向上找到AbstractApplicationContext,该类中实现了大部分的标准操作。
public AbstractApplicationContext(ApplicationContext parent) {
this();
setParent(parent);
}
//先看this方法,this()进入该方法对resourcePatternResolver进行赋值
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
//这里需要注意的是getResourcePatternResolver()中返回的是PathMatchingResourcePatternResolver对象,并把this作为参数赋值给resolver中的resourceLoader。
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
//在PathMatchingResourcePatternResolver中,this被赋值给resourceLoader。上面传进来的是context,怎么用resourceLoader进行接收了呢?
//因为Context实现了ResourceLoader的接口(这里需要记住)
private final ResourceLoader resourceLoader;//resourceLoader的定义
public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
this.resourceLoader = resourceLoader;
}
//************************分析完this(),下面看setParent(parent);(这里parent是个null值,这里我们进入看看都进行了哪些操作)**************************************************************
@Override
public void setParent(ApplicationContext parent) {
this.parent = parent;
if (parent != null) {
//注意这里,说明是从AbstractApplicationContext中取得的EnvEnvironment对象
Environment parentEnvironment = parent.getEnvironment();
if (parentEnvironment instanceof ConfigurableEnvironment) {
//merge()对取得的parentEnvironment和当前的Environment进行合并。
getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
}
}
}
// 再AbstractApplicationContext中,如果存在则直接返回,如果不存在则进行创建操作
// 注意该方法,后面有多次进行获取environment
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
//这里创建同时保存在了当前类AbstractApplicationContext中
this.environment = createEnvironment();
}
return this.environment;
}
//创建的时候返回以StandardEnvironment实现类进行创建
protected ConfigurableEnvironment createEnvironment() {
return new StandardEnvironment();
}
// 至此,ClassPathXmlApplicationContext构造方法中super()的操作结束
这里对ClassPathXmlApplicationContext构造方法的super操作进行汇总:
1、AbstractApplicationContext中对resourcePatternResolver设值,并把自身当做resourceLoader设置给resourcePatternResolver。
2、AbstractApplicationContext中对environment进行了设值
3、把parent的environment和自己的environment进行了合并
这里需要注意的是,进行到这一步environment和resourcePatternResolver都已经有值了,在后面就可以进行get使用了。
下面进入到setConfigLocations(configLocations) 操作
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {
super(parent);
//对该方法进行分析,这里configLocations的值为[springConfig.xml]
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
//进入void org.springframework.context.support.AbstractRefreshableConfigApplicationContext.setConfigLocations(String... locations)
public void setConfigLocations(String... locations) {
if (locations != null) {
//这句断言攒在的意义是什么?上面已经进行了不为空判断,如果为null根本就执行不到这一步
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
//该方法主要目的就是对configLocations进行解析设值
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
// 进入resolvePath,这里调用了Environment的resolveRequiredPlaceholders方法(上面已经说过Environment已经进行了设值)
protected String resolvePath(String path) {
return getEnvironment().resolveRequiredPlaceholders(path);
}
// 该方法全名为:String org.springframework.core.env.AbstractEnvironment.resolveRequiredPlaceholders(String text) throws IllegalArgumentException
//是实现在StandardEnvironment的父类AbstractEnvironment中
@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
// 这里又进行了调用
return this.propertyResolver.resolveRequiredPlaceholders(text);
}
// 这里的需要注意的是propertyResolver的实例化在哪里进行的。
// 在该类中有三个全局变量:
protected final Log logger = LogFactory.getLog(getClass());
private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);
private final ConfigurablePropertyResolver propertyResolver =new PropertySourcesPropertyResolver(this.propertySources);
// 所以propertyResolver在生成new StandEnvironment()的时候就同时创建了
// 这里不再继续进行跟进去,this.propertyResolver.resolveRequiredPlaceholders(text);主要是对占位符进行了替换操作,把${name}替换为其实际值。
// 至此setConfigLocations()操作结束
这里对ClassPathXmlApplicationContext构造方法的setConfigLocations(configLocations) 操作进行汇总:
1、xml对配置文件名称进行了解析,解析之后存储在String[] org.springframework.context.support.AbstractRefreshableConfigApplicationContext.configLocations数组中。
到这一步,xml配置文件路径已经进行了存储,下面就该对xml进行读取,加载、解析等操作。
下面进入到void org.springframework.context.support.AbstractApplicationContext.refresh() throws BeansException, IllegalStateException操作
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//对context的刷新进行准备操作
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//告诉子类刷新内部bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//对beanFactory进行准备操作,以便于context的后续使用
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//在对beanFactory进行标准化处理之后,允许子类对beanFactory进行后处理操作,子类覆写该方法进行特殊操作
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//在上下文中调用作为bean注册的工厂处理器。
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//注册拦截bean创建的bean处理器,这里只是进行注册操作
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//为上下文初始化message,即对国际化资源文件进行初始化
initMessageSource();
// Initialize event multicaster for this context.
//初始化应用消息广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//子类覆写该方法,进行自己的初始化操作
onRefresh();
// Check for listener beans and register them.
//查找所用已经注册过的listener bean并注册到广播器中
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//初始化剩下的单实例(非惰性)
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//最后一步:完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent事件,通知其他监听者
finishRefresh();
}
catch (BeansException ex) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
// Destroy already created singletons to avoid dangling resources.
//发生异常销毁已经创建的单利bean
destroyBeans();
// Reset 'active' flag.
//关闭刷新操作
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
beanFactory的创建和初始化操作都在该方法中进行,下面逐个方法进行分析
// 进入void org.springframework.context.support.AbstractApplicationContext.prepareRefresh()
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
//留给子类覆写,实现其特有的占位符初始化操作,这里方法体为空
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
//验证系统所必须的关键性配置参数是否已经加载到environment中,如果没有则抛出MissingRequiredPropertiesException异常
getEnvironment().validateRequiredProperties();
}
/**
* void org.springframework.context.support.AbstractApplicationContext.prepareRefresh()汇总:
* 1、让子类进行自身特有的占位符初始化操作
* 2、验证必须的配置参数是否已经加载
*/
// 进入ConfigurableListableBeanFactory org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory()
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新beanFactory
refreshBeanFactory();
//获取beanFactory并进行返回
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
//这里进行刷新操作,该方法实现于:void org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {// 判断方式:return (this.beanFactory != null);
//如果已经存在则进行销毁同时关闭,至于怎么销毁和关闭的就不详解
destroyBeans();
closeBeanFactory();
}
try {
//创建beanFactory,该方法直接return new DefaultListableBeanFactory(getInternalParentBeanFactory());这里需要注意的是beanFactory的实现类是DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
//设置序列化唯一id
beanFactory.setSerializationId(getId());
//设置beanFactory相关属性,是否允许覆盖同名称的不同定义的对象、是否允许循环依赖,可以被子类进行覆写
customizeBeanFactory(beanFactory);
//重点!!!加载beanDefinition 加载分两步:1、解析Document 2、注册BeanDefinition
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
// 这里进入关键方法loadBeanDefinitions,该方法实现于:void org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
//这里是使用xml文件进行配置的,所以这里使用的是XmlBeanDefinitionReader作为beanDefinitionReader,
//这里beanFactory作为BeanDefinitionRegistry实例传入beanDefinitionReader.XmlBeanDefinitionReader.XmlBeanDefinitionReader(BeanDefinitionRegistry registry);
//注意beanDefinitionReader中的registry
//提醒:还记得文章开始部分定义的BeanDefinition是什么吗?bean的所有信息在该对象中进行封装,包括bean的参数值、方法名、是否懒加载、是否为单例等各种信息
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
//注意这个ResourceLoader参数,此处的this指的是AbstractXmlApplicationContext,而AbstractBeanDefinitionReader.setResourceLoader(ResourceLoader resourceLoader)中接收的是ResourceLoader
//所以说AbstractXmlApplicationContext实现了ResourceLoader接口(上面已经说过)
beanDefinitionReader.setResourceLoader(this);
//设置实体解析器,该ResourceEntityResolver还是用ResourceLoader接收的this
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
//对defintionReader进行初始化操作,运训子类进行覆盖,然后开始进行实际加载bean definition
initBeanDefinitionReader(beanDefinitionReader);
//重点!!!进行BeanDefinitions的加载操作
loadBeanDefinitions(beanDefinitionReader);
}
// 这里进入关键方法loadBeanDefinitions,该方法实现于:void org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//取得ClassPathResource并进行加载
Resource[] configResources = getConfigResources();
if (configResources != null) {
//标识位置:loadBeanDefinitions_Resource
reader.loadBeanDefinitions(configResources);
}
//取得ConfigLocations并进行加载(这里的ConfigLocations就是上面解析出来的String[] configLocations,存储着配置文件的路径)
String[] configLocations = getConfigLocations();
if (configLocations != null) {
//标识位置:loadBeanDefinitions_String
reader.loadBeanDefinitions(configLocations);
}
}
// 这里的loadBeanDefinitions_String和loadBeanDefinitions_Resource进行加载的方法是一样的,都是调用int org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException
// 进行加载。只是loadBeanDefinitions_String在进行加载之前多了一步操作,把String转化为Resource,然后进行加载,这里就从loadBeanDefinitions_String跟进去
// 进入loadBeanDefinitions方法,该方法实现于:int org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
for (String location : locations) {
//循环对locations进行加载
counter += loadBeanDefinitions(location);
}
return counter;
}
//进入loadBeanDefinitions,该方法实现于:int org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(String location) throws BeanDefinitionStoreException
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
//继续调用加载
return loadBeanDefinitions(location, null);
}
//进入loadBeanDefinitions,该方法实现于: int org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//还记得这个resourceLoader什么时候赋值的吗?赋值的又是谁呢?AbstractXmlApplicationContext
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
//这里根据resourceLoader进行划分,不同的resourceLoader从不同的源加载resource。
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
//把resource进行缓存
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
//只能加载从绝对URL加载单例资源,xml走的是这里,进入之后区分类路径资源、URL资源和文件系统资源(xml属于该种),这里不再对封装resource进行分析
Resource resource = resourceLoader.getResource(location);
//进行记载definition,这里调用的方法和标识位置:loadBeanDefinitions_Resource调用的加载方法就相同了
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
//把resource进行缓存
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
//进入loadBeanDefinitions,该方法实现于:int org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException
//当前进行加载的resources存储于这个ThreadLocal线程局部变量中
private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded = new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded");
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
//操作之前先把currentResources放在resourcesCurrentlyBeingLoaded中,注意下面加载操作完成之后进行了remove
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
//这里把encodedResource放进currentResources中,后面依旧会remove
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//获取inputStream
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
//封装为InputSource
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
//为inputSource设置resource的编码方式
inputSource.setEncoding(encodedResource.getEncoding());
}
//这里才是真正进行BeanDefinitions的加载操作,前面的都是进行预处理封装inputSource
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
//操作之后把currentResources从resourcesCurrentlyBeingLoaded中移除出去,注意上面加载操之前的add
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
// 进入doLoadBeanDefinitions,该方法实现于:int org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//关键方法两步:取得Document;注册BeanDefinition
//这里就不再解析怎么加载Document的了,Spring是使用SAX进行xml解析的,可以自己详细了解
Document doc = doLoadDocument(inputSource, resource);
//把BeanDefinition注册到context中
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
// 进入registerBeanDefinitions,该方法实现于: int org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建documentReader这里返回的是 return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(this.getEnvironment());
//这个countBefore是为了统计从Document中加载的beanDefinition的个数
int countBefore = getRegistry().getBeanDefinitionCount();
//进行注册BeanDefinition操作
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
// 进入registerBeanDefinitions,该方法实现于:void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
//取出root节点,从root节点遍历所有节点进行注册
doRegisterBeanDefinitions(root);
}
// 进入doRegisterBeanDefinitions,该方法实现于:void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element root)
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(this.readerContext, root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
Assert.state(this.environment != null, "Environment must be set for evaluating profiles");
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
//为子类预留,覆写进行解析之前的特殊操作
preProcessXml(root);
//通过代理进行解析
parseBeanDefinitions(root, this.delegate);
//为子类预留,覆写进行解析之后的特殊操作
postProcessXml(root);
this.delegate = parent;
}
// 进入postProcessXml,该方法实现于:void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
//循环所有的Element节点进行解析
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
// 进入postProcessXml,该方法实现于: void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//对“import”标签进行解析注册
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//对“alias”标签进行解析注册
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//对“bean”标签进行解析注册,这里从这里面进去分析,这里的分支思路大同小异
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//对“beans”标签进行解析注册
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
// 进入processBeanDefinition,该方法实现于: void org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//对ele进行解析,把id、name、aliases进行封装
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//如果需要则使用bdHolder的代理进行操作
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
//对definition的最终注册,注意该方法的第二个参数:Registry
//设置readerContext位置:documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//设置Registry位置(第五个参数this):return new XmlReaderContext(resource, this.problemReporter, this.eventListener,this.sourceExtractor, this, getNamespaceHandlerResolver());
//该this指代的是XmlBeanDefinitionReader实例
//而他的Registry设置位置是:XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//所以该Registry就是beanFactory
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
//发送注册event给监听者
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
// 进入BeanDefinitionReaderUtils.registerBeanDefinition,该方法实现于: void org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {
// Register bean definition under primary name.
//取得beanName注册beanDefinition
String beanName = definitionHolder.getBeanName();
//注册beanDefinition
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
//取得对该beanName注册aliases,这里关联的是aliases--beanName,所以通过aliase进行取值的时候需要先由aliase找到beanName,然后根据beanName找到beanDefinition
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String aliase : aliases) {
registry.registerAlias(beanName, aliase);
}
}
}
// 进入registerBeanDefinition.registerBeanDefinition,该方法实现于:void org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException
//注意该方法的实现位置:DefaultListableBeanFactory
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name 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);
}
}
BeanDefinition oldBeanDefinition;
//加锁同步
//注意该上面的beanDefinitionMap
synchronized (this.beanDefinitionMap) {
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
//如果已经存在该beanDefinition则判断是否允许覆盖
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
" with a framework-generated bean definition ': replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {
//如果不存在该bean则注册beanName
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
//把bean加入缓存beanDefinitionMap,这里完成注册
this.beanDefinitionMap.put(beanName, beanDefinition);
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
//重置该beanDefinition的所有缓存 Reset all bean definition caches for the given bean
resetBeanDefinition(beanName);
}
}
//至此,beanFactory构建完成, ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();结束。
beanFactory创建完成之后,缓存中已经存储有配置bean的beanDefinition。
在void org.springframework.context.support.AbstractApplicationContext.refresh() throws BeansException, IllegalStateException中的其他方法是对beanFactory以及context的其他操作,主要是为子类覆写一些方法、注册一些监听、处理一下国际化资源文件等,这里就不再进行详细分析。
至此,该方法中的context 创建完成。
public class SpringTest {
public static void main(String[] args) {
//获取context上下文对象,该上下文是ClassPathXmlApplicationContext类
ApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
//从容器中取出名为"person"的对象
Person person = context.getBean("person", Person.class);
//调用person.info()方法。
person.info();
}
}
spring用着方便,但是实现起来确实很复杂,里面涉及了大量的设计模式,装饰模式、代理模式、工厂模式、模板方法等,对于学习系统设计有很大的帮助。
文章中只简单的介绍了一下beanFactory的创建,其中忽略了大量的细节,比如对单利bean的管理,beanDefinition到bean的创建,此外,对beanFactory的后期处理,Listeners的添加、MessageSource的初始化等。有兴趣的朋友可以深入研究一下,这里就不再继续分析,能力有限,很多东西我也不是太明白,还需要继续学习。建议刚接触该模块源码的朋友一定要多进行debug读源码,对源码进行分析,如果能在熟练使用sping的基础上读源码效果会更好,最好自己亲自绘制一下该模块的类图,这样可以对该模块的整体结构有一个比较清晰的认识,对上面的九个关键的类系就能够有更好的理解。
在学习的过程中遇到一本讲解比较详细的书,这里分享给大家,里面还有绘制的相关类图,用powerdesigner进行打开。
链接在此:学习资源分享 文件名分别为:spring源码深度解析 spring-IOC相关类图
------over
转:https://www.cnblogs.com/PerkinsZhu/p/6500837.html
相关推荐
Spring5 框架 ---- IOC容器 ---- 代码 Spring5 框架 ---- IOC容器 ---- 代码 Spring5 框架 ---- IOC容器 ---- 代码 Spring5 框架 ---- IOC容器 ---- 代码 Spring5 框架 ---- IOC容器 ---- 代码 Spring5 框架 ---- ...
Spring IOC,全称为Inversion of Control,中文常被称为“控制反转”,是Spring框架的核心特性之一。这个概念在软件设计中引入了一种新的依赖管理方式,它将对象的创建和管理权交给了容器,使得开发者可以更专注于...
IoC是一种设计模式,它的核心理念在于将对象的创建和依赖关系的维护从应用程序代码中解耦出来,交由一个外部容器(在Spring中就是ApplicationContext)来管理。这样做的好处包括提高代码的可测试性、灵活性和可维护...
Spring IoC通过XML配置文件实现了对象的实例化和依赖注入,有效地降低了对象间的耦合,提高了代码的可读性和可维护性。理解并熟练运用Spring的IoC机制是成为一名优秀的Java开发者的关键步骤之一。在实际项目中,结合...
Java Spring代理模式AOP-IOC分析 一、代理模式概述 在软件设计中,代理模式是一种常用的设计模式。它可以在不修改原始代码的情况下,扩展或修改原始对象的行为。代理模式可以分为静态代理和动态代理两种。静态代理...
总之,"spring-demo02-IOC-DI案例"是一个很好的实践平台,帮助开发者深入理解并掌握Spring框架的核心特性,提高代码的可维护性和可扩展性。通过研究和实践这个案例,你将能够更好地应用这些知识到实际的项目开发中。
**Spring技术--IOC控制反转** 在Java开发领域,Spring框架以其...总之,Spring的IOC技术通过控制反转和依赖注入,提高了代码的可维护性和可扩展性,降低了系统复杂性,是现代Java企业级应用开发中不可或缺的一部分。
02_spring核心技术-IOC.ppt
spring-IOC的一些笔记心得
Spring是Java领域广泛应用的一个轻量级开源框架,它的核心特性就是IoC,它使得应用程序的组件之间解耦,提高了代码的可测试性和可维护性。 在描述中提到的“对应博客资源,免费下载”可能意味着这个压缩包包含了某...
Spring框架-IoC实现CRUD
023-spring-ioc-ioc容器的bean获取三种方式.mp4 024-spring-ioc-扩展组件周期方法.mp4 025-spring-ioc-扩展作用域配置.mp4 026-spring-ioc-扩展factoryBean使用.mp4 027-spring-ioc-三层架构组件管理介绍和...
023-spring-ioc-ioc容器的bean获取三种方式.mp4 024-spring-ioc-扩展组件周期方法.mp4 025-spring-ioc-扩展作用域配置.mp4 026-spring-ioc-扩展factoryBean使用.mp4 027-spring-ioc-三层架构组件管理介绍和...
023-spring-ioc-ioc容器的bean获取三种方式.mp4 024-spring-ioc-扩展组件周期方法.mp4 025-spring-ioc-扩展作用域配置.mp4 026-spring-ioc-扩展factoryBean使用.mp4 027-spring-ioc-三层架构组件管理介绍和...
023-spring-ioc-ioc容器的bean获取三种方式.mp4 024-spring-ioc-扩展组件周期方法.mp4 025-spring-ioc-扩展作用域配置.mp4 026-spring-ioc-扩展factoryBean使用.mp4 027-spring-ioc-三层架构组件管理介绍和...
Spring-IoC容器
虽然AOP不在本次讨论的"Spring--IOC"主题内,但它是Spring框架的另一个重要特性,它允许我们在不修改已有代码的情况下,添加横切关注点,如日志、事务管理等。 **MyEclipse5.5开发平台** MyEclipse5.5是一款基于...
标题“Spring-MVC+Spring-IOC+Spring-JdbcTemple”揭示了这个项目或教程是关于如何集成并使用Spring框架的三个核心模块:Spring MVC、Spring IOC(Inversion of Control,控制反转)以及Spring JDBC Template。...
注解是Java语言提供的一种元数据机制,允许我们在源代码中嵌入信息,这些信息可以被编译器或者运行时环境解析和使用。Spring框架充分利用了这一特性,提供了一系列注解来简化配置,使得我们可以避免使用XML配置文件...
spring-ioc学习 新手可以下过来学习下, spring-ioc简介