跟孙哥学java
Spring源码的环境搭建
引入源码环境——-->可以让我们加注释 但是缺点是-->我们需要编译--->费时间
实际上---学习源码的过程,有没有源码环境区别不大
导入源码
:::info
- 获取Spring源码 github
git clone github.com/spring-proj…
- Spirng 5.x-->从使用maven 改为gradle
spring 5.x版本自动搭建环境是 下载gradle
引入aliyun镜像 build.gradle
repositories {
maven { url 'maven.aliyun.com/repository/… }
maven { url 'maven.aliyun.com/repository/…
maven { url "repo.spring.io/libs-spring… }
mavenCentral()
}
- IDEA导入Spring Project
- Build :::
Spring源码的核心--工厂(容器)
ApplicationContext(高级工厂)
编程过程中的一个门面--->类似于Mybatis SqlSession-->使用这个就可以操作数据库
Sping中最底层的工厂-->BeanFactory-->The root interface for accessing a Spring bean container.
而ApplicationContext 是集成工厂-->一个最大功能的类型
Spring如何读取XML配置文件
public class Test1 {
public static void main(String[] args) {
BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("applicationcontext.xml"));
User user = (User) beanFactory.getBean("user");
System.out.println(user);
}
}
1.new ClassPathResource 读取配置文件的
2.Resource-接口 -目的---> 读取相关配置文件,获得输入流--InputSteamSource
文件(xml,properties,txt)/网络中的数据
从这行代码开始分析-->进入到这个类中,看看它的构造方法---
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
//我们刚刚创建BeanFactory 所用的构造方法
//形参:resource – 要从中加载 Bean 定义的 XML 资源
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
//重载方法---多了一个参数——--父工厂:BeanFactory parentBeanFactory
//我们创建的这个父工厂为空
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
//所以实际上构造方法调用的是这个方法--->进入这个方法
this.reader.loadBeanDefinitions(resource);
}
进入XmlBeanDefinitionReader---中loadBeanDefinitions()方法
/*
从指定的 XML 文件装入 Bean 定义。
形参:resource – XML 文件的资源描述符
返回值:找到的 Bean 定义数
*/
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//new EncodedResource(resource))对Resource进一步封装
//实际上只是套了个壳子
return loadBeanDefinitions(new EncodedResource(resource));
}
继续进入loadBeanDefinitions()方法
/*
从指定的 XML 文件装入 Bean 定义。
形参:encodedResource – XML 文件的资源描述符,允许指定用于解析文件的编码
返回值: 找到的 Bean 定义数
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//这里主要看这个方法,上面的都是日志输出和一些判断
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
直接进入真正的读取XML方法 doLoadBeanDefinitions(InputSource inputSource, Resource resource)
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
//使用SAX 读取xml配置文件到Document对象中--->Spring再对他进行读取封装
//因为Spring操作Document不方便
Document doc = doLoadDocument(inputSource, resource);
//注册bean,并且放回注册bean的个数
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
然后就进入registerBeanDefinitions(doc, resource);这个方法
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//读取注册中心里面之前bean的个数
int countBefore = getRegistry().getBeanDefinitionCount();
//真正执行注册的方法
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//读取注册了xml中的bean的个数-之前的个数=新增bean的个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
进入registerBeanDefinitions
@SuppressWarnings("deprecation") // for Environment.acceptsProfiles(String...)
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(getReaderContext(), root, parent);
//读取默认命名空间-beans
if (this.delegate.isDefaultNamespace(root)) {
//读取profile--->多环境 dev,build
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
//就解析配置文件
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
parseBeanDefinitions--->
//解析文档根级别的元素:“import”、“alias”、“bean”。
//形参:root – 文档的 DOM 根元素
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//判断是否为beans下的标签
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)) {
//解析标签
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
---》parseDefaultElement
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);
}
//解析NESTED_BEANS_ELEMENT
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
我们主要看如何解析bean标签--->processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 将读取的ele变成文件对象--->BeanDefinitionHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
--->parseBeanDefinitionElement--->解析bean标签为bean文件对象-->Spring容易操作的对象
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
//解析id
String id = ele.getAttribute(ID_ATTRIBUTE);
//解析别名
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
//判断是否设置别名
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
//如果id未设置且设置了别买——->拿出别名的第一个设置为id
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
//判断是否id或别名与其他bean重复了
checkNameUniqueness(beanName, aliases, ele);
}
//读取class ,parent 等其他标签
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
//未设置别名和id-->默认设置一个id
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}