体系结构

Spring 有可能成为所有企业应用程序的一站式服务点,然而,Spring 是模块化的,允许你挑选和选择适用于你的模块,不必要把剩余部分也引入。下面的部分对在 Spring 框架中所有可用的模块给出了详细的介绍。

Spring 框架提供约 20 个模块,可以根据应用程序的要求来使用。

核心容器

核心容器由spring-core,spring-beans,spring-context,spring-context-support和spring-expression(SpEL,Spring表达式语言,Spring Expression Language)等模块组成,它们的细节如下:

  • spring-core模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。

  • spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。

  • context模块建立在由core和 beans 模块的基础上建立起来的,它以一种类似于JNDI注册的方式访问对象。Context模块继承自Bean模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过Servelet容器)等功能。Context模块也支持Java EE的功能,比如EJB、JMX和远程调用等。ApplicationContext接口是Context模块的焦点。spring-context-support提供了对第三方库集成到Spring上下文的支持,比如缓存(EhCache, Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。

  • spring-expression模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是JSP2.1规范中定义的统一表达式语言的扩展,支持set和get属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从Spring IoC容器检索对象,还支持列表的投影、选择以及聚合等。

数据访问/集成

数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下:

(注:JDBC=Java Data Base Connectivity,ORM=Object Relational Mapping,OXM=Object XML Mapping,JMS=Java Message Service)

  • JDBC 模块提供了JDBC抽象层,它消除了冗长的JDBC编码和对数据库供应商特定错误代码的解析。

  • ORM 模块提供了对流行的对象关系映射API的集成,包括JPA、JDO和Hibernate等。通过此模块可以让这些ORM框架和spring的其它功能整合,比如前面提及的事务管理。

  • OXM 模块提供了对OXM实现的支持,比如JAXB、Castor、XML Beans、JiBX、XStream等。

  • JMS 模块包含生产(produce)和消费(consume)消息的功能。从Spring 4.1开始,集成了spring-messaging模块。。

  • 事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。(注:编程式事务需要自己写beginTransaction()、commit()、rollback()等事务管理方法,声明式事务是通过注解或配置由spring自动处理,编程式事务粒度更细)

Web

Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:

  • Web 模块提供面向web的基本功能和面向web的应用上下文,比如多部分(multipart)文件上传功能、使用Servlet监听器初始化IoC容器等。它还包括HTTP客户端以及Spring远程调用中与web相关的部分。。

  • Web-MVC 模块为web应用提供了模型视图控制(MVC)和REST Web服务的实现。Spring的MVC框架可以使领域模型代码和web表单完全地分离,且可以与Spring框架的其它所有功能进行集成。

  • Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。

  • Web-Portlet 模块提供了用于Portlet环境的MVC实现,并反映了spring-webmvc模块的功能。

其他

还有其他一些重要的模块,像 AOP,Aspects,Instrumentation,Web 和测试模块,它们的细节如下:

  • AOP 模块提供了面向方面的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。

  • Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。

  • Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。

  • Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。

  • 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

手写Spring

为了深入了解Spring框架的核心容器,用自己的理解将spring框架的IOC写一遍。

这里只粘贴了部分代码,具体代码可以看下:https://github.com/xiaojiesir/handwritingspring

项目结构

1.利用dom4j读取ApplicationContext.xml信息

ApplicationContext.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<component-scan base-package="com.xiaojiesir.demo"></component-scan>
</beans>

读取xml文件内容

package com.springframework.handler.resolver;

import java.io.IOException;
import java.io.InputStream; import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader; public class XMLConfiguration {
private static final String CONFIG_PATH = "ApplicationContext.xml"; public String getScanBasePackage(){
String basePackageString = null; InputStream is = this.getClass().getClassLoader().getResourceAsStream(CONFIG_PATH);
SAXReader saxReader = new SAXReader(); try {
Document document = saxReader.read(is); if(null != document){
Element rootElement = document.getRootElement();
Element element = rootElement.element("component-scan");
//判断是否配置扫描
if(null != element){
basePackageString = element.attributeValue("base-package");
}
}else{
System.out.println("获取配置文件失败!");
} } catch (DocumentException e) {
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} return basePackageString;
}
}

2.扫描对应包下的被标记的类,并将被标记的类放在basePackageMappingToClass集合中

定义一个用来存放类对象的线程安全的集合  basePackageMappingToClass

public static List<Class<?>> basePackageMappingToClass = Collections.synchronizedList(new ArrayList<>());

因为我采用的是扫描整个包,所以需要遍历读取class文件,然后利用类的路径获取类的对象

代码如下:

private void scanBasePackage(String scanBasePackage) {
// 接收一个表示路径的参数,返回一个URL对象,该URL对象表示name对应的资源(文件)。
//该方法只能接收一个相对路径,不能接收绝对路径如/xxx/xxx。并且,接收的相对路径是相对于项目的包的根目录来说的。
     // scanBasePackage:com.xiaojiesir.demo
URL url = this.getClass().getClassLoader().getResource(scanBasePackage.replaceAll("\\.", "/"));
// url ---> file:/D:/workspace/myspring/target/classes/com/xiaojiesir/demo
//获取当前目录下所有文件 try {
File file = new File(url.toURI());//将url转为文件路径格式
file.listFiles(new FileFilter() { //File类的文件过滤器 //accept()方法接收到了参数pathname后参数是listFiles()传来的 在accept()的方法中进行判断.
@Override
public boolean accept(File pathname) {
//判断是否为目录
if(pathname.isDirectory()){
scanBasePackage(scanBasePackage + "."+ pathname.getName());
}else{
//获取当前类的类路径
String classPath = scanBasePackage + "." + pathname.getName().replaceAll("\\.class", "");
//通过类的路径获取类的对象
try {
System.out.println(classPath);
                 //com.xiaojiesir.demo.controller.UserController
                 //com.xiaojiesir.demo.dao.impl.UserDaoImpl
                 //com.xiaojiesir.demo.dao.UserDao
                 //com.xiaojiesir.demo.pojo.User
                 //
com.xiaojiesir.demo.service.impl.UserServiceImpl
                 //
com.xiaojiesir.demo.service.UserService
                 Class<?> clazz = this.getClass().getClassLoader().loadClass(classPath);
//判断类上面是否有@MyController,@MyRepository,@MyService注解
if(clazz.isAnnotationPresent(MyController.class)
|| clazz.isAnnotationPresent(MyRepository.class)
|| clazz.isAnnotationPresent(MyService.class)){
//把MySpring管理的类放在集合中
basePackageMappingToClass.add(clazz);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} }
return false;
}
});
} catch (URISyntaxException e) {
e.printStackTrace();
}
}

3.完成别名与对象实例映射对应关系

定义一个线程安全的集合,存储别名和类的实例映射

public static Map<String, Object> aliasMappingInstance = Collections.synchronizedMap(new HashMap<>());

private void initAliasMappingToInstance() {
if(basePackageMappingToClass.size() == 0){
return;
}
for(int i = 0;i < basePackageMappingToClass.size();i++){
Class<?> clazz = basePackageMappingToClass.get(i);
String alias = getBeanAlias(clazz);//定义类的别名,如果类注解有值,按照注解值,反之类名小写 try {
aliasMappingInstance.put(alias,clazz.newInstance());
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

4.遍历List集合,利用反射完成依赖注入

private void initInstanceInjectionObject() {
if(basePackageMappingToClass.size() == 0){
return;
}
for(int i = 0;i < basePackageMappingToClass.size();i++){
Class<?> clazz =basePackageMappingToClass.get(i);
String instanceAlias = getBeanAlias(clazz);
//获取需要依赖注入的对象
Object needInjectionObj = aliasMappingInstance.get(instanceAlias); //获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
Field[] fields = clazz.getDeclaredFields(); if(null != fields && fields.length > 0){
for(int j = 0;j < fields.length;j++){
//定义存储需要装配的依赖对象
Object injectObj = null;
Field field = fields[j];
//判断是否有@MyAutowired注解
if(field.isAnnotationPresent(MyAutowired.class)){
MyAutowired myAutowired = field.getAnnotation(MyAutowired.class);
//判断value是否为空字符串
if(!"".equals(myAutowired.value())){
//装配别名名称
String alias = myAutowired.value();
//获取到装配的依赖对象
injectObj = aliasMappingInstance.get(alias);
}else{
//按照默认方式装配依赖对象
Class<?> fieldType = field.getType();
//获取容器中所有实例的类型
Collection<Object> values = aliasMappingInstance.values();
Iterator<Object> iterator = values.iterator();
while(iterator.hasNext()){
Object object = iterator.next();
//判断是否为同一个类型
if(fieldType.isAssignableFrom(object.getClass())){
//找到需要装配依赖对象的实例
injectObj = object;
break;
}
}
}
}
//设置字段访问权限
field.setAccessible(true);
try {
//把依赖对象装配到响应的实例中
field.set(needInjectionObj, injectObj);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}

5.根据对象实例别名获取实例

public Object getBean(String name){
return aliasMappingInstance.get(name);
}

手写spring的更多相关文章

  1. 一个老程序员是如何手写Spring MVC的

    人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十 ...

  2. 【Spring】手写Spring MVC

    Spring MVC原理 Spring的MVC框架主要由DispatcherServlet.处理器映射.处理器(控制器).视图解析器.视图组成. 完整的Spring MVC处理 流程如下: Sprin ...

  3. 我是这样手写 Spring 的(麻雀虽小五脏俱全)

    人见人爱的 Spring 已然不仅仅只是一个框架了.如今,Spring 已然成为了一个生态.但深入了解 Spring 的却寥寥无几.这里,我带大家一起来看看,我是如何手写 Spring 的.我将结合对 ...

  4. 《四 spring源码》利用TransactionManager手写spring的aop

    事务控制分类 编程式事务控制          自己手动控制事务,就叫做编程式事务控制. Jdbc代码: Conn.setAutoCommite(false);  // 设置手动控制事务 Hibern ...

  5. 手写 Spring

    手写 Spring 不多说,简历装 X 必备.不过练好还是需要求一定的思维能力. 一.整体思路 思路要熟练背下来 1)配置阶段 配置 web.xml: XDispatchServlet 设定 init ...

  6. 手写Spring框架,加深对Spring工作机制的理解!

    在我们的日常工作中,经常会用到Spring.Spring Boot.Spring Cloud.Struts.Mybatis.Hibernate等开源框架,有了这些框架的诞生,平时的开发工作量也是变得越 ...

  7. 手写Spring+demo+思路

    我在学习Spring的时候,感觉Spring是很难的,通过学习后,发现Spring没有那么难,只有你去学习了,你才会发现,你才会进步 1.手写Spring思路: 分为配置.初始化.运行三个阶段如下图 ...

  8. 我是这样手写Spring的,麻雀虽小五脏俱全

    人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十 ...

  9. Spring事务原理分析--手写Spring事务

    一.基本概念和原理 1.Spring事务 基于AOP环绕通知和异常通知的 2.Spring事务分为编程式事务.声明事务.编程事务包括注解方式和扫包方式(xml) Spring事务底层使用编程事务(自己 ...

  10. 手写Spring MVC

    闲及无聊 又打开了CSDN开始看一看有什么先进的可以学习的相关帖子,这时看到了一位大神写的简历装X必备,手写Spring MVC. 我想这个东西还是有一点意思的 就拜读了一下大佬的博客 通读了一遍相关 ...

随机推荐

  1. ybt1107题解和方法总结

    今天花了三个小时的时间刷了些基础题,虽说是简单题,但是有一些还是有点难度的 比如ybt1107,我死嗑了半个小时. [题目描述] 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米. ...

  2. Mybatis 和 Solon 在一起的升级版

    终于说通 Solon 作者,让他为 Solon 框架添加事务注解支持了:并且把 mybatis-solon-plugin 的 @Df 注解更名为 @Db ,接地气多了(Df是什么鬼呢?新手肯定这么想. ...

  3. BIGI行情http请求实时行情数据方式

    BIGI行情http请求实时行情数据方式 新浪财经文华财经并非实时行情数据源,所以获取的行情数据源也并非实时的.以下介绍的方法和新浪财经获取行情数据源的方法是一致的.需要实时行情数据源可以向BIGI行 ...

  4. A Review on Generative Adversarial Networks: Algorithms, Theory, and Applications

    1 Introduction GANs由两个模型组成:生成器和鉴别器.生成器试图捕获真实示例的分布,以便生成新的数据样本.鉴别器通常是一个二值分类器,尽可能准确地将生成样本与真实样本区分开来.GANs ...

  5. Linux两台服务器mysql数据库同步

    我们在做web系统部署的时候往往涉及到两台甚至多台数据库的备份,为了数据安全考虑(虽然说到底不过是一堆0 1,但是价值千金啊),所以我们还是乖乖做同步把! 1.准备两台Linux服务器(主.从) 2. ...

  6. 《HelloGitHub》第 53 期

    兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程.对开源社区感兴趣 人群的月刊,月刊的内容包括:各种编 ...

  7. springboot之对之前的补充

    Spring Cloud 初级 一. Spring Boot 回顾   1 什么是 Spring Boot?   Spring Boot 是在 Spring 的基础之上产生的(确切的说是在 Sprin ...

  8. e3mall商城的归纳总结4之图片服务器以及文本编辑器

    一.图片服务器 --1.认识图片服务器 大家可能都知道在分布式架构中使用图片上传可能会导致文件存放在某一个项目,而我们的项目基本上都采用集群的方式 ,因此这样会导致图片的问题比较难以存放,在这里我们有 ...

  9. windows下安装jdk+tomcat+maven并配置

    一.下载安装jdk并配置 1.1 进行JDK下载 下载地址:一键直达 一般下载后,安装位置默认,一路下一步,一直到安装完毕-"关闭". 1.2 环境变量配置 不要管是不是一般情况, ...

  10. linux 下分别使用pip2、pip3

    上次切换了Python2和Python3.但是Python3并没有pip,所有在Python3下不能安装包. 下面实现在Python3 下安装pip3 1,首先安装setuptools wget -- ...