《Spring使用到源码理解》第一章:Spring容器理解和使用(xml版本)

1. 什么是容器

大家在使用spring框架时,其实一直都在跟容器打交道,比如我们使用@Autowired注解时,就是从容器中获取到对应的对象的,也使用bean标签可以向容器中注册对象。其实我们可以把容器理解成一个“桶”,这个“桶”里面装的就是我需要使用的对象。

2. 带着疑问阅读

  • 什么是容器?
  • 如果构建spring容器?
  • 什么是bean定义?
  • bean注册的大体流程是怎么样的?

3.基础使用

3.1 构建一个基于xml的spring容器

创建一个需要交给容器管理java类

public class UserServiceImpl{
   public String getName(){
   		return "普通用户->张三";
   }
}

构建application-base.xml将其放在resource目录下,该xml中使用bean标签向容器中注册UserServiceImpl的定义对象(bean标签、如何注册、定义对象如何不清楚没关系,后面会一一解释的)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
   	https://www.springframework.org/schema/beans/spring-beans.xsd">
   <bean id="userServiceImpl" class="com.qiupeng.bean.base.service.Impl.UserServiceImpl" />
</beans>

定义一个测试函数

public class BeanBaseTest{
   private static final Logger logger = LogManager.getLogger(BeanBaseTest.class);
   public static void main(String[] arg){
   	       ApplicationContext context = new ClassPathXmlApplicationContext(“classpath:application-base.xml”);
   	       UserServiceImpl userServiceImpl = context.getBean("userServiceImpl",UserServiceImpl.class);
   	       logger.info(userServiceImpl.getName());
   	       Arrays.stream(context.getBeanDefinitionNames()).forEach(logger::info);
   } 
}

最终输出

[INFO ] 2023-06-15 14:25:41,090 com.qiupeng.bean.base.BeanBaseTest - 普通用户->张三
[INFO ] 2023-06-15 14:25:41,097 com.qiupeng.bean.base.BeanBaseTest - userServiceImpl

通过上述例子就已经完成一个容器的构建,已经实现了bean的注册和使用流程。

3.2 执行流程

通过创建一个 ClassPathXmlApplicationContext 对象并且传入一个xml,就能构建一个基于xml的容器对象了。我画了一个图帮助大家理解流程。
在这里插入图片描述

在图中可以看出,首先是一个“bean定义的生成工厂”,从xml中读取需要使用bean标签,然后在将其转为bean定义对象,在存入到容器中,我们可以使用以下个代码进行验证。

public class BeanBaseTest {
   private static final Logger logger = LogManager.getLogger(BeanBaseTest.class);
   public static void main(String[] arg){
			GenericApplicationContext context = new GenericApplicationContext();
			new XmlBeanDefinitionReader(context).loadBeanDefinitions("classpath:application-base.xml");
			context.refresh();
			UserServiceImpl userServiceImpl = context.getBean("userServiceImpl",UserServiceImpl.class);
			logger.info(userServiceImpl.getName());
   	    Arrays.stream(context.getBeanDefinitionNames()).forEach(logger::info);
	}
}

最终输出

[INFO ] 2023-06-15 14:25:41,090 com.qiupeng.bean.base.BeanBaseTest - 普通用户->张三
[INFO ] 2023-06-15 14:25:41,097 com.qiupeng.bean.base.BeanBaseTest - userServiceImpl

上述代码中创建了一个GenericApplicationContext 容器对象,再构建了一个XmlBeanDefinitionReader加载xml的“bean定义的生成工厂”,输出和上一个例子是样的。

4.总结

  • 容器其实就是一个存储bean对象的“桶”。
  • 可以使用ClassPathXmlApplicationContext或者GenericApplicationContext快速构建容器。(其实构建容器的方式还有很多后面会一一介绍)。
  • bean定义其实是就是一个存储class的属性的一个中间对象,容器通过这个中间对象来生成对应对象实例。(在srping中BeanDefinition就是bean定义对象)。
  • bean加载流程:原始数据(xml等)=> “bean定义的生成工厂”=>bean定义=>容器=>实例化

5. 扩展知识

通过上述文章的理解,容器必须基于xml吗?
其实很显然不是,我们可以自己来构建“bean定义的加工厂”来生成对应bean定义对象,接下来我们就来实现一个基于txt的容器。

构建一个bean定义生成工厂

public class TxtBeanDefinitionReader extends AbstractBeanDefinitionReader {
   public MyBeanDefinitionReader(BeanDefinitionRegistry registry) {
   	super(registry);
   }
   @Override
   public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
   	//获取bean容器
   	BeanDefinitionRegistry registry = getRegistry();
   	//记录初始化beanDefinition数量
   	int count = 0;
   	String contentAsString = "";
   	try {
   		if (resource.isOpen()) {
   			contentAsString = resource.getContentAsString(StandardCharsets.UTF_8);
   			resource.getInputStream().close();
   		} else {
   			contentAsString = resource.getContentAsString(StandardCharsets.UTF_8);
   		}
   	} catch (IOException e) {
   		e.printStackTrace();
   	}
   	String[] split = contentAsString.split("\r\n");
   	for (String classPath : split) {
   		if (createBeanDefinition(classPath, registry) != null) {
   			count++;
   		}
   	}
   	return count;
   }
   public RootBeanDefinition createBeanDefinition(String classPath, BeanDefinitionRegistry registry) {
   	try {
   		String[] beanData = classPath.split(",");
   		if (beanData.length != 2) {
   			return null;
   		}
   		Class<?> aClass = Class.forName(beanData[0]);
   		RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
   		rootBeanDefinition.setBeanClass(aClass);
   		registry.registerBeanDefinition(beanData[1], rootBeanDefinition);
   		return rootBeanDefinition;
   	} catch (ClassNotFoundException e) {
   		e.printStackTrace();
   	}
   	return null;
   }
}

创建一个txtBean.txt文件,该文件中存储了class全路径和bean的id,使用“,”进行分割。

com.qiupeng.bean.base.service.Impl.UserServiceImpl,userServiceImpl

创建测试类

public class BeanBaseTest {
	private static final Logger logger = LogManager.getLogger(BeanBaseTest.class);
	public static void main(String[] arg){ 
		GenericApplicationContext context = new GenericApplicationContext();
		new MyBeanDefinitionReader(context).loadBeanDefinitions("txtBean.txt");
		context.refresh();
		UserServiceImpl userServiceImpl = context.getBean("userServiceImpl",UserServiceImpl.class);
		logger.info(userServiceImpl.getName());
		Arrays.stream(context.getBeanDefinitionNames()).forEach(logger::info);
	}
}

最终输出

[INFO ] 2023-06-15 14:25:41,090 com.qiupeng.bean.base.BeanBaseTest - 普通用户->张三
[INFO ] 2023-06-15 14:25:41,097 com.qiupeng.bean.base.BeanBaseTest - userServiceImpl

上述代码就是通过txt配置bean对象,在通过自己编写的”bean定义生成工厂“来构建bean定义对象,然后注册到容器中去。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
第1章:对Spring框架进行宏观性的概述,力图使读者建立起对Spring整体性的认识。   第2章:通过一个简单的例子展现开发Spring Web应用的整体过程,通过这个实例,读者可以快速跨入Spring Web应用的世界。   第3章:讲解Spring IoC容器的知识,通过具体的实例详细地讲解IoC概念。同时,对Spring框架的三个最重要的框架级接口进行了剖析,并对Bean的生命周期进行讲解。   第4章:讲解如何在Spring配置文件中使用Spring 3.0的Schema格式配置Bean的内容,并对各个配置项的意义进行了深入的说明。   第5章:对Spring容器进行解构,从内部探究Spring容器的体系结构和运行流程。此外,我们还将对Spring容器一些高级主题进行深入的阐述。   第6章:我们从Spring AOP的底层实现技术入手,一步步深入到Spring AOP的内核中,分析它的底层结构和具体实现。   第7章:对如何使用基于AspectJ配置AOP的知识进行了深入的分析,这包括使用XML Schema配置文件、使用注解进行配置等内容。   第8章:介绍了Spring所提供的DAO封装层,这包括Spring DAO的异常体系、数据访问模板等内容。   第9章:介绍了Spring事务管理的工作机制,通过XML、注解等方式进行事务管理配置,同时还讲解了JTA事务配置知识。   第10章:对实际应用中Spring事务管理各种疑难问题进行透彻的剖析,让读者对Spring事务管理不再有云遮雾罩的感觉。   第11章:讲解了如何使用Spring JDBC进行数据访问操作,我们还重点讲述了LOB字段处理、主键产生和获取等难点知识。   第12章:讲解了如何在Spring中集成Hibernate、myBatis等数据访问框架,同时,读者还将学习到ORM框架的混用和DAO层设计的知识。   第13章:本章重点对在Spring中如何使用Quartz进行任务调度进行了讲解,同时还涉及了使用JDK Timer和JDK 5.0执行器的知识。   第14章:介绍Spring 3.0新增的OXM模块,同时对XML技术进行了整体的了解。   第15章:对Spring MVC框架进行详细介绍,对REST风格编程方式进行重点讲解,同时还对Spring 3.0的校验和格式化框架如果和Spring MVC整合进行讲解。   第16章:有别于一般书籍的单元测试内容,本书以当前最具实战的JUnit4+Unitils+ Mockito复合测试框架对如何测试数据库、Web的应用进行了深入的讲解。   第17章:以一个实际的项目为蓝本,带领读者从项目需求分析、项目设计、代码开发、单元测试直到应用部署经历整个实际项目的整体开发过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值