Spring框架

Spring框架

一、Spring核心概念

1Spring框架优点

1.1 方便解耦,简化开发 IOC/DI

1.2 AOP编程支持

 

@Before

INewsMapper

@After

1.3 声明式事务支持

1.4 Spring支持Junit测试

1.5 降低JavaEE api使用难度

 

 

2Spring框架核心

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 根据beanid属性值调用

   /* 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代表引用,引用beanID-->

<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 根据beanid属性值调用

   /* 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 根据beanid属性值调用

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.3P命名空间注入,基于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>

 

 

2Spring自动依赖注入

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基于注解版本的IOCDI

3.1前提条件:大配置文件,加入扫描注解

 <!--扫描注解-->

<context:component-scan base-package="com.wdksoft"/>

 

 

3.2注解IOC是将对象注入到容器中的

@Component :将当前对象当做Bean注入到容器当中去  @Bean

@Repository : 专门注入Mapper层接口

@Service:专门注入Service层对象

@Controller:专门注入Controller

 

3.3DI注解调用

@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());

}

 

 

ServiceMapper注入和依赖:

Mapper层接口:

public interface INewsMapper {

public String sayHi();

}

 

Mapper层接口实现类:

@Repository

/**

 * <bean id="iNewsMapper" class="INewsMapperImpl"></bean>

 * 正常开发@Repository写在接口上,不用写Mapper实现类,Myabtis小配置文件就可以当做实现类,但是Spring容器中不允许注入接口,

 * SpringMyabtis整合时,可以通过特定类扫描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面向切面编程

1SpringAOP概念

专心做事,主要关注业务逻辑,其余的操作可以抽离成公共模块,进行增强处理

  AOP原理:在不改变原对象的基础之上,生成代理对象,在代理对象做增强处理

 

2AOP专业术语

 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("===mapperaddUser方法===");

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面向切面编程

1SpringAOP概念

专心做事,主要关注业务逻辑,其余的操作可以抽离成公共模块,进行增强处理

  AOP原理:在不改变原对象的基础之上,生成代理对象,在代理对象做增强处理

 

2AOP专业术语

 

 

3AOP第一个案例

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("===mapperaddUser方法===");

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();

 

}

 

}

 

3JDK动态代理案例

 

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();

 

}

 

4Cglib动态代理案例

 

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();

 

}

 

 

 

 

 

5SpringAOP代理模式面试要点

 

1.SpringAOP代理模式:

 

代理生成对象取决于目标对象,如果目标对象包含接口,则采用JDK动态代理,如果目标对象不包含接口,则采用CGLIB动态代理

 

对比CGLIBJDK动态代理:

 

1.JDK面向接口的,cglib是面向业务类的

 

2.JDK是在运行时期,CGLIB是在编译时期

 

3.JDK1.61.7版本当中JDKCGLIB慢,在JDK1.8版本JDKCGLIB

 

 

 

1.AOP概念,为什么使用AOP

 

2.AOP底层实现方式采用代理模式

 

分为JDKCJLIB,区别为......

 

 

 

 

 

 

 

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),但是这种切面功能过于简单,只能将切面织入到目标类的所有方法当中,无法完成将切面织入到目标方法当中

顾问AdvisorSpring提供的另外一种切面的方式,可以完成复杂功能,能选择性的植入目标方法当中

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

1Spring概述

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方法:用于调用存储过程以及函数

2JDBTemplate用法

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 ServiceIMPL实现类

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>

 

<!--MapperService注入到容器当中-->

<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 向容器当中注入dataSourceJDBCTemplate对象

<!--加载配置文件-->

<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;

5jdbcTemplate总结

1.查询数据时,如果查询返回多行数据可以采用queryqueryForObject(使用rowMapper映射)

2.查询数据返回单行单列值时,可以使用queryForObject(指定返回值类型)

6查询单列值

 //查询sid1的数据

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事务管理

1spring事务概述

 

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添加了一条数据,sex2,那么当事务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种传播行为

1PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。

2PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。

3PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。

4PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。

5PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

6PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

7PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

 

 

6、事务配置方式(事务案例)

模拟银行转账

1、数据库mybank

2:、实体层entityBank

3mapper:

//原账户减钱
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

 

1Spring整合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整合ehcachejar-->

<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 MapperSqlSessionFactory关联到一起

1.9.5 ServiceMapper关联到一起即可

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());

}

}

 

 

 

2Spring整合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整合ehcachejar-->

<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 MapperSqlSessionFactory关联到一起

1.9.5 ServiceMapper关联到一起即可

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>

 

4mybatis-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插件,用于自动生成MapperPOJO-->

                    <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 启动插件,进行生成

 

 

 

 

 

 

 

 

posted @ 2020-02-13 21:02  F阿东  阅读(181)  评论(0)    收藏  举报