本章主要内容包括Spring简介、Spring的两大特性(IOC和AOP)、事务MyBatis集成Spring等。
也许有读者会疑惑,明明是MyBatis-Plus实战,怎么还讲MyBatis这么多东西?
其实很简单,MyBatis-Plus是由MyBatis衍生而来的,其实MyBatis-Plus与Spring整合其实与MyBatis跟Spring整合差异并不大,读者通过前面的MyBatis-Plus初步和MyBatis初步这两个章节,我相信读者们如果看过,心中自会明了。
1.1 Spring简介
Spring是企业Java最流行的应用程序开发框架。全球数百万开发人员使用Spring Framework创建高性能,易于测试和可重用的代码。
Spring框架是一个开源Java平台。它最初由Rod Johnson编写,并于2003年6月首次在Apache 2.0许可下发布。
Spring Framework的核心功能可用于开发任何Java应用程序,但有一些扩展用于在Java EE平台之上构建Web应用程序。Spring框架的目标是通过启用基于POJO的编程模型,使J2EE开发更易于使用并促进良好的编程实践。
Spring相关资料:
Spring的架构图,如下:
使用Spring有什么好处?
(1)Spring使开发人员能够使用POJO开发企业级应用程序。仅使用POJO的好处是您不需要EJB容器产品(如应用程序服务器),但您可以选择仅使用强大的servlet容器(如Tomcat)或某些商业产品;
(2)Spring采用模块化方式组织。即使包和类的数量很大,你也只需要担心你需要的那些而忽略其余的;
(3)Spring并没有重新发明轮子,而是真正利用了一些现有技术,如几个ORM框架,日志框架,JEE,Quartz和JDK计时器以及其他视图技术;
(4)测试用Spring编写的应用程序很简单,因为依赖于环境的代码被移动到这个框架中。此外,通过使用JavaBeanstyle POJO,使用依赖注入来注入测试数据变得更加容易;
(5)Spring的Web框架是一个设计良好的Web MVC框架,它提供了一个很好的替代Web框架,如Struts或借着Spring名气流行+自身相比Struts2更轻量级的实现方式的SpringMVC;
(6)Spring提供了一个方便的API,用于将特定于技术的异常(例如,JDBC,Hibernate或JDO抛出)转换为一致的,未经检查的异常;
(7)轻量级IoC容器往往是轻量级的,尤其是与EJB容器相比时。这有利于在具有有限内存和CPU资源的计算机上开发和部署应用程序;
1.2 IOC特性
1.2.1 IOC简介
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
那么什么是依赖注入呢?
我们分别看看这两个词。这里依赖部分转换为两个类之间的关联。例如,A类依赖于B类。现在,让我们看第二部分,注入。所有这些意味着,B类将由IoC注入A类。
依赖注入可以通过将参数传递给构造函数或使用setter方法进行后构建来实现。
1.2.2 IOC实例
下面我自己曾经的一个项目博客系统里面的部分代码为例来讲解
(1)编写数据访问层接口
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 selectPostWherePage(HashMap map);
/**
* 根据用户ID显示该用户的所有文章
*/
public List selectUserIdWherePage(Map map);
/**
*显示该用户ID下所有文章总数
*/
public int selectUserIdWherePageCount(Integer userId);
}
(2)编写业务接口
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 selectPostWherePage(int currentPage);
/**
* 根据用户ID显示该用户的所有文章
*/
public PageBean selectUserIdWherePage(int currentPate,int userId);
/**
*显示该用户ID下所有文章总数
*/
public int selectUserIdWherePageCount(Integer userId);
}
(3)编写业务接口实现类
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 selectPostWherePage(int currentPage) {
HashMap map = new HashMap();
PageBean pageBean = new PageBean();
//封装当前页数
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 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 selectUserIdWherePage(int currentPage,int userId) {
PageBean pageBean = new PageBean();
Map paramMap = new HashMap();
//封装当前页数
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 lists = postMapper.selectUserIdWherePage(paramMap);
pageBean.setLists(lists);
return pageBean;
}
}
(4)对应的Spring的xml文件内容
通过这段例子,我想大家应该明白了什么是依赖注入,如果不这样写的话,你前台要想获得对应的数据访问层(DAO层)数据,必须得实例化,十几二十个还好管理,成千上万个呢?那估计你肯定会有骂娘的冲动了。同时也明白了Spring为你管理对象的好处。如果没有Spring为你管理对象,一个一个实例化,那将是一件非常恐惧的事情。
1.3 AOP特性
1.3.1 AOP简介
Spring的一个关键组件是面向切面编程(AOP)框架。跨越应用程序多个点的功能称为跨领域问题,这些跨领域问题在概念上与应用程序的业务逻辑分开。各方面有各种常见的良好示例,包括日志记录,声明式事务,安全性,缓存等。
OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面。DI可帮助您将应用程序对象彼此分离,而AOP可帮助您将交叉问题与它们所影响的对象分离。
Spring Framework的AOP模块提供了面向方面的编程实现,允许您定义方法拦截器和切入点,以便干净地解耦实现应该分离的功能的代码。
1.3.2 AOP实例
就拿Spring的xml注解事务配置讲解:
(1)spring-mybatis.xml事务配置部分内容
上述内容,比如配置切面,这个切面相当于不管怎么样你必定会经过的,比如电视中山大王经常去某个必经之路抢经过路人的钱财。
当然了,上面的配置,主要是关于事务的。熟悉xml事务配置的,对于上面xml代码再熟悉不过了。
不熟悉的也没有关系,用多了自然明白。另外补充一点,上面同时也代表了一种规则,比如我的添加方法叫userAdd,但是我的事务配置了必须要以add或者append或者其他read-only为false开头的才能在数据库对应的表新增数据,现在我的添加方法叫userAdd,它就会触发该规则中包含的另外一种规则就是:
这样一来,大家或许就知道它的应用了,如果是传统的那种Java编程(非Spring),我们将要写很多判断。
1.4 事务
1.4.1 事务简介
这里说到的事务主要是指数据库事务。数据库事务是一个被视为单一的工作单元的操作序列。这些操作要么完全地执行,要么完全不执行。事务管理是一个重要组成部分,RDBMS 面向企业应用程序,以确保数据完整性和一致性。
事务的概念可以描述为具有以下四个关键属性说成是ACID:
(1)原子性:事务应该当作一个单独单元的操作,这意味着整个序列操作要么是成功,要么是失败的;
(2)一致性:这表示数据库的引用完整性的一致性,表中唯一的主键等;
(3)隔离性:可能同时处理很多有相同的数据集的事务,每个事务应该与其他事务隔离,以防止数据损坏;
(4)持久性:一个事务一旦完成全部操作后,这个事务的结果必须是永久性的,不能因系统故障而从数据库中删除。
一个真正的 RDBMS 数据库系统将为每个事务保证所有的四个属性。使用 SQL 发布到数据库中的事务的简单视图如下:
(1)使用 begin transaction 命令开始事务。
(2)使用 SQL 查询语句执行各种删除、更新或插入操作。
(3)如果所有的操作都成功,则执行提交操作,否则回滚所有操作。
Spring 框架在不同的底层事务管理 APIs 的顶部提供了一个抽象层。Spring 的事务支持旨在通过添加事务能力到 POJOs 来提供给 EJB 事务一个选择方案。Spring 支持编程式和声明式事务管理。EJBs 需要一个应用程序服务器,但 Spring 事务管理可以在不需要应用程序服务器的情况下实现。
1.4.2 两种事务(局部事务与全局事务)
局部事务是特定于一个单一的事务资源,如一个 JDBC 连接,而全局事务可以跨多个事务资源事务,如在一个分布式系统中的事务。
局部事务管理在一个集中的计算环境中是有用的,该计算环境中应用程序组件和资源位于一个单位点,而事务管理只涉及到一个运行在一个单一机器中的本地数据管理器。局部事务更容易实现。
全局事务管理需要在分布式计算环境中,所有的资源都分布在多个系统中。在这种情况下事务管理需要同时在局部和全局范围内进行。分布式或全局事务跨多个系统执行,它的执行需要全局事务管理系统和所有相关系统的局部数据管理人员之间的协调。
1.4.3 事务管理的两种形式
Spring 支持两种类型的事务管理:
编程式事务管理:这意味着你在编程的帮助下有管理事务。这给了你极大的灵活性,但却很难维护(编程管理事务,一大堆if-else等各种判断,代码量大先不说,但是以后维护起来会使你有种想跳楼的冲动)。
声明式事务管理:这意味着你从业务代码中分离事务管理。你仅仅使用注解或 XML 配置来管理事务(前面的AOP示例就很好地体现了XML管理事务)。
声明式事务管理比编程式事务管理更可取,尽管它不如编程式事务管理灵活,但它允许你通过代码控制事务。但作为一种横切关注点,声明式事务管理可以使用 AOP 方法进行模块化。Spring 支持使用 Spring AOP 框架的声明式事务管理。
1.5 MyBatis集成Spring
1.5.1 新建Maven项目导入依赖
这里的依赖不仅仅包括MyBatis整合Spring的必需依赖,同时也包含SpringMVC的依赖,之所以导入是为了后面的复用。
4.0.0
cn.demo.test
test001
0.0.1-SNAPSHOT
war
junit
junit
3.8.1
test
org.springframework
spring-test
4.3.13.RELEASE
org.springframework
spring-webmvc
4.3.13.RELEASE
org.springframework
spring-core
4.3.13.RELEASE
org.springframework
spring-aop
4.3.13.RELEASE
aspectj
aspectjweaver
1.5.4
aspectj
aspectjrt
1.5.4
org.codehaus.jackson
jackson-mapper-asl
1.9.11
org.mybatis
mybatis
3.1.1
org.mybatis
mybatis-spring
1.1.1
mysql
mysql-connector-java
5.1.21
c3p0
c3p0
0.9.1.2
jar
org.slf4j
slf4j-api
1.7.5
org.slf4j
slf4j-log4j12
1.7.5
log4j
log4j
1.2.17
jstl
jstl
1.2
org.springframework
spring-context-support
4.3.13.RELEASE
javax.servlet.jsp
javax.servlet.jsp-api
2.2.1
provided
javax.servlet
javax.servlet-api
3.1.0
provided
org.springframework
spring-web
4.3.13.RELEASE
org.springframework
spring-webmvc
4.3.13.RELEASE
com.alibaba
fastjson
1.2.41
org.apache.commons
commons-dbcp2
2.1.1
com.google.code.gson
gson
2.2.4
org.apache.commons
commons-lang3
3.3.2
org.apache.maven.plugins
maven-compiler-plugin
2.0.2
1.8
1.8
1.5.2 建立实体类和相应的mapper以及xml
(1)编写POJO
package cn.entity;
public class User {
private Integer Id;
private String userName;
private String PassWord;
public Integer getId() {
return Id;
}
public void setId(Integer id) {
Id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return PassWord;
}
public void setPassWord(String passWord) {
PassWord = passWord;
}
}
(2)编写数据访问层接口
package cn.mapper;
import cn.entity.User;
public interface UserMapper {
public User selectUserInfo(String userName);
}
(3)编写XML配置文件
1.5.3 建立service以及service的实现类
(1)编写业务接口
package cn.service;
import cn.entity.User;
public interface UserService {
public User selectUserInfo(String userName);
}
(2)编写业务接口实现类
package cn.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.entity.User;
import cn.mapper.UserMapper;
import cn.service.UserService;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User selectUserInfo(String userName) {
// TODO Auto-generated method stub
return userMapper.selectUserInfo(userName);
}
}
1.5.4 编写mybatis整合spring相关的配置文件
application-config.xml
mybatis-config.xml
log4j.properties
#config root logger
log4j.rootLogger = INFO,system.out
log4j.appender.system.out=org.apache.log4j.ConsoleAppender
log4j.appender.system.out.layout=org.apache.log4j.PatternLayout
log4j.appender.system.out.layout.ConversionPattern=[Log] %5p[%F:%L]:%m%n
#config this Project.file logger
log4j.logger.thisProject.file=INFO,thisProject.file.out
log4j.appender.thisProject.file.out=org.apache.log4j.DailyRollingFileAppender
log4j.appender.thisProject.file.out.File=logContentFile.log
log4j.appender.thisProject.file.out.layout=org.apache.log4j.PatternLayout
1.5.5 单元测试确保application-config.xml和mybatis-config.xml配置正确
package cn.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import cn.entity.User;
import cn.mapper.UserMapper;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application-config.xml")
public class JunitTest {
@Autowired
private UserMapper userMapper;
@Test
public void testName() throws Exception {
User user = userMapper.selectUserInfo("youcong");
System.out.println(user.getPassWord());
}
}
运行出来输出对应的信息,说明配置没有问题,同时也说明的MyBatis成功整合Spring。
1.6 小结
通过本章的学习,我相信你对Spring会有一个大致的了解,另外本章动手实践的只有一个MyBatis整合Spring的例子,其实本章可以有很多例子,笔者因为时间缘故就没有写太多,当然了,还考虑到本章肯定会非常长,所以例子也没有写太多,不过读者请放心,后续会有更多的补充,这种更多的补充,不仅对读者有帮助,同时对笔者个人也有帮助。
本文部分内容来自:笔者博客园