Spring

Spring基本原理:

通过反射解析类及其类的各种信息,包括构造器、方法及其参数、属性。然后将其封装成bean定义信息类、constructor信息类、method信息类、property信息类,最终放到一个map里,也就是所谓的container,池等等,其实就是个map。

当写好配置文件,启动项目后,框架会先按照配置文件找到那个要scan的包,然后解析包里面的所有类,找到所有含有@bean、@service等注解的类,利用反射解析它们,包括解析构造器、方法、属性等等,然后放到一个map里。

当你需要一个bean的时候,框架就会从container找是不是有这个类的定义,若找到就通过构造器new出来(这就是控制反转,框架会帮你new出来)。再在这个类找是不是又要注入的属性或者方法,比如标@autowired的属性,若有则还到container里找到对应的解析类,new出对象,并通过之前解析出来的信息类找到setter方法,然后用该方法注入对象(这就是依赖注入)。如果其中有一个类在container里没找到,则抛出异常,比如常见的spring无法找到该类定义、无法wire的异常。

嵌套bean则用到了递归,container会放到servletcontext里面,每次request从servletcontext找到这个container即可,不用多次解析类定义。如果bean的scope是singleton,则会重用这个bean不再重新创建,将这个bean放到一个map里,每次用都先从这个map里面找。如果scope是session,则该bean会放到session里面。

Spring容器是个Map映射

IOC底层是反射机制

AOP底层是动态代理

SpringMVC是对Servlet进行的封装

Spring源码地址

Spring-framework源码地址

参考:

pdf:《Spring3.x企业应用开发实战》-陈雄华 林开雄

微信读书:《Spring3.0就是这么简单》-陈雄华 林开雄

pdf:《Spring揭秘》-王福强

认识Spring

Spring是分层的Java SE/EE应用一站式的轻量级开源框架,以反转控制(Inverse of Control,IoC)和面向切面编程(Aspect Oriented Programming,AOP)为内核,提供了展现层Spring MVC、持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术。

  • 方便解耦,简化开发

通过Spring提供的Ioc容器,将对象之间的依赖关系交由Spring进行控制。

  • AOP编程的支持

通过Spring提供的AOP功能,用户可以进行面向切面编程

  • 声明式事务的支持
  • 方便程序的测试
  • 方便继承各种优秀的框架
  • 降低Jave EE API的适用难度

为如JDBC、JavaMail、远程调用等提供了一个薄薄的封装层,简化调用

Spring体系结构

Spring框架由1400多个类组成,整个框架按其所属功能可以划分5个主要模块

Spring框架结构.png

  • IoC

    Spring核心模块实现了IoC的功能,用配置的方式进行类与类之间依赖关系的描述。BeanFactory接口是Spring框架的核心接口,其实现了许多核心功能。

    Context模块构建于核心模块之上,扩展了BeanFactory的功能,添加了i18n国际化、Bean生命周期控制、框架事件体系、资源加载透明化等多项功能。还提供如邮件服务、任务调度、JNDI定位、EJB集成、远程访问等。ApplicationContext是Context模块的核心接口。

    表达式语言模块时统一表达式语言(unified EL)的一个扩展,用于查询和管理运行期的对象,支持设置和获取对象属性,调用对象方法,操作数组、集合等。还提供了逻辑表达式运算、变量定义等功能。使用它就可以方便地通过表达式和Spring IoC容器进行交互。

IoC包括DI(Dependence Injection依赖注入)和DL(Dependence Lookup依赖查找)

IoC有两阶段:收集和注册(即写配置文件等);分析和组装

三种依赖注入方式:

  1. 构造方法注入(constructor injection)
  2. setter方法注入(setter injection)
  3. 接口注入(interface injection)

其中分析组装的依据:

  • 用xml配置来描述bean与bean之间的关系;
  • 用注解方式(如@Autowired和@Inject);

IoC的角色.png

被注入对象和依赖对象由Ioc Service Provider统一管理。Ioc容器充当Ioc Service Provider角色。被注入对象需要什么直接跟Ioc Service Provider招呼一声就行。

使用IoC前后的差别.png

  • AOP

Java 5.0引入java.lang.instrument,允许在JVM启动时启用一个代理类,通过该代理类在运行期修改类地字节码,改变一个类的功能,实现AOP的功能。

  • 数据访问和集成

任何应用程序的核心问题都是对数据的访问和操作。数据又多种表现形式,如数据表、XML、消息等。其中数据表的访问可以通过JDBC、Hibernate或iBatis等。

Spring站在DAO的抽象层面,建立了一套面向DAO层统一的异常体系,同时将各种访问数据的检查型异常转换为非检查型异常,为整合各种持久层框架提供基础。

  • Web及远程访问

Spring提供了一个完整的类似于Struts的MVC框架,称为Spring MVC。

实例功能概述

以登录模块为例

功能简介

Spring登录实例交互流程图.png

  1. 首先用户访问login.jsp,返回带用户名/密码表单的登录页面。
  2. 用户在登陆页面输入用户名/密码,提交表单到服务器,Spring根据配置(如又一城的tile.xml)调用LoginController控制器来响应登录请求。
  3. LoginController调用UserService#hashMatchUser()方法,根据用户名和密码查询是否存在匹配的用户,UserService内部通过调用持久层UserDao完成具体的数据库访问操作。
  4. 如果不存在匹配的用户,重定向login.jsp页面,并报告错误,否则到下一步。
  5. LoginController调用UserService#findUserByUserName()方法,加载匹配的User对象并更新用户最近一次的登录时间和登录IP地址。
  6. LoginController调用UserService#loginSuccess()方法,进行登陆成功的业务处理,创建一个LoginLog对象,并利用LoginLogDao将其插入数据库中。
  7. 重定向到欢饮页面main.jsp,欢迎页面产生响应返回给用户。

环境准备

数据库MySQL5.x、IntelliJ IDEA、Maven、

MySQL 4.1.0以前不支持事务,MySQL 4.1.0对事务提供有限的支持

  1. 创建库表
  2. 初始化一条数据
  3. 创建项目:设置pom文件、分包dao、domain、service、web(若项目大则把dao、service分到功能内)、项目大的情况下对配置文件也要按模块划分
  • 领域对象(domain)(也叫实体类):一般要 implements Serializable,以便可以序列号

  • 传统JDBC API太底层,执行一条最简单的查询操作都要:获取连接–创建Statement–执行数据操作–获取结果–关闭Statement–关闭结果集–关闭连接

    Spring JDBC对传统JDBC API进行了薄层的封装,用户可不必写那些样板式的代码,只写必不可少的代码通过模板类即可完成大部分数据访问的操作。

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
<beans ...>
<!--❶扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入-->
<context:component-scan base-package="com.smart.dao"/>
<!--❷定义一个使用DBCP实现的数据源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3309/sampledb"
p:username="root"
p:password="1234"/>
<!--❸定义JDBC模板Bean-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource"/>
</beans>

在❶处,我们使用Spring的<context:component-scan>扫描指定类包下的所有类,这样在类中定义的Spring注解(如@Repository、@Autowired等)才能产生作用。

在❷处,我们使用Jakarta的DBCP开源数据源实现方案定义了一个数据源,数据库驱动器类为com.mysql.jdbc.Driver,由于我们设置的MySQL数据库的服务端口为3309,而非默认的3306,所以数据库URL中显式指定了3309端口的信息。

在❸处配置了JdbcTemplate Bean,将❷处声明的dataSource注入JdbcTemplate中,而这个JdbcTemplate Bean将通过@Autowired自动注入LoginLog和UserDao的Bean中,可见Spring可以很好地将注解配置和XML配置统一起来。

Spring IoC

IoC:Inverse of Control(控制反转)

  • 读作“反转控制”,更好理解,不是什么技术,是一种设计思想。将原本在程序中手动创建对象的控制权,交由Spring框架来管理。

  • 正控:若要使用某个对象,需要自己去负责对象的创建

  • 反控:若要使用某个对象,只需要从Spring容器中获取需要使用的对象,不关心对象的创建过程,也就是把创建对象的控制权反转给了Spring框架

  • 好莱坞法则:Don’t call me, I’ll call you

Spring IoC阐述

控制反转是一种通过描述(在Java中可以是XML或者注解)并购第三方(Spring)去产生或获取特定对象的方式。

  • 好处:

    降低对象之间的耦合

    我们不需要理解一个类的具体实现,只需要知道它有什么用就好了(直接向IoC容器拿)

主动创建的模式种,责任归于开发者,而在被动的模式下,责任归于IoC容器,基于这样的被动形式,我们就说对象被控制反转了。(也可以说是反转了控制)

Spring IoC容器的设计

Spring IoC容器的设计主要是基于以下两个接口:

  • BeanFactory
  • ApplicationContext

SpringIoc容器的ApplicationContext类图.png

BanFactory

SpringIoc容器的BeanFactory结构.png

  • getBean

对应了多个方法来获取配置给Spring IoC容器的Bean

  1. 按类型拿bean
1
bean = (Bean) factory.getBean();

要求在Spring种只配置了一个这种类型的实例,否则会有不知道获取哪一个而报错。

  1. 按照bean的名字拿bean
1
bean = (Bean) factory.getBean("beanName");

这种不安全,IDE不会检查其安全性(关联性)

  1. 按照名字和类型拿bean:(推荐)
1
bean = (Bean) factory.getBean("beanName", Bean.class);
  • isSingleton 判断是否单例(默认为true)

  • isPrototype若为真,则你从容器中获取Bean,容器会为你生成一个新的实例(默认为false)

  • 关于type的匹配,这是个按Java类型匹配的方式

  • getAliases获取别名

《看透Spring MVC源代码分析与实践》

基础结构

  • BS结构网络传输的分解方式有两种:OSI参考模型、TCP/IP参考模型

    OSI和TCP-IP参考模型.jpg

  • 网络传输的规矩不是强制的,所以不叫制度也不叫标准而叫协议

    TCP/IP参考模型可看作是种协议

    BS结构中TCP/IP模型中的网络接入层没有相应协议,网际互联层是IP协议,传输层是TCP协议,应用层是HTTP协议

    BS中还用到DNS协议。在HTTP上层还有相关的规范,如Java Web开发中使用的Servlet标准

  • 数据传输的本质就是按照晶振震动周期或者其整数倍来传输代表0/1的高低电平,传输过程中最核心的就是各种传输协议,对直接连接的硬件来说就是各种总线协议,对网络传输来说就是网络协议

  • BS模型中解决问题的核心主要就是解决海量数据操作问题和高并发问题,网站复杂的架构就是从这俩问题演变出来的。