(1)Spring是一个开源框架,是整个生态的基石(SpringBoot、SpringCloud等都是以Spring为基石的)
(2)Spring是为了简化企业开发而生的,使得开发变得更加优雅和简介
(3)Spring是一个IOC和AOP的容器框架
①IOC,翻译过来就是控制反转,是一种设计思想,在java开发中,将你设计好的对象交给spring容器控制,而不是显示的用代码进行对象的创建。控制反转的思想完全颠覆了应用程序组件获取资源的传统方式:反转了资源的获取方向——改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效率。这种行为也称为查找的被动形式。
②DI,翻译过来就是依赖注入。DI 是 IOC 的具体实现方式:即组件以一些预先定义好的方式(例如:set 注入,构造器
注入等)接收来自于容器的资源注入。总结就是:IOC 是一种控制反转的思想, 而 DI 是对 IOC 的一种具体实现。
③AOP,即面向切面编程,它是面向对象编程的一种补充和完善,它通过预编译方式和运行期动态代理的方式实现在不修改源代码的情况下给程序动态统一添加额外功能。它将公共逻辑(比如事务管理、日志、缓存等)封装成切面,跟业务代码进行
分离。
④容器:包含并管理应用对象的生命周期,就好比用桶装水一样,spring就是桶,而对象就是水
(1)你可以轻松的写一个web应用
Spring框架有一个模块叫做SpringMVC,你可以利用该模块来开发Web应用。
(1)set方法
(2)构造方法
(1)方便解耦,简化开发
通过Spring提供的IOC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的的过度耦合。用户也不在为
单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用
(2)AOP编程的支持
通过Spring的AOP功能,方便进行切面编程,许多不容易用传统OOP实现的功能可以通过AOP轻松实现
(3)声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务管理,提高开发效率和质量
(4)可以用非容器依赖的方式
spring的事务是由AOP来实现的,首先要生成具体的代理对象,然后按照AOP的整套流程来执行具体的操作逻辑,正常
情况下要通过通知来完成核心功能,但是事务不是通过通知来实现的,而是通过一个TransactionInterceptor来实现的,然
后调用invoke来实现具体的逻辑:
(1)先做准备工作,解析各个方法上事务相关的属性,根据具体的属性来判断是否开始新事务
(2)当需要开启的时候,获取数据库的连接,关闭自动提交功能,开启事务
(3)执行具体的sql逻辑操作
(4)在操作过程中,如果执行失败了,那么会通过completeTransactionAfterThrowing来完成事务的回滚操作,回滚的具体
逻辑是通过doRollBack方法来实现的,实现的时候也是先获取连接对象,通过连接对象来回滚
(5)如果执行过程中,没有任何意外情况的发生,那么通过commitTransactionAfterReturning来完成事务的提交操作,提交的具体逻辑是通过doCommit方法来实现的,实现的时候也是要获取连接,通过连接对象来提交
(6)当事务执行完毕后需要清除相关的事务信息cleanupTransactioninfo
(1)前端控制器 DispatcherServlet(不需要程序员开发)
用户请求到达前端控制器,它就相当于MVC模式中的C, DispatcherServlet是整个流程控制的中心,由它调用其他组件处理用户的请求,DisPatcherServlet的存在降低了组件之间的耦合度
(2)处理器映射器HanlerMapping(不需要程序员开发)
HandlerMapping负责根据用户请求找到Handler处理器,SpringMVC提供了不同的映射器实现不同的映射方式,例如:配置文件方式,
实现接口方式,注解方式等。
(3)处理器适配器HandlerAdaptor
通过HandlerAdaptor对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
(4)处理器Handler(需要程序员开发)
这是我们开发中要编写的具体业务控制器。由DispatcherServlet把用户请求转发到 Handler。由Handler对具体的用户请求进行处理。
(5)视图解析器ViewResolver(不需要程序员开发)
View Resolver 负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成
View视图对象,最后对View进行渲染将处理结果通过页面展示给用户
(6)视图view(需要程序员开发jsp)
view是一个接口,它的实现类支持不同的视图类型(jsp,freemarker,pdf等等)
(1)#{}是预编译处理,${}
是字符串替换
(2)MyBatis在处理#{}时,会将SQL中的#{}替换为?号,调用PreparedStatement的set方法来赋值
(3)MyBatis在处理 ${}
时,就是把 ${}
替换成变量的值,调用Statement来赋值
(4)使用#{}方式能够很大程度防止sql注入(提高系统安全),${}
方式无法防止Sql注入
(5)#{}的变量替换是在DBMS(数据库管理系统)中、变量替换后,#{}对应的变量会自动加上单引号
${}
的变量替换是在DBSM外、变量替换后,${}
对应的变量不会加上单引号
注意:
1.在JDBC能使用占位符的地方,最好优先使用#{}
UPDATE t_address
SET is_default = 0
WHERE uid = #{uid}
2.在JDBC不支持使用占位符的地方,就只能使用${},典型情况就是 动态参数
(1)比如 有两张表,分别是emp_11 和 emp_22 .如果需要在查询语句中 动态指定表名,就只能使用 ${}
select * from emp_ ${year}
(2)再比如MyBatis 排序时使用order by 动态参数时,此时也只能使用 ${}
select * from dept order by ${name}
(1)使用@Param注解
Integer updateDefaultByAid(
@Param("aid") Integer aid,
@Param("modifiedUser") String modifiedUser,
@Param("modifiedTime") Date modifiedTime
);
(2)使用集合
(3)使用Java Bean传参
Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分
页。可以在sql内直接拼写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物
理分页,比如:操作MySQL数据的时候,在原有SQL后面拼写limit。分页插件的基本原理是使用
Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,
根据dialect方言,添加对应的物理分页语句和物理分页参数
使用foreach标签
(1)foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach标签的属性主
要有item,index,collection,open,separator,close。
①item 表示集合中每一个元素进行迭代时的别名,随便起的变量名;
②index 指定一个名字,用于表示在迭代过程中,每次迭代到的位置,不常用;
③open 表示该语句以什么开始,常用“(”;
④separator 表示在每次进行迭代之间以什么符号作为分隔符,常用“,”;
⑤close 表示以什么结束,常用“)”。
(2)在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是
在不同情况下,该属性的值是不一样的,主要有一下3种情况:
① 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
② 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
③ 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封
装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map
的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封
装的map里面的key
(1)Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态
拼接sql的功能,
(2)Mybatis提供了9种动态sql标签
trim|where|set|foreach|if|choose|when|otherwise|bind。
(3)其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此
来完成动态sql的功能。
(1)MyBatis启动加载
①SqlSessionFactory:会完成全局配置文件和映射文件的加载解析操作,然后会把相关的信息保存到
Configuration对象中。创建的SqlSessionFactory对象的实现是DefaultSqlSessionFactory对象
②SqlSession:通过SqlSessionFactory获取了SqlSession对象,创建的具体的实例是DefaultSqlSession
(2)MyBatis如何处理请求
SqlSession中提供了处理请求的方法:save select update delete
调用对应的Executor处理,如果有配置缓存处理–> 先走二级缓存,然后再走一级缓存;如果缓存中都
没有查询到对应的数据才会走数据库操作,交给StatementHandler来处理,通过ParameterHandler处理
SQL中的占位符,通过ResultSetHandler处理结果集的映射。
(1)缓存模块:装饰器模式
(2)日志模块:适配器模式,代理模式
(3)SqlSessionFactory:工厂模式
(4)Mapper接口:代理模式
(5)SqlSessionFactoryBuilder:建造者模式
标签的属性有哪些?(1)collection:代表要遍历的集合元素,注意编写时不要写#{}
(2)open:代表语句的开始部分
(3)close:代表语句的结束部分
(4)item:代表遍历集合的每个元素,生成的变量名
(5)sperator:代表分隔符
①动态sql语句
<select id="findByIds" parameterType="list">
select * from User
<where>
<foreach collection="array" open="id in(" close=")" item="id" seperator=",">
#id
foreach>
where>
select>
②测试
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int[] ids = new int[]{2,5};
List<User> userList = userMapper.findByIds(ids);
(1)实体类的名字和数据库相同时,可以直接设置resultType参数为pojo类
<select id="findByParent" resultType="com.cy.store.entity.District">
SELECT *
FROM t_dict_district
WHERE parent = #{parent}
ORDER BY CODE ASC;
select>
(2)若不同,需要设置resultMap将查询结果集中的列一一映射到bean对象的各个属性
<resultMap id="resultUser" type="com.cy.store.entity.User">
<result column="created_user" property="createdUser">result>
<result column="created_time" property="createdTime">result>
<result column="modified_user" property="modifiedUser">result>
<result column="modified_time" property="modifiedTime">result>
resultMap>
<select id="findByUsername" resultMap="resultUser">
select *
from t_user
where username = #{username}
select>
要想理解parameterType和parameterMap的区别
我们以下面这个mapper接口中的方法为例
Cart findByUidAndPid(
@Param("uid") Integer uid,
@Param("pid") Integer pid
);
(1)parameterType的使用
//行内参数映射
<select id="findByUidAndPid" parameterType="java.lang.Integer">
SELECT *
FROM t_cart
WHERE uid = #{uid}
AND pid = #{pid};
select>
(2)parameterMap的使用
注意:要把占位符#{}改为?
<parameterMap id="cart" type="com.cy.store.entity.Cart">
<parameter property="uid"/>
<parameter property="pid"/>
</parameterMap>
<select id="findByUidAndPid" parameterMap="cart">
SELECT *
FROM t_cart
WHERE uid = ?
AND pid = ?;
</select>
(3)使用场景
(1)观看上面两种方法,我们会发现使用行内参数映射比parameterMap配置看起来更直观,阅读性更强,这里只是两个参数,所以是两个?,如果我们有100个参数呢?
(2)实际上,parameterMap元素很少被使用,因为他和select|insert|update|delete元素的parameterType属性的作用类似。
而且就连parameterType属性也很少使用,因为mybatis可以通过类型处理器(TypeHandler)推断出具体传入语句的参数类型:
(1)简化部署
在使用Spring时,项目部署时需要我们在服务器上部署Tomcat,然后把项目打成war包扔到Tomcat里,
在使用SpringBoot后,我们不需要在服务器上去部署Tomcat,因为SpringBoot内嵌了Tomcat,我们只
需要将项目打成jar包就能独立运行,所有的依赖包都在一个jar包内。
(2)简化配置
Spring 虽然是Java EE轻量级框架,但是配置却是极其繁琐的,有各种xml、Annotation配置,一旦出错了是很难找到出错原因的。SpringBoot采用了Java Config 的方式,对spring进行配置。例如我们新建一个类,在这个类中使用@Configuration和@Bean两个注解,@Configuration注解代表该类是个配置类,
@Bean注解表示该方法返回一个Bean对象
(3)自动配置
Spring Boot能根据当前类路径下的类、jar包来自动配置bean,如添加一个spring-boot-starterweb启动器就能拥有web的功能,无需其他配置。
(4)简化监控
我们可以引入 spring-boot-start-actuator 依赖,直接使用REST方式来获取进程的运行期性能参数,从而
达到监控的目的,比较方便。但是 SpringBoot 只是个微框架,没有提供相应的服务发现与注册的配套功能,没有外围监控集成方案,没有外围安全管理方案,所以在微服务架构中,还需要SpringCloud来配合一 起使用。
(5)简化依赖,比如我们要创建一个web项目,在使用spring的时候,需要在pom文件中添加多个依赖;
而SpringBoot则会帮助开发者快速启动一个web容器,在SpringBoot中,我们只需要在pom文件中添加一个
spring-boot-starter-web依赖即可。
核心注解是@SpringBootApplication,它也是启动类上的注解,该注解主要包含了以下3个注解:
(1)@SpringBootConfiguration:组合了@Configuration注解,实现配置文件的功能
(2)@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭
数据源自动配置的功能:@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
(3)@ComponentScan:Spring组件扫描
(1)自动装配, 简单来说就是自动把第三方组件的 Bean 装载到 Spring IOC 容器里面,不需要开发人员再去写 Bean 的相关配置。在 Spring Boot 应用里面, 只需要在启动类上加上@SpringBootApplication 注解就可以实现自动装配。
(2)@SpringBootApplication 是 一 个 复 合 注 解 , 真 正 实 现 自 动 装 配 的 是@EnableAutoConfiguration注解。
①引入 Starter 启动依赖组件的时候, 这个组件里面必须要包含一个@Configuration 注解配置类,而在这个配置类里面通过@Bean 注解声明需要装配到 IOC 容器的 Bean 对象。
②这个配置类是放在第三方的 jar 包里面, 然后通过 SpringBoot 中的约定优于配置思想, 把这个配置类的全路径放在 classpath:/META-INF/spring.factories 文件中。这样SpringBoot 就可以知道第三方 jar 包里面的配置类的位置, 这个步骤主要是用到了 Spring 里面的 SpringFactoriesLoader 来完成。
③SpringBoot 拿到第三方 jar 包里面声明的配置类以后, 再通过 Spring 提供的ImportSelector 接口, 实现对这些配置类
的动态加载。
(3)在我看来, SpringBoot 是约定优于配置这一理念下的产物, 所以在很多的地方,都会看到这类的思想。 它的出现, 让开发人员更加聚焦在了业务代码的编写上,而不需要去关心和业务无关的配置。
(4)其实, 自动装配的思想, 在 SpringFramework3.x 版本里面的@Enable 注解, 就有了实现的雏形。 @Enable 注解是模块驱动的意思, 我们只需要增加某个@Enable 注解, 就自动打开某个功能, 而不需要针对这个功能去做 Bean 的配置, @Enable 注解的底层也是帮我们去自动完成这个模块相关 Bean 的注入。