个人说明:

下面有一部分引用该链接:https://www.tutorialspoint.com/spring/spring_architecture.htm 另外一部分加上我个人的使用经验和体会

之所以参考,第一,相关概念知识回顾;第二,系统化和条理化。

我想做到的是,给初学者一个全局的概况和相关应用的说明,给中级开发者们,一个知识回顾和灵感的体会。

至于高级开发者,即架构师或者专家,我就不再这班门弄斧了,不过也十分希望他们的意见和看法,以此来灵感碰撞产生知识火花。

该篇博文,主要是回顾我的使用Spring的经历历程和一些深刻体会,另外我希望加上一些源码方面的理解。

对于初学者而言,知道怎么用就行了,但对于非初学者而言,不仅仅要知道怎么用,还要知道如何用的更好(这就需要你知道它的底层原理和实现机制)。

一、简述

Spring是企业Java最流行的应用程序开发框架。全球数百万开发人员使用Spring Framework创建高性能,易于测试和可重用的代码。

Spring框架是一个开源Java平台。它最初由Rod Johnson编写,并于2003年6月首次在Apache 2.0许可下发布。

弹簧在尺寸和透明度方面很轻巧。Spring框架的基本版本大约为2MB。

Spring Framework的核心功能可用于开发任何Java应用程序,但有一些扩展用于在Java EE平台之上构建Web应用程序。Spring框架的目标是通过启用基于POJO的编程模型,使J2EE开发更易于使用并促进良好的编程实践。

二、使用Spring的好处

(1)Spring使开发人员能够使用POJO开发企业级应用程序。仅使用POJO的好处是您不需要EJB容器产品(如应用程序服务器),但您可以选择仅使用强大的servlet容器(如Tomcat)或某些商业产品。

对于初学者而言或许会疑惑,什么是POJO?

简单的说,POJO相当于JavaBean,又称实体类。

这里还要补充说下,应用服务器和web服务器的区别?常见的应用服务器和web服务器有哪些?

常见的应用服务器,比如我比较常用的就是tomcat,当然在我的朋友中,他们有些人使用Jboss或者resin或weblogic等等。

常见的web服务器:比如apache、nginx等

相同点(共性):遵守HTTP协议

不同点:(应用服务器即可处理静态请求(图片、js、css、html等),又可以处理动态请求(可嵌入服务端脚本,例如:jsp,freemarker,volocity等),而web服务器只能处理静态请求,不能处理静态请求,当然了,web服务器处理静态资源的效率自然比应用服务器处理静态资源的效率要高的多。

(2)Spring采用模块化方式组织。即使包和类的数量很大,你也只需要担心你需要的那些而忽略其余的。

(3)Spring并没有重新发明轮子,而是真正利用了一些现有技术,如几个ORM框架,日志框架,JEE,Quartz和JDK计时器以及其他视图技术。

常用的ORM框架:Spring的JDBC,MyBatis,Hibernate等;

常见的日志框架:log4j或slif4j等;

视图技术:JSP+Volocity+Freemarker等;

定时任务:相比JDK定时任务更通俗易懂的Quartz;

(4)测试用Spring编写的应用程序很简单,因为依赖于环境的代码被移动到这个框架中。此外,通过使用JavaBeanstyle POJO,使用依赖注入来注入测试数据变得更加容易。

例如Spring的Junit4或者Juni5

(5)Spring的Web框架是一个设计良好的Web MVC框架,它提供了一个很好的替代Web框架,如Struts或借着Spring名气流行+自身相比Struts2更轻量级的实现方式的SpringMVC。

(6)Spring提供了一个方便的API,用于将特定于技术的异常(例如,JDBC,Hibernate或JDO抛出)转换为一致的,未经检查的异常。

Spring提供的API非常易懂,Spring对于有一定Java基础的人而言,很容易上手

(7)轻量级IoC容器往往是轻量级的,尤其是与EJB容器相比时。这有利于在具有有限内存和CPU资源的计算机上开发和部署应用程序。

说到轻量级,什么是轻量级?为什么要轻量级?轻量级给实际项目开发会带来哪些好处?

轻量级,简单说就是低耦合,代码相互依存度不强,遵守软件开中的编码"高内聚,低耦合"原则。

解释了什么是轻量级,为什么要轻量级就更好说明了,谁都不希望在需求变更的时候,改了这段代码,那段代码就出问题了,换言之,好不容易解决了一个bug,新的bug又出现了,代码耦合度越强,内聚性低,那么bug只会越改越多,最终除了拼命的加班加班改bug改bug,这也就是程序员为什么会猝死的一个重要原因之一以及为什么找不到对象,处对象也是需要时间的,天天对着电脑改bug,公司加班通宵达旦的改,回来还得改,这样导致个人提高时间少了(个人提高,主要在于平时看书,总结加上实践练习,再加上开源项目学习,借鉴前辈们的解决方案,虽说要有创新精神,但是,就拿中国的改革开放而言,现在已经是中国有特色的的社会主义道路,但是在此新中国(1978年之前)我们模仿苏联,走苏联的社会主义道路,满清时,我们学习西方,掀起了洋务运动,维新变法,辛亥革命等等,但最后都没有达到应有的效果,都相继失败了,这是为什么呢?因为我们忽略的自身的实际情况。有一句话叫做量力而行,还有一句话叫做循环渐进,还有最后一句话叫日积月累)。

最后轻量级会给实际项目开发带来哪些好处?简单的说,

第一,代码可扩展性强;

第二,代码可维护性好;

第三,bug机率少,加班就少,加班少有利于生命健康,而且还有利于代码功力的提升。

补充说明:我想谁都不愿意,天天改着因为自己平时不认真或者是编码时,不好好想怎样做会更好,更有利于扩展和维护,反而将其当为体力劳动,那么即便做了四年五年,那与一年两年又有何区别呢?人要有梦想,没有梦想和咸鱼就没有区别了。

(8)Spring提供了一致的事务管理接口,可以缩小到本地事务(例如,使用单个数据库)并扩展到全局事务(例如,使用JTA或者使用Spring的xml事务或注解事务等)。

事务,为什么需要事务?银行去取钱的例子可以很好说明这一点,这里不再赘述,网上一大把例子和博文说明。

三、依赖注入

Spring最常见的技术是Inversion of Control 的依赖注入(DI)风格。该控制反转(IOC)是一个笼统的概念,它可以在许多不同的方式来表达。依赖注入只是控制反转的一个具体例子。

在编写复杂的Java应用程序时,应用程序类应尽可能独立于其他Java类,以增加重用这些类的可能性,并在单元测试时独立于其他类测试它们。依赖注入有助于将这些类粘合在一起,同时保持它们的独立性。

究竟什么是依赖注入?我们分别看看这两个词。这里依赖部分转换为两个类之间的关联。例如,A类依赖于B类。现在,让我们看第二部分,注入。所有这些意味着,B类将由IoC注入A类。

依赖注入可以通过将参数传递给构造函数或使用setter方法进行后构建来实现。

以下面一段代码说明:

PostMapper.java

package cn.blog.mapper;

import java.util.HashMap;
import java.util.List;
import java.util.Map; import cn.blog.entity.Post;
/*
* 文章接口
*/
public interface PostMapper { /**
* 根据文章ID显示文章
*/
public Post selectByPostId(Integer postId); /**
* 显示文章总数
*/
public int selectPostCount(); /**
*分页显示
*/
public List<Post> selectPostWherePage(HashMap<String,Object> map); /**
* 根据用户ID显示该用户的所有文章
*/
public List<Post> selectUserIdWherePage(Map<String,Object> map); /**
*显示该用户ID下所有文章总数
*/
public int selectUserIdWherePageCount(Integer userId); }

PostService.java

package cn.blog.service;

import org.apache.ibatis.annotations.Param;

import cn.blog.entity.Post;
import cn.blog.utils.PageBean; public interface PostService { /**
* 根据文章ID显示文章
*/
public Post selectByPostId(Integer postId); /**
* 显示文章总数
*/
public int selectPostCount(); /**
*分页显示
*/
public PageBean<Post> selectPostWherePage(int currentPage); /**
* 根据用户ID显示该用户的所有文章
*/
public PageBean<Post> selectUserIdWherePage(int currentPate,int userId); /**
*显示该用户ID下所有文章总数
*/
public int selectUserIdWherePageCount(Integer userId); }

PostServiceImpl.java

package cn.blog.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import cn.blog.entity.Post;
import cn.blog.mapper.PostMapper;
import cn.blog.service.PostService;
import cn.blog.utils.PageBean; @Service
public class PostServiceImpl implements PostService{ @Autowired
private PostMapper postMapper; @Override
public Post selectByPostId(Integer postId) {
// TODO Auto-generated method stub
return postMapper.selectByPostId(postId);
} @Override
public int selectPostCount() {
// TODO Auto-generated method stub
return postMapper.selectPostCount();
} @Override
public PageBean<Post> selectPostWherePage(int currentPage) {
HashMap<String,Object> map = new HashMap<String,Object>();
PageBean<Post> pageBean = new PageBean<Post>(); //封装当前页数
pageBean.setCurrPage(currentPage); //每页显示的数据
int pageSize=5;
pageBean.setPageSize(pageSize); //封装总记录数
int totalCount = postMapper.selectPostCount();
pageBean.setTotalCount(totalCount); //封装总页数
double tc = totalCount;
Double num =Math.ceil(tc/pageSize);//向上取整
pageBean.setTotalPage(num.intValue()); map.put("start",(currentPage-1)*pageSize);
map.put("size", pageSize);
//封装每页显示的数据
List<Post> lists = postMapper.selectPostWherePage(map);
pageBean.setLists(lists); return pageBean;
} @Override
public int selectUserIdWherePageCount(Integer userId) {
// TODO Auto-generated method stub
return postMapper.selectUserIdWherePageCount(userId);
} @Override
public PageBean<Post> selectUserIdWherePage(int currentPage,int userId) { PageBean<Post> pageBean = new PageBean<Post>(); Map<String,Object> paramMap = new HashMap<String,Object>();
//封装当前页数 pageBean.setCurrPage(currentPage); //每页显示的数据
int pageSize=5;
pageBean.setPageSize(pageSize); //封装总记录数
int totalCount = postMapper.selectUserIdWherePageCount(userId);
pageBean.setTotalCount(totalCount); //封装总页数
double tc = totalCount;
Double num =Math.ceil(tc/pageSize);//向上取整
pageBean.setTotalPage(num.intValue());
paramMap.put("start", (currentPage-1)*pageSize);
paramMap.put("size", pageBean.getPageSize());
paramMap.put("userId", userId); //封装每页显示的数据
List<Post> lists = postMapper.selectUserIdWherePage(paramMap); pageBean.setLists(lists); return pageBean;
} }

对应的xml配置文件为:

<bean id="postMapper" class="com.blog.mapper.PostMapper">
</bean> <bean id="postService" class="cn.blog.service.impl.PostServiceImpl">
<property name="postMapper" ref="postMapper"/>
</bean>

通过这段例子,我想大家应该明白了什么是依赖注入,如果不这样写的话,你前台要想获得对应的数据访问层(DAO层)数据,必须得实例化,十几二十个还好管理,成千上万个呢?那估计你肯定会有骂娘的冲动了。同时也明白了Spring为你管理对象的好处。如果没有Spring为你管理对象,一个一个实例化,那将是一件非常恐惧的事情。

四、面向切面编程

Spring的一个关键组件是面向切面编程(AOP)框架。跨越应用程序多个点的功能称为跨领域问题,这些跨领域问题在概念上与应用程序的业务逻辑分开。各方面有各种常见的良好示例,包括日志记录,声明式事务,安全性,缓存等。

OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面。DI可帮助您将应用程序对象彼此分离,而AOP可帮助您将交叉问题与它们所影响的对象分离。

Spring Framework的AOP模块提供了面向方面的编程实现,允许您定义方法拦截器和切入点,以便干净地解耦实现应该分离的功能的代码。

就拿Spring的xml注解配置讲解:

   <!-- 配置事务管理 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean> <!-- 事务管理 属性 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="append*" propagation="REQUIRED"/>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="modify*" propagation="REQUIRED"/>
<tx:method name="edit*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="remove*" propagation="REQUIRED"/>
<tx:method name="repair" propagation="REQUIRED"/> <tx:method name="get*" propagation="REQUIRED" read-only="true"/>
<tx:method name="find*" propagation="REQUIRED" read-only="true"/>
<tx:method name="load*" propagation="REQUIRED" read-only="true"/>
<tx:method name="search*" propagation="REQUIRED" read-only="true"/>
<tx:method name="datagrid*" propagation="REQUIRED" read-only="true"/>
<tx:method name="*" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice> <!-- 配置切面 -->
<aop:config>
<aop:pointcut id="transactionPointcut" expression="execution(* com.rms.service..*.*(..))"/>
<aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice"/>
</aop:config>

上述例子,比如配置切面,这个切面相当于不管怎么样你必定会经过的,比如电视中山大王经常去某个必经之路抢经过路人的钱财。

当然了,上面的配置,主要是关于事务的。熟悉xml事务配置的,对于上面xml代码再熟悉不过了。

不熟悉的也没有关系,用多了自然明白。另外补充一点,上面同时也代表了一种规则,比如我的添加方法叫userAdd,但是我的事务配置了必须要以add或者append或者其他read-only为false开头的才能在数据库对应的表新增数据,现在我的添加方法叫userAdd,它就会触发该规则中包含的另外一种规则就是:<tx:method name="*" propagation="REQUIRED" read-only="true"/>,这个规则将非上述列出的均判断为查询,而我的userAdd是新增,但是不符合上述配置的事务规则,就会导致报错,从而插入数据失败。

这样一来,大家或许就知道它的应用了,如果是传统的那种Java编程(非Spring),我们将要写很多判断。

五、Spring的架构图

经常用Spring相关的组件开发项目,对于上述架构图,我想一定不陌生了。

简要概述说明:

核心容器

核心容器由核心,Bean,上下文和表达式语言模块组成,其详细信息如下 -

  • 所述Core 模块提供了框架的基本部分,包括IOC和依赖注入特征。

  • Bean模块提供的BeanFactory,这是一个复杂的实现工厂模式。

  • Context模块建立由核心和豆类模块提供的固体基体上,它是访问定义和配置的任何对象的介质。ApplicationContext接口是Context模块的焦点。

  • 使用SpEL模块提供用于查询并在运行时操作对象图的强大的表达式语言。

数据访问/集成

数据访问/集成层由JDBC,ORM,OXM,JMS和Transaction模块组成,其详细信息如下 -

  • JDBC模块提供了一个JDBC的抽象层,消除了冗长的JDBC相关编码的需要。

  • ORM模块提供的集成层为流行的对象关系映射API,包括JPA,JDO,休眠,和iBatis。

  • OXM模块提供了支持用于JAXB,蓖麻,XMLBeans的,JiBX的及XStream对象/ XML映射实现的抽象层。

  • Java Messaging Service JMS模块包含用于生成和使用消息的功能。

  • Transaction模块支持编程和声明式事务管理实现特殊接口的类,并为所有的POJO。

Web

Web层由Web,Web-MVC,Web-Socket和Web-Portlet模块组成,其详细信息如下 -

  • Web模块提供了基本的面向Web的集成功能,如多文件上传功能,并使用servlet的听众和一个面向Web的应用程序上下文IoC容器的初始化。

  • Web-MVC模块包含Web应用程序的Spring的模型-视图-控制器(MVC)的实现。

  • Web-Socket模块提供客户端和Web应用程序服务器之间基于WebSocket的-,双向通信支持。

  • Web-Portlet模块提供了MVC实现在门户环境中使用,并反映了网络服务程序模块的功能。

Miscellaneous

其他重要的模块很少,如AOP,Aspects,Instrumentation,Web和Test模块,其详细信息如下 -

  • AOP模块提供了一个面向方面的编程实现,允许你定义方法拦截器和切入点干净地分离实现的功能,应该被分离的代码。

  • Aspects模块提供了与AspectJ的,这又是一个强大而成熟的AOP框架集成。

  • Instrumentation 模块提供类工具的支持和类加载器实现在某些应用服务器使用。

  • Messaging模块提供STOMP作为WebSocket的子协议在应用程序中使用的支持。它还支持用于从WebSocket客户端路由和处理STOMP消息的注释编程模型。

  • Test模块支持Spring组件的使用JUnit或TestNG的框架中进行测试。

Spring(一)之概括与架构的更多相关文章

  1. VS2010+MVC4+Spring.NET2+NHibernate4-传统三层架构-前篇

    VS2010+MVC4+Spring.NET2+NHibernate4 - 传统三层架构 - 前篇 一直追求使用开源项目,就因一个字:懒! 一直想整理一下的,却一直懒到现在!从当初用的MVC3到现在的 ...

  2. SpringMVC,Spring,Hibernate,Mybatis架构开发搭建之SpringMVC部分

    SpringMVC,Spring,Hibernate,Mybatis架构开发搭建之SpringMVC部分 辞职待业青年就是有很多时间来写博客,以前在传统行业技术强度相对不大,不处理大数据,也不弄高并发 ...

  3. Spring Cloud构建微服务架构(一)服务注册与发现

    Spring Cloud简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁 ...

  4. 一文读懂 Spring Boot、微服务架构和大数据治理三者之间的故事

    微服务架构 微服务的诞生并非偶然,它是在互联网高速发展,技术日新月异的变化以及传统架构无法适应快速变化等多重因素的推动下诞生的产物.互联网时代的产品通常有两类特点:需求变化快和用户群体庞大,在这种情况 ...

  5. Spring Cloud构建微服务架构(二)服务消费者

    Netflix Ribbon is an Inter Process Communication (IPC) cloud library. Ribbon primarily provides clie ...

  6. Spring Cloud构建微服务架构:服务网关(路由配置)【Dalston版】

    转载:http://blog.didispace.com/spring-cloud-starter-dalston-6-2/ 原创  2017-08-26  翟永超  Spring Cloud 被围观 ...

  7. Cola Cloud 基于 Spring Boot, Spring Cloud 构建微服务架构企业级开发平台

    Cola Cloud 基于 Spring Boot, Spring Cloud 构建微服务架构企业级开发平台: https://gitee.com/leecho/cola-cloud

  8. Spring Cloud构建微服务架构(五)服务网关

    通过之前几篇Spring Cloud中几个核心组件的介绍,我们已经可以构建一个简略的(不够完善)微服务架构了.比如下图所示: 我们使用Spring Cloud Netflix中的Eureka实现了服务 ...

  9. Spring Cloud构建微服务架构 - 服务网关

    通过之前几篇Spring Cloud中几个核心组件的介绍,我们已经可以构建一个简略的(不够完善)微服务架构了.比如下图所示: alt 我们使用Spring Cloud Netflix中的Eureka实 ...

随机推荐

  1. 01 使用Git基本方法

    什么是Git? Git是目前世界上最先进的分布式版本控制系统(没有之一). 你得先有一个Git仓库,才能进行操作.创库就是Git存放你要保存的快照的数据的地方. 拥有一个Git仓库,有两种方法. 创建 ...

  2. oracle 多列数据相同,部分列数据不同合并不相同列数据

    出现这样一种情况: 前面列数据一致,最后remark数据不同,将remark合并成 解决办法: 最后一列:结果详情: 使用到的语句为: select a,b,c,wm_concat(d) d,wm_c ...

  3. apache-kylin 权威指南—读书笔记

    1. 概述 kylin 是 OLAP 引擎,采用多维立方体预计算技术,可将大数据的 SQL 查询速度提升到亚秒级别. 需求: 虽然像 spark,hive 等使用 MPP 大规模并行处理和列式存储的方 ...

  4. bnu 10805 矩形神码的 平面向量的运行

    矩形神码的 Time Limit: 1000ms Memory Limit: 65536KB Special Judge   64-bit integer IO format: %lld      J ...

  5. js事件队列

    前面跟网友讨论到了JS的事件队列 ,对这个有了一些理解,事件队列我认为就是把一些不按顺序执行的事件放到队列里面,然后按照自己制定的顺序去执行,那么什么情况下会用到这个呢?我首先想到的是动画,动画是会执 ...

  6. Visual Studio Code 保存时自动格式化的问题

    烦人的说,保存的时候自动格式化, 格式话后,代码就失效了 纳尼!!!! 网上其他人都说     JS-CSS-HTML Formatter这个插件在捣蛋!   试了,的确如此. 找到他,给禁用,就不会 ...

  7. Spring Tech

    1.Spring中AOP的应用场景.Aop原理.好处? 答:AOP--Aspect Oriented Programming面向切面编程:用来封装横切关注点,具体可以在下面的场景中使用: Authen ...

  8. 微信小程序-02-项目文件之间配合和调用关系

    微信小程序-02-项目文件之间配合和调用关系 我就不说那么多了,我是从官方文档拷贝的,然后加上一些自己的笔记,不喜勿喷 官方文档:https://developers.weixin.qq.com/mi ...

  9. Android深入四大组件(六)Service的启动过程

    前言 此前我用较长的篇幅来介绍Android应用程序的启动过程(根Activity的启动过程),这一篇我们接着来分析Service的启动过程.建议阅读此篇文章前,请先阅读Android深入四大组件(一 ...

  10. c# 设计模式 之:抽象工厂

    1.作用:抽象工厂的目的就是生产[产品族],之前讲的“工厂模式”的每一个factory只造一种产品,抽象工厂让一个factory造多个产品. uml类图: 代码实现: 抽象工厂代码: namespac ...