Spring 源码理解(一)

基于上一篇博客的小demo, 我通过debug看了下spring 大概的工作流程,做了点小笔记:

package com.test.main;

		import com.test.app.Appconfig;
		import com.test.dao.TestDao;
		import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
	public static void main(String[] args) {
		/**
		 * AnnotationConfigApplicationContext (后面用 registry 代称) 构造器中做了以下事情:
		 * 1. 父类构造器里初始化了一个 DefaultListableBeanFactory,包含一个beanDefinitionMap 和一个 beanDefinitionNames
		 * 2. 构造了一个reader
		 * 		2.1 reader 构造器里,注册若干个后置处理器 (详情查看AnnotationConfigUtils.registerAnnotationConfigProcessors())
		 * 3. 构造了一个scanner
		 * 4. 把registry构造方法传入的class (e.g.Appconfig.class)作为bean 也注册到 registry 的 DefaultListableBeanFactory中
		 * 5. refresh()// TODO
		 *
		 * 注意:
		 * #2.1注册后置处理器 和 #4 注册Appconfig 都是
		 * 通过 registry.registerBeanDefinition(beanName, definition); 放入到registry的 defaultListableBeanFactory中的beanDefinitionMap的
		 *
		 * */
		AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class); //把spring所有的前提环境准备好
		TestDao testDao = annotationConfigApplicationContext.getBean(TestDao.class);
		testDao.query();
	}
}

 

关键字理解:

1. BeanDefinition

Java 中的class 用类Class 表示  <-----> Spring中的bean 用类BeanDefinition表示

BeanDefinition中存了bean的定义信息。比如: 类名、scope、属性、构造函数参数列表、是否是单例类、是否是懒加载等

BeanDefinition 一定是Class, 但Class 不一定是BeanDefinition

Spring 内的bean来源于:

  1. spring 内部的bean
  2. @annotation 添加该注解的类会被Spring 识别为bean
  3. @bean 添加该注解的方法返回的类会被Spring 识别为bean
  4. <bean> 在XML中通过bean 标签定义的类会被Spring 识别为bean

2. BeanDefinitionHolder

是一个类似于map的数据结构,key是一个BeanDefinition对象,value是BeanDefinition对应的bean name。用于方便中间传值封装的一个对象,最后key和value 分别会被放到spring bean工厂的bean map中

3. DefaultListableBeanFactory

是整个bean加载的核心,是spring注册bean及加载bean的默认实现。

 

以下问题通过阅读源码得到了证实:

1. 如果单例类中注入了原型(prototype 类型)的对象,这样元型对象就失去了意义。2种解决办法:

  • 添加注解@lookup。 在单例类中新加一个带有该注解的方法。被该标注的方法会被重写,然后根据其返回值的类型,Spring容器调用BeanFactory的getBean()方法来返回一个bean。
package com.test.dao;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;

@Repository
@Scope("prototype")
public class TestDao2 {
	public void query(){
		System.out.println("This is TestDao2...");
	}
}
package com.test.dao;

import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.stereotype.Repository;


@Repository
public class TestDao { ;

	public void query(){
		System.out.println("Hello Spring!");
		System.out.println(getTestDao2().hashCode());
	}

	@Lookup
	public TestDao2 getTestDao2(){
		return null;
	}
}
  • 放弃依赖注入,让单例类实现接口ApplicationContextAware,并重写方法setApplicationContext 拿到 ApplicationContext 对象,然后便可以通过ApplicationContext.getBean("beanname")每次拿到一个新对象。
package com.test.dao;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Repository;
;

@Repository
public class TestDao implements ApplicationContextAware {

	ApplicationContext applicationContext;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	public void query(){
		System.out.println("Hello Spring!");
		System.out.println(applicationContext.getBean("testDao2").hashCode());
	}

}

方法2 的原理是通过ApplicationContextAwareProcessor Bean后置处理器实现的。这个后置处理器在Bean初始化之后去检查该bean是否继承了接口ApplicationContextAware,如果继承了就调用bean的setApplicationContext 方法把ApplicationContext  传给该bean

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值