Java 自定义Spring框架与核心功能详解
作者:李阿昀
在上一讲中,我们对Spring的基本使用进行了一个简单的回顾,接下来,我们就来看一下Spring核心功能结构。
Spring核心功能结构
Spring大约有20个模块,由1300多个不同的文件构成,而这些模块可以分为下面几部分:
- 核心容器
- AOP和设备支持
- 数据访问与集成
- Web组件
- 通信报文
- 集成测试
- ······
下面这张图就是Spring框架的总体架构图。
接下来,我就带领着大家逐一看一下Spring里面的这些模块。
核心容器
核心容器由Beans、Core、Context和Expression(Spring Expression Language,SpEL)4个模块组成。
spring-beans和spring-core模块
spring-beans和spring-core模块是Spring框架的核心模块,包含了控制反转(Inversion of Control,IoC)和依赖注入(Dependency Injection,DI)。
这俩模块里面有一个核心接口叫BeanFactory,为什么说它是核心接口呢?因为Spring IoC里面有一个很重要的概念,那就是容器,而BeanFactory接口定义的就是容器共有的功能,很显然,BeanFactory就是容器对象顶层接口。下面,我们不妨再来重新认识一遍BeanFactory。
BeanFactory使用控制反转对应用程序的配置和依赖性规范与实际的应用程序代码进行了分离。大家要知道,bean以及依赖的管理,我们都是在Spring的配置文件里面进行配置的,这样,是不是就能大大降低程序之间的耦合啊?
BeanFactory属于延时加载,也就是说在实例化容器对象后并不会自动实例化bean,只有当bean被使用时,BeanFactory才会对该bean进行实例化与依赖关系的装配。这句话什么意思呢?我们不妨先回到咱们的Maven工程(即spring_demo)中,然后再通过代码演示来理解一下这句话。现在我们创建Spring的容器对象就不再使用ApplicationContext接口了,而是来使用BeanFactory接口,如下所示。
package com.meimeixia.controller; import com.meimeixia.service.UserService; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.io.ClassPathResource; /** * @author liayun * @create 2021-09-19 18:41 */ public class UserController { public static void main(String[] args) throws Exception { // 1. 创建Spring的容器对象 // ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); // 2. 从容器对象中获取UserService对象 UserService userService = beanFactory.getBean("userService", UserService.class); // 3. 调用UserService对象的方法进行业务逻辑处理 userService.add(); } }
以上UserController类的代码修改完毕之后,我们并不会看到延时加载的效果,为了看到延时加载的效果,我们还得分别在UserDaoImpl和UserServiceImpl这俩类里面提供一个无参构造方法,因为bean在实例化的时候,肯定是要调用其构造方法的。
- UserDaoImpl类:
package com.meimeixia.dao.impl; import com.meimeixia.dao.UserDao; /** * 数据访问层实现类 * @author liayun * @create 2021-09-19 18:29 */ public class UserDaoImpl implements UserDao { public UserDaoImpl() { System.out.println("userDao被创建了"); } @Override public void add() { System.out.println("UserDao..."); } }
- UserServiceImpl类:
package com.meimeixia.service.impl; import com.meimeixia.dao.UserDao; import com.meimeixia.service.UserService; /** * 业务逻辑层实现类 * @author liayun * @create 2021-09-19 18:37 */ public class UserServiceImpl implements UserService { // 因为业务逻辑层是要调用数据访问层中的功能的,所以在这儿我们得声明一个UserDao类型的变量 private UserDao userDao; // 注意了,这儿我们并没有为该变量进行赋值,赋值的操作得交给Spring去做,只是这样做的前提是我们得为该变量提供一个setter方法 public void setUserDao(UserDao userDao) { this.userDao = userDao; } public UserServiceImpl() { System.out.println("userService被创建了"); } @Override public void add() { System.out.println("UserService..."); userDao.add(); } }
为了方便大家看到延时加载的效果,于是我在UserController类的如下代码处打上了一个断点,然后我会以Debug的方式来运行UserController类的代码。
此时,程序肯定是要停留在断点处的,然后我们按下F6
键让程序再往下运行一行代码,当你切换到控制台时,你会发现控制台并没有任何打印结果,如下图所示。
现在容器对象已经实例化完了,而且我们还为UserDaoImpl和UserServiceImpl这俩类提供了一个无参构造方法,照理来说,此时应该自动实例化bean的(就是自动创建UserDaoImpl和UserServiceImpl这俩类的对象),我们应该能够看到控制台中会打印相应结果的,因为创建UserDaoImpl和UserServiceImpl这俩类的对象,就必须得调用其无参构造。但是,控制台我们没有看到任何打印结果,这就说明在实例化容器对象后并不会自动实例化bean,原因正是BeanFactory属于延时加载。
那什么时候实例化bean呢?使用容器对象里面的getBean方法获取对应的对象时就会实例化bean了,当然了,并不是我们自个去实例化,而是Spring帮我们去实例化。所以,当你按下F6
键让程序再往下运行一行代码之后,你就能够看到控制台中会打印相应结果了,如下图所示。
足以证明只有当bean被使用时,BeanFactory才会对该bean进行实例化与依赖关系的装配!OK,这里就给大家演示完了BeanFactory的延时加载。
spring-context模块
spring-context模块构架于核心模块(即spring-beans和spring-core这俩模块)之上,扩展了BeanFactory,为它添加了bean生命周期控制、框架事件体系及资源加载透明化等功能。此外,该模块还提供了许多企业级支持,如邮件访问、远程访问、任务调度等。
大家注意了,ApplicationContext是该模块的核心接口,它的超类是BeanFactory,也就是说它是BeanFactory的子接口。与BeanFactory不同,ApplicationContext实例化后会自动对所有的单实例bean进行实例化与依赖关系的装配,使之处于待用状态。
这又是啥子意思呢?还是回到咱们的Maven工程(即spring_demo)中,这里我依旧通过代码来给大家进行演示。现在我们创建Spring的容器对象还是使用ApplicationContext接口了,如下所示。
package com.meimeixia.controller; import com.meimeixia.service.UserService; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.io.ClassPathResource; /** * @author liayun * @create 2021-09-19 18:41 */ public class UserController { public static void main(String[] args) throws Exception { // 1. 创建Spring的容器对象 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); // BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); // 2. 从容器对象中获取UserService对象 UserService userService = applicationContext.getBean("userService", UserService.class); // 3. 调用UserService对象的方法进行业务逻辑处理 userService.add(); } }
依旧在UserController类的如下代码处打上了一个断点,然后以Debug的方式来运行UserController类的代码。
此时,程序肯定是要停留在断点处的,然后我们按下F6
键让程序再往下运行一行代码,当你切换到控制台时,你会发现现在控制台有打印结果了,如下图所示。
这也就是说在实例化容器对象后就会自动实例化bean,我想大家也应该猜到原因了,就是与BeanFactory相反,ApplicationContext属于非延时加载。所以,这里大家一定要非常清楚BeanFactory和ApplicationContext的区别。
spring-context-support模块
spring-context-support模块是对Spring IoC容器及IoC子容器的扩展支持。
这里面涉及到了一个IoC子容器,想必大家都用过Spring MVC吧!它和Spring就牵扯到了一个父容器和子容器的关系,当然,这一块我们不做重点说明啊!
spring-context-indexer模块
spring-context-indexer模块是Spring的类管理组件和Classpath扫描组件。
想必大家都知道,如果我们在配置文件里面配置了一个组件扫描的话,那么它就会自动去扫描对应类路径下面的那些类有没有对应的注解。
spring-expression模块
spring-expression模块是统一表达式语言(EL)的扩展模块,可以查询、管理运行中的对象,同时也可以方便地调用对象方法,以及操作数组、集合等。它的语法类似于传统EL,但提供了额外的功能,最出色的要数函数调用和简单字符串的模板函数。EL的特性是基于Spring产品的需求而设计的,可以非常方便地同Spring IoC进行交互。
AOP和设备支持
用过Spring框架的话,那么你肯定用过AOP,相信你应该也是比较熟悉的,所以这里我就不再做过多赘述了。
数据访问与集成
其实,数据访问与集成这一模块说白了就是对Dao层进行封装的一个组件。
Web组件
对Web层进行封装的组件。
通信报文
从以上Spring框架的总体架构图中可以看到,Messaging代表的就是通信报文,这里我只是提一嘴。
集成测试
从以上Spring框架的总体架构图中可以看到,Test代表的就是集成测试,说白了就是Spring集成JUnit来进行单元测试。
当然了,Spring框架里面肯定还有一些其他模块,但我在这里不可能一一列出来,于是就只挑了如上几个模块来说了一下,其中要重点关注核心容器这一模块。
bean概述
接下来,我来为大家讲一讲Spring中的bean,因为bean对于Spring来说特别特别重要,所以我单独把它拿过来给大家讲一讲。
Spring就是面向bean的编程(简称BOP,Bean Oriented Programming),bean在Spring中处于核心地位。bean对于Spring的意义就像Object对于OOP的意义一样,如果Spring中没有了bean,那么也就没有Spring存在的意义了。Spring IoC容器通过配置文件或者注解的方式来管理bean对象之间的依赖关系。
接下来,我们来看一下什么是bean?
Spring中bean用于对一个类进行封装。如下面的配置:
<bean id="userDao" class="com.meimeixia.dao.impl.UserDaoImpl"></bean> <bean id="userService" class="com.meimeixia.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"></property> </bean>
你会发现以上配置中用到了两个<bean>
标签,而每一个<bean>
标签就代表着一个bean。就拿第一个<bean>
标签来说,id属性的值就是bean对象的名称,而class属性的值就是bean对象所属类的全限定类名。为什么要声明这俩属性呢?因为Spring底层在去创建bean对象时,是通过反射的方式根据全限定类名去创建该类的对象的。
为什么bean如此重要呢?这是因为:
- Spring将bean对象交由一个叫IoC的容器进行管理。也就是说IoC容器是以bean对象为单位来进行管理的。
- bean对象之间的依赖关系在配置文件中体现,并由Spring完成。
这里,我们简单地去聊了一下Spring中的bean,对于bean,大家应该还是要知道一点的。
到此这篇关于Java 自定义Spring框架与核心功能详解的文章就介绍到这了,更多相关Java 自定义Spring框架内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!