Spring框架
Spring框架
一、Spring核心概念
1、Spring框架优点
1.1 方便解耦,简化开发 IOC/DI
1.2 AOP编程支持
@Before
INewsMapper
@After
1.3 声明式事务支持
1.4 Spring支持Junit测试
1.5 降低JavaEE api使用难度
2、Spring框架核心
IOC
控制反转:将控制权转移,以前是由对象自身维护关系,转移给Spring容器进行管理
IOC是一种思想,是Spring框架的核心,贯穿始终,就是管理Spring容器中的对象的声明周期和依赖关系,降低对象与对象之间的耦合
DI:依赖注入
是IOC思想的实现方式
AOP:面向切面编程,专心做事~,程序员主要处理程序逻辑,其余的例如权限判断,日志生成等都有AOP来做
二、Spring环境搭建
1、 导入Spring核心依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
2、创建Spring大配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
3、 案例,向Spring容器中注入一个对象
2.3.1 创建一个类,当做一个对象
2.3.2 将对象注入到容器当中去
<!--bean代表注入的对象
id属性代表bean的唯一标识,后去对象依赖或者调用该对象时,通过id调用
class代表对象类型,需要写全路径
-->
<bean id="student" class="com.wdksoft.entity.Student">
<!--在给对象属性赋值时,属性必须包含Set访问器,匹配规则如下:set+属性名(开头大写)-->
<property name="stuId" value="1"/>
<property name="stuName" value="柴英杰"/>
</bean>
2.3.3 测试,调用注入的对象
@Test
public void beanTest() {
//步骤一:加载Spring大配置文件,返回值为Spring上下文
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//步骤二:调用注入的Bean 根据bean的id属性值调用
/* Student student = (Student)applicationContext.getBean("student");
student.sayHi();*/
//根据类型调用
Student stu = (Student)applicationContext.getBean("student01");
stu.sayHi();
}
三、域属性注入
域属性注入,在Student类中,植入Teacher对象
<bean id="student" class="com.wdksoft.entity.Student">
<!--在给对象属性赋值时,属性必须包含Set访问器,匹配规则如下:set+属性名(开头大写)-->
<property name="stuId" value="1"/>
<property name="stuName" value="柴英杰"/>
<!--域属性引用 ref代表引用,引用bean的ID-->
<property name="teacher" ref="teacher"/>
</bean>
<!--注入Teacher对象-->
<bean id="teacher" class="com.wdksoft.entity.Teacher">
<property name="tId" value="1"/>
<property name="tName" value="山间的风"/>
</bean>
2.4.2 测试
@Test
public void beanTest() {
//步骤一:加载Spring大配置文件,返回值为Spring上下文
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//步骤二:调用注入的Bean 根据bean的id属性值调用
/* Student student = (Student)applicationContext.getBean("student");
student.sayHi();*/
//根据类型调用
Student stu = (Student)applicationContext.getBean("student");
stu.sayHi();
}
1、打印机案例
1. 准备纸张和墨盒接口
public interface Ink {
//获取颜色的方法
public String getColor();
}
public interface Paper {
//获取纸张大小方法
public String getSize();
}
2. 准备纸张和墨盒接口实现类
public class ColorInk implements Ink{
@Override
public String getColor() {
return "彩色";
}
}
public class GrayInk implements Ink{
@Override
public String getColor() {
return "黑白";
}
}
public class A4Paper implements Paper{
@Override
public String getSize() {
return "A4";
}
}
public class B5Paper implements Paper{
@Override
public String getSize() {
return "B5";
}
}
3. 准备一个打印机,调用纸张和墨盒
public class Print {
//准备墨盒
private Ink ink;
//准备纸张
private Paper paper;
//打印方法
public void printCosole(){
System.out.println("您正在使用:"+ink.getColor()+"墨盒和:"+paper.getSize()+"纸张打印内容~");
}
public Ink getInk() {
return ink;
}
public void setInk(Ink ink) {
this.ink = ink;
}
public Paper getPaper() {
return paper;
}
public void setPaper(Paper paper) {
this.paper = paper;
}
}
4. 将纸张,墨盒,打印机注入到容器当中
<!--准备墨盒-->
<bean id="grayink" class="com.wdksoft.print.ink.GrayInk"></bean>
<bean id="colorink" class="com.wdksoft.print.ink.ColorInk"></bean>
<!--准备纸张-->
<bean id="a4paper" class="com.wdksoft.print.paper.A4Paper"></bean>
<bean id="b5paper" class="com.wdksoft.print.paper.B5Paper"></bean>
<!--打印机-->
<bean id="print" class="com.wdksoft.print.Print">
<property name="ink" ref="colorink"/>
<property name="paper" ref="a4paper"/>
</bean>
5.测试
@Test
public void printTest() {
//步骤一:加载Spring大配置文件,返回值为Spring上下文
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//步骤二:调用注入的Bean 根据bean的id属性值调用
Print print=(Print) applicationContext.getBean("print");
print.printCosole();
}
四、Spring的注入方式
1、基于XML版本的DI注入
1.1、基于setter方法注入属性
<!--基于Setter方法注入,属性必须有set方法,setStuName-->
<bean id="student" class="com.wdksoft.Student">
<property name="stuName" value="柴英杰"/>
<property name="stuId" value="1"/>
</bean>
@Test
public void setter(){
//加载配置文件
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
//调用getBean
Student student = (Student)applicationContext.getBean("student");
System.out.println(student.toString());
}
1.2、基于构造方法注入
<!--基于构造方法注入:必须完全指定参数值-->
<bean id="constructorStu" class="com.wdksoft.Student">
<!--name代表参数名字 value代表值 ref代表引用(类型,不能与value同时存在)
type代表属性类型
-->
<!--<constructor-arg name="stuId" value="2"/>
<constructor-arg name="stuName" value="冯旭东" />-->
<!--index代表参数下标-->
<constructor-arg index="0" value="2"/>
<constructor-arg index="1" value="冯旭东" />
</bean>
@Test
public void constructor(){
//加载配置文件
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
//调用getBean
Student student = (Student)applicationContext.getBean("constructorStu");
System.out.println(student.toString());
}
1.3、P命名空间注入,基于setter
1.3.1 在大配置文件头导入p命名空间 xmlns:p="http://www.springframework.org/schema/p"
1.3.2 大配置文件配置
<bean id="pStu" class="com.wdksoft.Student" p:stuId="3" p:stuName="安静的周健美男子"/>
1.4、不同数据格式注入方式
<!--注入不同类型数据-->
<bean id="conllectionDI" class="com.wdksoft.ConllectionDI">
<!--数组类型注入-->
<property name="args">
<array>
<value>arg01</value>
<value>arg02</value>
</array>
</property>
<!--list单列集合注入-->
<property name="strList">
<list>
<!--引用复杂类型-->
<ref bean="pStu"/>
<value>list02</value>
</list>
</property>
<!--set单列集合-->
<property name="strSet">
<set>
<value>set01</value>
<!--引用复杂类型-->
<ref bean="constructorStu"/>
</set>
</property>
<!--map双列集合-->
<property name="strMap">
<map>
<entry key="mapkey01" value="mapvalue01"/>
<!--引用复杂类型-->
<entry key="mapkeystu" value-ref="student"/>
</map>
</property>
<!--配置类型-->
<property name="properties">
<props>
<prop key="jdbc.driver">com.mysql.jdbc.Driver</prop>
<prop key="jdbc.url">jdbc:mysql://localhost:3306/myschool</prop>
<prop key="jdbc.username">root</prop>
<prop key="jdbc.password">root</prop>
</props>
</property>
</bean>
2、Spring自动依赖注入
2.1 no默认值
代表Spring不会进行自动的依赖注入
2.2 byName
根据依赖的属性名匹配容器当中Bean 的ID,如果ID相同,则注入,否则不进行注入
<bean id="student" class="com.wdksoft.Student" autowire="byName">
<property name="stuName" value="柴英杰"/>
<property name="stuId" value="1"/>
</bean>
<bean id="teacher" class="com.wdksoft.Teacher">
<property name="tId" value="1"/>
<property name="tName" value="山间的风"/>
</bean>
2.3 byType
根据依赖对象的类型进行注入,如果没有则不注入,如果容器中有且只有一个则注入,如果容器中有多个则会抛出异常
<bean id="student" class="com.wdksoft.Student" autowire="byType">
<property name="stuName" value="柴英杰"/>
<property name="stuId" value="1"/>
</bean>
<bean id="teacher" class="com.wdksoft.Teacher">
<property name="tId" value="1"/>
<property name="tName" value="山间的风"/>
</bean>
3、基于注解版本的IOC和DI
3.1、前提条件:大配置文件,加入扫描注解
<!--扫描注解-->
<context:component-scan base-package="com.wdksoft"/>
3.2注解IOC是将对象注入到容器中的
@Component :将当前对象当做Bean注入到容器当中去 @Bean
@Repository : 专门注入Mapper层接口
@Service:专门注入Service层对象
@Controller:专门注入Controller层
3.3、DI注解调用
@Resource byName自动注入,如果名字注入失败就根据类型
@Autowired byType注入,如果发生类型重复,可以使用@Qualifier指定Bean名称
3.4、@Component案例
@Component("student") //将对象当做Bean注入到容器当中去
public class Student {
public Integer stuId=1;
public String stuName="张三";
@Override
public String toString() {
return "Student{" +
"stuId=" + stuId +
", stuName='" + stuName + '\'' +
'}';
}
}
@Test
public void component(){
//加载配置文件
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
//调用getBean
Student student = (Student)applicationContext.getBean("student");
System.out.println(student.toString());
}
Service和Mapper注入和依赖:
Mapper层接口:
public interface INewsMapper {
public String sayHi();
}
Mapper层接口实现类:
@Repository
/**
* <bean id="iNewsMapper" class="INewsMapperImpl"></bean>
* 正常开发@Repository写在接口上,不用写Mapper实现类,Myabtis小配置文件就可以当做实现类,但是Spring容器中不允许注入接口,
* Spring和Myabtis整合时,可以通过特定类扫描Mapper接口,能够帮助你将接口注入到容器当中去
*/
public class INewsMapperImpl implements INewsMapper {
@Override
public String sayHi() {
return "Mapper层接口实现类的方法返回值";
}
}
Service层接口:
public interface INewsService {
public String sayHi();
}
Service层接口实现类:
@Service("iNewsService")
public class INewsServiceImpl implements INewsService {
//植入Mapper层对象
@Resource //获取容器中的INewsMapper对象
private INewsMapper abc;
@Override
public String sayHi() {
return abc.sayHi();
}
}
测试类:
@Test
public void service(){
//加载配置文件
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
//调用getBean
INewsService iNewsService = (INewsService)applicationContext.getBean("iNewsService");
System.out.println(iNewsService.sayHi());
}
五、AOP面向切面编程
1、SpringAOP概念
专心做事,主要关注业务逻辑,其余的操作可以抽离成公共模块,进行增强处理
AOP原理:在不改变原对象的基础之上,生成代理对象,在代理对象做增强处理
2、AOP专业术语
1)连接点(Joinpoint)
程序执行的某个特定位置:如类开始初始化前、类初始化后、类某个方法调用前、调用后、方法抛出异常后。一个类或一段程序代码拥有一些具有边界性质的特定点,这些点中的特定点就称为“连接点”。Spring仅支持方法的连接点,即仅能在方法调用前、方法调用后、方法抛出异常时以及方法调用前后这些程序执行点织入增强。连接点由两个信息确定:第一是用方法表示的程序执行点;第二是用相对点表示的方位。
2)切点(Pointcut)
每个程序类都拥有多个连接点,如一个拥有两个方法的类,这两个方法都是连接点,即连接点是程序类中客观存在的事物。AOP通过“切点”定位特定的连接点。连接点相当于数据库中的记录,而切点相当于查询条件。切点和连接点不是一对一的关系,一个切点可以匹配多个连接点。在Spring中,切点通过org.springframework.aop.Pointcut接口进行描述,它使用类和方法作为连接点的查询条件,Spring AOP的规则解析引擎负责切点所设定的查询条件,找到对应的连接点。其实确切地说,不能称之为查询连接点,因为连接点是方法执行前、执行后等包括方位信息的具体程序执行点,而切点只定位到某个方法上,所以如果希望定位到具体连接点上,还需要提供方位信息。
3)增强(Advice)
增强是织入到目标类连接点上的一段程序代码,在Spring中,增强除用于描述一段程序代码外,还拥有另一个和连接点相关的信息,这便是执行点的方位。结合执行点方位信息和切点信息,我们就可以找到特定的连接点。
4)目标对象(Target)
增强逻辑的织入目标类。如果没有AOP,目标业务类需要自己实现所有逻辑,而在AOP的帮助下,目标业务类只实现那些非横切逻辑的程序逻辑,而性能监视和事务管理等这些横切逻辑则可以使用AOP动态织入到特定的连接点上。
5)引介(Introduction)
引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过AOP的引介功能,我们可以动态地为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
6)织入(Weaving)
织入是将增强添加对目标类具体连接点上的过程。AOP像一台织布机,将目标类、增强或引介通过AOP这台织布机天衣无缝地编织到一起。根据不同的实现技术,AOP有三种织入的方式:
a、编译期织入,这要求使用特殊的Java编译器。
b、类装载期织入,这要求使用特殊的类装载器。
c、动态代理织入,在运行期为目标类添加增强生成子类的方式。
Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
7)代理(Proxy)
一个类被AOP织入增强后,就产出了一个结果类,它是融合了原类和增强逻辑的代理类。根据不同的代理方式,代理类既可能是和原类具有相同接口的类,也可能就是原类的子类,所以我们可以采用调用原类相同的方式调用代理类。
8)切面(Aspect)
切面由切点和增强(引介)组成,它既包括了横切逻辑的定义,也包括了连接点的定义,Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。
3、AOP第一个案例
3.1 模拟业务逻辑
Mapper层:
public interface IUserInfoMapper {
//添加用户
public int addUser(UserInfo info);
}
MapperImpl层:
public class IUserInfoMapperImpl implements IUserInfoMapper {
@Override
public int addUser(UserInfo info) {
System.out.println("===mapper层addUser方法===");
return 0;
}
}
Service层:
public interface IUserInfoService {
//添加用户
public int addUser(UserInfo info);
}
ServiceImpl层:
public class IUserInfoServiceImpl implements IUserInfoService {
//植入Mapper层对象
private IUserInfoMapper iUserInfoMapper;
@Override
public int addUser(UserInfo info) {
System.out.println("===Service层的业务方法===");
return iUserInfoMapper.addUser(info);
}
public IUserInfoMapper getiUserInfoMapper() {
return iUserInfoMapper;
}
public void setiUserInfoMapper(IUserInfoMapper iUserInfoMapper) {
this.iUserInfoMapper = iUserInfoMapper;
}
}
3.2向容器中注入业务对象
<!--注入Mapper层对象-->
<bean id="iUserInfoMapper" class="com.wdksoft.mapper.impl.IUserInfoMapperImpl"></bean>
<!--注入Service层对象-->
<bean id="iUserInfoService" class="com.wdksoft.service.impl.IUserInfoServiceImpl">
<property name="iUserInfoMapper" ref="iUserInfoMapper"/>
</bean>
3.2 导入依赖:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
3.2 定义切面增强类:
前置增强:MethodBeforeAdvice,重写before方法 Method代表目标方法 args代表目标方法的参数 target目标对象
public class MyBefore implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("-----------------------日志处理--------------------------------");
}
}
后置增强:
public class MyAfter implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("-----------------事务处理-----------------------------");
}
}
3.3 将增强对象注入到容器当中
<!--注入增强类-->
<bean id="myBefore" class="com.wdksoft.advice.MyBefore"></bean>
<bean id="myAfter" class="com.wdksoft.advice.MyAfter"></bean>
3.4 找到切点,将切点和增强类织入到一起
<!--aop增强处理-->
<aop:config>
<!--定义切点和连接点-->
<aop:pointcut id="pointcut" expression="execution(* *..service.*.*(..))"/>
<!--织入:将增强和切点织入到一起 advice-ref代表Advice增强类的引用 pointcut-ref切点-->
<aop:advisor advice-ref="myBefore" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="myAfter" pointcut-ref="pointcut"/>
</aop:config>
4、配置方式实现AOP增强
自定义增强类,自定义增强方法
public class MyAdvice {
public void before(){
System.out.println("********************日志记录***********************");
}
public void after(){
System.out.println("********************事务处理***********************");
}
}
配置applcationContext.xml文件
1.将增强类注入到容器
<!--注入增强类-->
<bean id="myAdvice" class="com.wdksoft.advice.MyAdvice"/>
2.指定增强配置
<!--配置AOP-->
<aop:config>
<!--切点-->
<aop:pointcut id="pointcut" expression="execution(* *..service.*.*(..))"/>
<!--织入增强 ref指定自定义增强类-->
<aop:aspect ref="myAdvice">
<!--method代表增强类中的方法-->
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after-returning method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
5、环绕增强
public class MyRoundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("-------------------环绕前--------------------");
//执行业务方法
Object proceed = invocation.proceed();
System.out.println("-------------------环绕后--------------------");
return proceed;
}
}
配置applcationContext.xml文件
<bean id="myRoundAdvice" class="com.wdksoft.advice.MyRoundAdvice"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* *..service.*.*(..))"/>
<aop:advisor advice-ref="myRoundAdvice" pointcut-ref="pointcut"/>
</aop:config>
6、异常增强
实现ThrowsAdvice接口,方法定义参考接口源码
public class MyExceptionAdvice implements ThrowsAdvice {
public void afterThrowing(Exception ex) {
System.out.println("================异常增强==================");
}
}
配置applcationContext.xml文件
<bean id="myExceptionAdvice" class="com.wdksoft.advice.MyExceptionAdvice"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* *..service.*.*(..))"/>
<aop:advisor advice-ref="myExceptionAdvice" pointcut-ref="pointcut"/>
</aop:config>
7、最终增强After
无论如何都执行
五、AOP面向切面编程
1、SpringAOP概念
专心做事,主要关注业务逻辑,其余的操作可以抽离成公共模块,进行增强处理
AOP原理:在不改变原对象的基础之上,生成代理对象,在代理对象做增强处理
2、AOP专业术语
3、AOP第一个案例
3.1 模拟业务逻辑
Mapper层:
public interface IUserInfoMapper {
//添加用户
public int addUser(UserInfo info);
}
MapperImpl层:
public class IUserInfoMapperImpl implements IUserInfoMapper {
@Override
public int addUser(UserInfo info) {
System.out.println("===mapper层addUser方法===");
return 0;
}
}
Service层:
public interface IUserInfoService {
//添加用户
public int addUser(UserInfo info);
}
ServiceImpl层:
public class IUserInfoServiceImpl implements IUserInfoService {
//植入Mapper层对象
private IUserInfoMapper iUserInfoMapper;
@Override
public int addUser(UserInfo info) {
System.out.println("===Service层的业务方法===");
return iUserInfoMapper.addUser(info);
}
public IUserInfoMapper getiUserInfoMapper() {
return iUserInfoMapper;
}
public void setiUserInfoMapper(IUserInfoMapper iUserInfoMapper) {
this.iUserInfoMapper = iUserInfoMapper;
}
}
3.2向容器中注入业务对象
<!--注入Mapper层对象-->
<bean id="iUserInfoMapper" class="com.wdksoft.mapper.impl.IUserInfoMapperImpl"></bean>
<!--注入Service层对象-->
<bean id="iUserInfoService" class="com.wdksoft.service.impl.IUserInfoServiceImpl">
<property name="iUserInfoMapper" ref="iUserInfoMapper"/>
</bean>
3.2 导入依赖:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
3.2 定义切面增强类:
前置增强:MethodBeforeAdvice,重写before方法 Method代表目标方法 args代表目标方法的参数 target目标对象
public class MyBefore implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("-----------------------日志处理--------------------------------");
}
}
后置增强:
public class MyAfter implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("-----------------事务处理-----------------------------");
}
}
3.3 将增强对象注入到容器当中
<!--注入增强类-->
<bean id="myBefore" class="com.wdksoft.advice.MyBefore"></bean>
<bean id="myAfter" class="com.wdksoft.advice.MyAfter"></bean>
3.4 找到切点,将切点和增强类织入到一起
<!--aop增强处理-->
<aop:config>
<!--定义切点和连接点-->
<aop:pointcut id="pointcut" expression="execution(* *..service.*.*(..))"/>
<!--织入:将增强和切点织入到一起 advice-ref代表Advice增强类的引用 pointcut-ref切点-->
<aop:advisor advice-ref="myBefore" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="myAfter" pointcut-ref="pointcut"/>
</aop:config>
4、配置方式实现AOP增强
自定义增强类,自定义增强方法
public class MyAdvice {
public void before(){
System.out.println("********************日志记录***********************");
}
public void after(){
System.out.println("********************事务处理***********************");
}
}
配置applcationContext.xml文件
1.将增强类注入到容器
<!--注入增强类-->
<bean id="myAdvice" class="com.wdksoft.advice.MyAdvice"/>
2.指定增强配置
<!--配置AOP-->
<aop:config>
<!--切点-->
<aop:pointcut id="pointcut" expression="execution(* *..service.*.*(..))"/>
<!--织入增强 ref指定自定义增强类-->
<aop:aspect ref="myAdvice">
<!--method代表增强类中的方法-->
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after-returning method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
5、环绕增强
public class MyRoundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("-------------------环绕前--------------------");
//执行业务方法
Object proceed = invocation.proceed();
System.out.println("-------------------环绕后--------------------");
return proceed;
}
}
配置applcationContext.xml文件
<bean id="myRoundAdvice" class="com.wdksoft.advice.MyRoundAdvice"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* *..service.*.*(..))"/>
<aop:advisor advice-ref="myRoundAdvice" pointcut-ref="pointcut"/>
</aop:config>
6、异常增强
实现ThrowsAdvice接口,方法定义参考接口源码
public class MyExceptionAdvice implements ThrowsAdvice {
public void afterThrowing(Exception ex) {
System.out.println("================异常增强==================");
}
}
配置applcationContext.xml文件
<bean id="myExceptionAdvice" class="com.wdksoft.advice.MyExceptionAdvice"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* *..service.*.*(..))"/>
<aop:advisor advice-ref="myExceptionAdvice" pointcut-ref="pointcut"/>
</aop:config>
7、最终增强After
无论如何都执行
六、代理模式
1、代理模式概况
1.1 代理模式:为了在添加功能时不修改原始对象,而是生成代理对象,方便扩展,解耦
1.2 代理模式分类:
1.2.1 静态代理:静态代理需要手工编写代理类,代理类引用被代理对象
1.2.2 动态代理:在内存中构建代理对象,不需要手动编写代理类
JDK动态代理
CGLIB动态代理
1.2.3 代理主题:
抽象主题(接口) 真实主题(实现类) 代理主题(代理实现类)
2、静态代理案例
1.3 静态代理:静态代理需要手动编写代理类,在代理类当中调用被代理对象
1.3.1 创建抽象主题
/**
* 抽象主题
*/
public interface Subject {
public void request();
}
1.3.2 创建真实主题
/**
* 真实主题
*/
public class SubjectImpl implements Subject{
@Override
public void request() {
System.out.println("真实主题重写方法==========================");
}
}
1.3.3 创建代理主题,调用真实主题
**
* 代理主题:静态代理在代理实现类中调用代理的目标对象
*/
public class ProxySubject implements Subject{
//注入真实对象
private Subject subject=new SubjectImpl();
@Override
public void request() {
System.out.println("==============日志产生==================");
subject.request();
System.out.println("==============后续处理==================");
}
}
1.3.4 测试
public class StaticProxyTest {
public static void main(String[] args) {
//创建代理对象
ProxySubject proxySubject=new ProxySubject();
proxySubject.request();
}
}
3、JDK动态代理案例
1.4 JDK动态代理:运行时期,在内存当中构建代理对象,代理的目标对象必须有接口
1.4.1 创建抽象主题
/**
* 抽象主题
*/
public interface IDoSome {
public void doSome();
}
1.4.2 创建真实主题
/**
* 真实主题
*/
public class IDoSomeImpl implements IDoSome{
@Override
public void doSome() {
System.out.println("===================真实主题的业务==============");
}
}
1.4.3 通过JDK提供的Proxy类创建代理对象,在Handler处理时调用目标方法
public static void main(String[] args) {
//植入目标对象
final IDoSome idoSome=new IDoSomeImpl();
//创建代理对象的实例
/**
* ClassLoader 目标对象的类加载器
* Interfaces 目标对象的接口类型
* InvocationHandler 实现增强的处理器
*/
IDoSome iDoSomeProxy = (IDoSome)Proxy.newProxyInstance(idoSome.getClass().getClassLoader(), idoSome.getClass().getInterfaces(), new InvocationHandler() {
/**
*
* @param proxy 被代理的目标对象
* @param method 目标对象的方法
* @param args 目标对象方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-----------------日志处理----------------------");
//执行被代理对象的方法 传递原始对象
Object invoke = method.invoke(idoSome, args);
System.out.println("-----------------后续处理----------------------");
return invoke;
}
});
iDoSomeProxy.doSome();
}
4、Cglib动态代理案例
1.5 CGLIB动态代理
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
1.5.1 CGLIB动态代理特点:编译时期在内存中生成代理对象,对于不适用接口的业务类,JDK动态代理无法处理,cglib采用非常底层的字节码技术,可以为一个类生成代理对象
1.5.2 创建真实主题
/**
* 真实主题
*/
public class CgLibInfo {
public void doSome(){
System.out.println("真实业务===============");
}
}
1.5.3 采用CGLIB实现动态代理
public static void main(String[] args) {
//步骤一:创建一个目标对象
final CgLibInfo info=new CgLibInfo();
//步骤二:创建代理生成类
Enhancer enhancer=new Enhancer();
//步骤三:指定代理模板,指定目标对象模板,获取对象内信息
enhancer.setSuperclass(info.getClass());
//步骤四:执行代理回调增强操作
enhancer.setCallback(new MethodInterceptor() {
/**
*
* @param o 被代理对象
* @param method 被代理对象的方法
* @param objects 被代理对象的参数
* @param methodProxy 代理对象的方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("-----------------日志处理----------------------");
//执行代理对象的目标方法
Object invoke = methodProxy.invoke(info, objects);
System.out.println("-----------------后续处理----------------------");
return invoke;
}
});
//步骤五:生成代理对象
CgLibInfo cgLibInfoProxy = (CgLibInfo)enhancer.create();
cgLibInfoProxy.doSome();
}
5、SpringAOP代理模式面试要点
1.SpringAOP代理模式:
代理生成对象取决于目标对象,如果目标对象包含接口,则采用JDK动态代理,如果目标对象不包含接口,则采用CGLIB动态代理
对比CGLIB和JDK动态代理:
1.JDK面向接口的,cglib是面向业务类的
2.JDK是在运行时期,CGLIB是在编译时期
3.在JDK1.6和1.7版本当中JDK比CGLIB慢,在JDK1.8版本JDK比CGLIB快
1.AOP概念,为什么使用AOP
2.AOP底层实现方式采用代理模式
分为JDK和CJLIB,区别为......
6、代理工厂模式
2.代理工厂方式实现AOP增强
2.1 创建核心业务
public interface IDoSomeService {
public void doSome();
}
public class IDoSomeServiceImpl implements IDoSomeService {
@Override
public void doSome() {
System.out.println("核心业务~~~~~~~~~~~~~~~~");
}
}
2.2 创建增强
public class MyBefore implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("====================日志记录==================");
}
}
public class MyAfter implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("==============后置增强=================");
}
}
2.3 使用代理工厂实现增强
<!--业务Bean注入-->
<bean id="iDoSomeService" class="com.wdksoft.service.impl.IDoSomeServiceImpl"/>
<!--增强-->
<bean id="myBefore" class="com.wdksoft.advice.MyBefore"/>
<bean id="myAfter" class="com.wdksoft.advice.MyAfter"/>
<!--代理工厂-->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--目标对象-->
<property name="target" ref="iDoSomeService"/>
<!--增强-->
<property name="interceptorNames" value="myBefore,myAfter"/>
</bean>
2.4 测试
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
IDoSomeService iDoSomeService=(IDoSomeService)applicationContext.getBean("proxyFactoryBean");
iDoSomeService.doSome();
}
7、 更换动态代理方式
在ProxyFactoryBean中配置,proxyTargetClass设置为true代表强制暴露代理,使用cglib,默认值为false
<property name="proxyTargetClass" value="true"/>
六、Spring顾问
1、通知和顾问
Advice切面/通知是Spring框架提供的一种切面(aspectj),但是这种切面功能过于简单,只能将切面织入到目标类的所有方法当中,无法完成将切面织入到目标方法当中
顾问Advisor是Spring提供的另外一种切面的方式,可以完成复杂功能,能选择性的植入目标方法当中
2、顾问案例
pointcutAdvisor是顾问的一个接口,接口下有一个NameMatchMethodPointcutAdvisor名称匹配方法切入点顾问
1.1 业务类
public class IDoSomeService {
public void doSome(){
System.out.println("============doSome方法业务===============");
}
public void service(){
System.out.println("============service方法业务===============");
}
}
1.2 增强类
public class MyAdvice implements MethodBeforeAdvice, AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("=================后置增强===================");
}
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("=================前置增强===================");
}
}
1.3 配置大配置文件,利用顾问管理增强Advice(通知),目标方法
<!--注入业务类-->
<bean id="iDoSomeService" class="com.wdksoft.service.IDoSomeService"/>
<!--注入增强类-->
<bean id="myAdvice" class="com.wdksoft.advisor.MyAdvice"/>
<!--配置顾问:管理切面-->
<bean id="advisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<!--增强-->
<property name="advice" ref="myAdvice"/>
<!--目标方法 value代表目标方法的名称-->
<property name="mappedNames" value="doSome"/>
</bean>
<!--代理工厂-->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="iDoSomeService"/>
<!--顾问-->
<property name="interceptorNames" value="advisor"/>
</bean>
1.4 测试
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
IDoSomeService iDoSomeService=(IDoSomeService)applicationContext.getBean("proxyFactoryBean");
iDoSomeService.doSome();
System.out.println("********************************************************************************");
iDoSomeService.service();
}
3、顾问的自动代理:匹配正则表达式
2.1 默认顾问自动代理生成器 DefaultAdvisorAutoProxyCreator,只能匹配顾问,可以匹配多个顾问 所有的业务Bean都会执行增强
<!--注入业务类-->
<bean id="iDoSomeService" class="com.wdksoft.service.IDoSomeService"/>
<!--注入增强类-->
<bean id="myAdvice" class="com.wdksoft.advisor.MyAdvice"/>
<!--正则匹配方法切点顾问-->
<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!--增强-->
<property name="advice" ref="myAdvice"/>
<!--匹配方法格式
. 代表任意单个字符
+ 表示一个字符出现一次或者多次
* 标识前一个字符出现0-n
-->
<property name="patterns" value=".*do.*"/>
</bean>
<!--默认顾问自动代理生成器 只能管理顾问-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
2.2 名称匹配方法代理生成器,可以选择性的对bean进行增强,可以配置顾问或者通知
<!--顾问-->
<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!--通知-->
<property name="advice" ref="myAdvice"/>
<!--匹配方法-->
<property name="patterns" value=".*do.*"/>
</bean>
<!--BeanName自动代理生成器 可以指定业务Bean 支持通知和顾问-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!--匹配Bean的名称-->
<property name="beanNames" value="iDoSomeService"/>
<!--指定通知或者顾问-->
<property name="interceptorNames" value="advisor"/>
</bean>
八、AOP注解
1、开启注解支持
<!--开启注解扫描-->
<context:component-scan base-package="com.wdksoft"/>
<!--开启AOP注解支持-->
<aop:aspectj-autoproxy/>
2、定义目标业务类,将目标业务类注入到容器当中
@Service("iUserInfoService")
public class IUserInfoService {
public int addUser(){
System.out.println("添加用户的业务==================");
return 1;
}
}
3、定义增强类,将增强类注入到容器当中,并且在增强类中指定增强
@Component //代表将增强类注入到容器当中
@Aspect //代表当前是增强类
public class MyAopAdvice {
//定义切点
@Pointcut("execution(* *..service.*.*(..))")
public void pointcut(){
}
@Before("pointcut()")
public void before(){
System.out.println("======================前置增强:日志记录====================");
}
@AfterReturning("pointcut()")
public void after(){
System.out.println("======================后置增强:日志记录====================");
}
}
4、测试
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
IUserInfoService iUserInfoService=(IUserInfoService)applicationContext.getBean("iUserInfoService");
iUserInfoService.addUser();
}
六、Spring整合JDBCTemplate
1、Spring概述
Spring提供的组件,jdbcTemplate在传统的JDBC上做了一些封装,使用Spring进行注入,可以把DataSource注入Spring容器当中
JDBCTemplate处理了资源的创建和释放工作
1.1 execute方法:可以用于执行任何SQL语句,执行DDL语句
1.2 update方法以及batchUpdata方法:update方法一般用于增删改,batchUpdate方法一般用于批处理
1.3 query以及queryxxxxx:用于执行查询
1.4 call方法:用于调用存储过程以及函数
2、JDBTemplate用法
2.1 导入依赖,spring-jdbc依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
2.2 创建jdbc.properties文件存放数据库连接参数
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/studentdb
jdbc.user=root
jdbc.password=root
2.3 创建实体
2.4 创建Mapper层
public interface IStudentInfoMapper {
//查询所有学生信息
public List<StudentInfo> getAllStudent();
}
2.5 创建Mapper层实现类,继承JDBCDaoSupport
public class IStudentInfoMapperImpl extends JdbcDaoSupport implements IStudentInfoMapper {
@Override
public List<StudentInfo> getAllStudent() {
//获取JDBCTemplate对象
JdbcTemplate jdbcTemplate = getJdbcTemplate();
//执行查询
List<StudentInfo> stuList = jdbcTemplate.query("SELECT * FROM studentInfo", new RowMapper<StudentInfo>() {
//映射数据
/**
*
* @param rs 结果集
* @param rowNum 当前数据行号
* @return
* @throws SQLException
*/
@Override
public StudentInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
StudentInfo info = new StudentInfo();
info.setSid(rs.getInt("sid"));
info.setSname(rs.getString("sname"));
info.setSaddress(rs.getString("saddress"));
info.setSage(rs.getInt("sage"));
info.setSgender(rs.getString("sgender"));
info.setSemail(rs.getString("semail"));
return info;
}
});
return stuList;
}
}
2.6 创建Service层
public interface IStudentInfoService {
//查询所有学生信息
public List<StudentInfo> getAllStudent();
}
2.7 Service层IMPL实现类
public class IStudentInfoServiceImpl implements IStudentInfoService {
//植入Mapper层对象
private IStudentInfoMapper iStudentInfoMapper;
@Override
public List<StudentInfo> getAllStudent() {
return iStudentInfoMapper.getAllStudent();
}
public IStudentInfoMapper getiStudentInfoMapper() {
return iStudentInfoMapper;
}
public void setiStudentInfoMapper(IStudentInfoMapper iStudentInfoMapper) {
this.iStudentInfoMapper = iStudentInfoMapper;
}
}
3、 大配置文件
1.加载配置文件
2.创建dataSource
3.创建JDBCTemplate对象,关联dataSource数据源
4.注入Mapper层,关联JDBCTemplate
5.注入Service层
<!--加载配置文件-->
<context:property-placeholder location="classpath:datasource.properties"/>
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置jdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--将Mapper和Service注入到容器当中-->
<bean id="iStudentInfoMapper" class="com.wdksoft.mapper.impl.IStudentInfoMapperImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="iStudentInfoService" class="com.wdksoft.service.impl.IStudentInfoServiceImpl">
<property name="iStudentInfoMapper" ref="iStudentInfoMapper"/>
</bean>
4、注解方式实现JDBCTemplate
3.1 依赖,datasource.properties不变
3.2 向容器当中注入dataSource和JDBCTemplate对象
<!--加载配置文件-->
<context:property-placeholder location="classpath:datasource.properties"/>
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置jdbcTemplate-->
<bean class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
注意要扫描注解,否则无效
<!--扫描注解-->
<context:component-scan base-package="com.wdksoft"/>
3.3 将Mapper层注入到容器当中
@Repository
public class IStudentInfoMapperImpl implements IStudentInfoMapper {
}
3.4 在Mapper层获取JDBCTemplate对象
@Resource
private JdbcTemplate jdbcTemplate;
3.5 将Service层注入到容器当中
@Service("iStudentInfoService")
public class IStudentInfoServiceImpl implements IStudentInfoService {
}
3.6 Service调用容器中的Mapper
@Resource
private IStudentInfoMapper iStudentInfoMapper;
5、jdbcTemplate总结
1.查询数据时,如果查询返回多行数据可以采用query和queryForObject(使用rowMapper映射)
2.查询数据返回单行单列值时,可以使用queryForObject(指定返回值类型)
6、查询单列值
//查询sid为1的数据
public String getStudentNameById(Integer id);
MapperIMPL层:
@Override
public String getStudentNameById(Integer id) {
String sname = jdbcTemplate.queryForObject("select sname from studentinfo where sid=?",String.class,id);
return sname;
}
7、删除数据,利用preparedStatement
//删除
public Integer deleteStudent(Integer id);
MapperIMPL层:
@Override
public Integer deleteStudent(Integer id) {
int count = jdbcTemplate.update("delete from studentInfo where sid=?", id);
return count;
}
7、添加数据
8.1 mapper层
//添加一条学生信息
public int addStudent(StudentInfo info);
8.2 mapper层实现类
@Override
public int addStudent(StudentInfo info) {
//第一种
Object [] obj={info.getSname(),info.getSgender(),info.getSage()};
int update = jdbcTemplate.update("insert into studentinfo(sname,sgender,sage) values(?,?,?)",obj);
//第二种
/*String sql="insert into studentinfo(sname,sgender,sage) values(?,?,?)";
Object [] obj={info.getSname(),info.getSgender(),info.getSage()};
int update = jdbcTemplate.update(sql, obj);
System.out.println("返回值类型:"+update);*/
return update;
}
8.3 service层
//添加
public int addStudent(StudentInfo info);
8.4 service层实现类
@Override
public int addStudent(StudentInfo info) {
return iStudentInfoMapper.addStudent(info);
}
8.5 测试类
//添加学生信息
/* StudentInfo info=new StudentInfo();
info.setSname("帅气得超哥");
info.setSgender("男");
info.setSage(18);
int i = iStudentInfoService.addStudent(info);
System.out.println(info.toString()+i);*/
9、修改数据
9.1 mapper层
//修改一名学生信息数据
public int updateInfo(StudentInfo info);
9.2 mapper层实现类
@Override
public int updateInfo(StudentInfo info) {
Object [] obj={info.getSname(),info.getSgender(),info.getSage(),info.getSid()};
int update = jdbcTemplate.update("update studentinfo set sname=?,sgender=?,sage=? where sid=?", obj);
return update;
}
9.3 service层
//修改一名学生信息数据
public int updateInfo(StudentInfo info);
9.4 service层实现类
@Override
public int updateInfo(StudentInfo info) {
return iStudentInfoMapper.updateInfo(info);
}
9.5 测试类
//修改
StudentInfo info=new StudentInfo();
info.setSid(5);
info.setSname("超哥");
info.setSgender("男");
info.setSage(18);
int i = iStudentInfoService.updateInfo(info);
System.out.println(info.toString());
六、spring事务管理
1、spring事务概述
1.事务:事务是一个整体,内部包含了一批SQL语句,事务提交要么都成功,要么都失败,事务也可以执行回滚
Spring提供事务平台管理器:PlatFormTransationManager,可以实现对各个框架进行事务管理操作
2、事务的四大特性:ACID
2.1 原子性(Atomicity),事务是一个整体,不可再分,事务操作要么都成功,要么都失败
2.2 一致性(Consistency):
2.3 隔离性(Isolation),多个事务之间互不干扰
2.4 持久性(Durability),事务内的所有数据操作将保存到数据库当中
3、事务隔离性问题
如果说当高并发情况下,可能会产生事务隔离性的问题,可能多个事务之间相互干扰了,那么就会发生以下的情况:
1.脏读:一个事务读取了另外一个事务没有提交的数据
2.不可重复读:事务A在频繁读取一个数据,读取数据的过程当中,该数据被另外一个事务B更改提交了,那么事务A所获取到的结果发生了不一致情况
3.虚读/幻读:事务A在修改表的所有数据,假如将sex都改为1,那么在修改过程当中事务B添加了一条数据,sex为2,那么当事务A修改完毕后再次查看时。发现有一条没有修改
4、事务的隔离级别
1.读未提交TransactionDefinition.read_uncommited
2.读已提交TransactionDefinition.read_commited
3.可重复读TransactionDefinition.repeatable_read
4.串行化TransactionDefinition.serializable
spring提供第五种:TransactionDefinition.Isolation_default 根据所选型的数据库获取 mysql可重复读 oracle或者sql server是读已提交
5、事务的7种传播行为
1、PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
2、PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘
3、PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
4、PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
5、PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6、PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
7、PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
6、事务配置方式(事务案例)
模拟银行转账
1、数据库mybank
2:、实体层entity:Bank
3、 mapper层:
//原账户减钱
public int reduceMoney(Bank bank, double money);
//目标账户加钱
public int inToMoney(Bank bank, double money);
Mapper层实现类:
@Repository
public class IBankMapperImpl implements IBankMapper {
@Resource
private JdbcTemplate jdbcTemplate;
@Override
public int reduceMoney(Bank bank,double money) {
return jdbcTemplate.update("update bank set card_balance=card_balance-? where card_code=?",money,bank.getCard_code());
}
@Override
public int inToMoney(Bank bank,double money) {
return jdbcTemplate.update("update bank set card_balance=card_balance+? where card_code=?",money,bank.getCard_code());
}
4、service层
/**
* 转账方法
* @param reduceBank 原账户
* @param inToBank 目标账户
* @param money 转账金额
*/
public void transfer(Bank reduceBank, Bank inToBank, double money);
Service层实现类:
@Service("iBankService")
public class IBankServiceImpl implements IBankService {
@Resource
private IBankMapper iBankMapper;
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED)
@Override
public void transfer(Bank reduceBank, Bank inToBank, double money) {
//转账 减钱
iBankMapper.reduceMoney(reduceBank,money);
//模拟异常情况下
int result=5/0;
//加钱
iBankMapper.inToMoney(inToBank,money);
}
6.1 事务代理工厂:利用代理工厂生成代理对象,在目标对象的基础之上加入了事务管理,如果执行需要用到事务时,程序报错,那么事务会自动回滚
<!--事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--事务代理工厂:加工生成对象-->
<bean id="transactionProxyFactoryBean" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!--引用事务管理-->
<property name="transactionManager" ref="transactionManager"/>
<!--目标对象-->
<property name="target" ref="iBankService"/>
<!--配置传播行为和隔离级别-->
<property name="transactionAttributes">
<props>
<!--哪一个方法要被事务管理 指定该方法事务的隔离级别和传播行为-->
<prop key="transfer">ISOLATION_DEFAULT,PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
6.2 基于AOP的事务
<!--事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--aop事务-->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<!--配置隔离级别和传播行为-->
<tx:attributes>
<tx:method name="trans*" propagation="REQUIRED" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
<!--将目标对象和事务绑定到一起-->
<aop:config>
<!--切点表达式-->
<aop:pointcut id="pointcut" expression="execution(* *..service.impl.*.*(..))"/>
<!--织入-->
<aop:advisor advice-ref="transactionAdvice" pointcut-ref="pointcut"/>
</aop:config>
6.3 注解事务
6.4 开启注解事务支持
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启事务注解支持-->
<tx:annotation-driven/>
6.5 在目标方法上加入Transation注解即可
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED)
@Override
public void transfer(Bank reduceBank, Bank inToBank, double money) {
//转账
iBankMapper.reduceMoney(reduceBank,money);
iBankMapper.inToMoney(inToBank,money);
}
十、spring整合mybatis
1、Spring整合Mybatis,基于XML配置
1.1 引入依赖:
除Spring依赖和Mybatis依赖以外,新增:commons-logging,slf4j,mybaits-spring,druid
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<!--引入需要的ehcache插件-->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>1.2.3</version>
</dependency>
<!--mybatis整合ehcache的jar-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
1.2 创建配置文件
log4j.properties
datasource.properties
mybatis-config.xml
applicationContext.xml
ehcache.xml(如果不适用第三方缓存则不用引入)
1.3 创建Entity实体
1.4 创建Mapper层接口
public interface IBankMapper {
//查询所有银行账户
public List<Bank> getAllBank();
}
1.5 Mapper小配置文件
<!--namespace需要指向接口全路径-->
<mapper namespace="com.wdksoft.mapper.IBankMapper">
<select id="getAllBank" resultType="Bank">
select* from bank
</select>
</mapper>
注意pom.xml开启扫描,否则不会加载小配置文件
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
1.6 mybaits-config大配置文件内容:
<configuration>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<!--别名配置-->
<typeAliases>
<package name="com.wdksoft.entity"/>
</typeAliases>
<!--加载小配置文件-->
<mappers>
<package name="com.wdksoft.mapper"/>
</mappers>
</configuration>
1.7 配置Service层
public interface IBankService {
//查询所有银行账户
public List<Bank> getAllBank();
}
1.8 配置ServiceImpl层
public class IBankServiceImpl implements IBankService {
//植入Mapper层对象
private IBankMapper iBankMapper;
@Override
public List<Bank> getAllBank() {
return iBankMapper.getAllBank();
}
public IBankMapper getiBankMapper() {
return iBankMapper;
}
public void setiBankMapper(IBankMapper iBankMapper) {
this.iBankMapper = iBankMapper;
}
}
1.9 配置applicationContext.xml文件
1.9.1 配置数据源
1.9.2 配置SqlSessionFactory,加载数据源,加载mybatis大配置文件
1.9.3 关联Mapper映射,扫描Mapper包,将Mapper的所有接口注入到容器
1.9.4 将Mapper和SqlSessionFactory关联到一起
1.9.5 将Service和Mapper关联到一起即可
1.9.6 补充:如果用到增强和事务,你就配置,如果不用就不用配置
<!--加载jdbc.properties配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置DataSource 阿里: druid c3p0 dbcp-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置SqlSessionfactory-->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--加载数据源-->
<property name="dataSource" ref="dataSource"/>
<!--加载mybatis大配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!--关联Mapper映射-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.wdksoft.mapper"/>
</bean>
<!--Mapper注入,利用代理工厂生成对象-->
<bean id="iBankMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!--代理的Mapper-->
<property name="mapperInterface" value="com.wdksoft.mapper.IBankMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactoryBean"/>
</bean>
<!--Service层注入-->
<bean id="iBankService" class="com.wdksoft.service.impl.IBankServiceImpl">
<property name="iBankMapper" ref="iBankMapper"/>
</bean>
1.10 测试
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
IBankService iBankService =(IBankService) applicationContext.getBean("iBankService");
List<Bank> allBank = iBankService.getAllBank();
for (Bank bank:allBank){
System.out.println(bank.toString());
}
}
2、Spring整合Mybatis,基于注解配置
1.1 引入依赖:
除Spring依赖和Mybatis依赖以外,新增:commons-logging,slf4j,mybaits-spring,druid
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<!--引入需要的ehcache插件-->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>1.2.3</version>
</dependency>
<!--mybatis整合ehcache的jar-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
1.2 创建配置文件
log4j.properties
datasource.properties
mybatis-config.xml
applicationContext.xml
ehcache.xml(如果不适用第三方缓存则不用引入)
1.3 创建Entity实体
1.4 创建Mapper层接口
@Repository
public interface IBankMapper {
//查询所有银行账户
public List<Bank> getAllBank();
}
1.5 Mapper小配置文件
<!--namespace需要指向接口全路径-->
<mapper namespace="com.wdksoft.mapper.IBankMapper">
<select id="getAllBank" resultType="Bank">
select* from bank
</select>
</mapper>
注意pom.xml开启扫描,否则不会加载小配置文件
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
1.6 mybaits-config大配置文件内容:
<configuration>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<!--别名配置-->
<typeAliases>
<package name="com.wdksoft.entity"/>
</typeAliases>
<!--加载小配置文件-->
<mappers>
<package name="com.wdksoft.mapper"/>
</mappers>
</configuration>
1.7 配置Service层
public interface IBankService {
//查询所有银行账户
public List<Bank> getAllBank();
}
1.8 配置ServiceImpl层
@Service("iBankService")
public class IBankServiceImpl implements IBankService {
//植入Mapper层对象
@Resource
private IBankMapper iBankMapper;
@Override
public List<Bank> getAllBank() {
return iBankMapper.getAllBank();
}
}
1.9 配置applicationContext.xml文件
1.9.1 配置数据源
1.9.2 配置SqlSessionFactory,加载数据源,加载mybatis大配置文件
1.9.3 关联Mapper映射,扫描Mapper包,将Mapper的所有接口注入到容器
1.9.4 将Mapper和SqlSessionFactory关联到一起
1.9.5 将Service和Mapper关联到一起即可
1.9.6 补充:如果用到增强和事务,你就配置,如果不用就不用配置
<!--加载jdbc.properties配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置DataSource 阿里: druid c3p0 dbcp-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置SqlSessionfactory-->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--加载数据源-->
<property name="dataSource" ref="dataSource"/>
<!--加载mybatis大配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!--关联Mapper映射-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.wdksoft.mapper"/>
</bean>
<!--注解扫描-->
<context:component-scan base-package="com.wdksoft"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启事务-->
<tx:annotation-driven/>
1.10 测试
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
IBankService iBankService =(IBankService) applicationContext.getBean("iBankService");
List<Bank> allBank = iBankService.getAllBank();
for (Bank bank:allBank){
System.out.println(bank.toString());
}
}
3、使用pageHelper插件
3.1 基于Mybatis大配置文件
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper"></plugin>
</plugins>
3.2 基于Spring大配置文件
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--加载数据源-->
<property name="dataSource" ref="dataSource"/>
<!--加载mybatis大配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageHelper">
</bean>
</array>
</property>
</bean>
4、mybatis-generator使用
反向生成插件,能够根据数据库反向生成实体和Mapper接口
4.1 导入依赖
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
4.2 开启mybatis-generator插件
<plugin>
<!--Mybatis-generator插件,用于自动生成Mapper和POJO-->
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<!--配置文件的位置 一定要改成配置文件的位置-->
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
<executions>
<execution>
<id>Generate MyBatis Artifacts</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
</plugin>
4.3 配置generatorConfig.xml生成规则
1.数据库驱动jar包位置
<classPathEntry location="F:\maven\mvnRepo\mysql\mysql-connector-java\5.1.38\mysql-connector-java-5.1.38.jar"/>
2.数据库链接URL,用户名、密码
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/smbms" userId="root" password="root">
3.<!-- 实体类生成的位置 -->
<javaModelGenerator targetPackage="com.smbms.test.entity" targetProject=".\src\main\java">
<property name="enableSubPackages" value="false"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
4.<!-- *Mapper.xml 文件的位置 -->
<sqlMapGenerator targetPackage="com.smbms.test.mapper" targetProject=".\src\main\java">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
5.<!-- Mapper 接口文件的位置 -->
<javaClientGenerator targetPackage="com.smbms.test.mapper" targetProject=".\src\main\java" type="XMLMAPPER">
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
6.<!-- 相关表的配置 -->
<table tableName="smbms_address" domainObjectName="Smbms_Address"
enableCountByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
enableUpdateByExample="false"/>
4.4 启动插件,进行生成

浙公网安备 33010602011771号