Spring的介绍
Spring是一个企业级的Java应用开发的框架
Spring是一个开源框架,轻量级,基础版本只有2M大小
Spring主要使用开发Java应用程序,该框架的目标是使开发的应用更加容易使用
Spring的优势:
简化Java的开发
基于轻量级和最小侵入式开发
通过依赖注入和面向接口实现松耦合
基于切面进行声明式开发
通过切面和模板减少样式代码
学习要点:
Spring的介绍
Spring的IOC介绍(控制反转)
Spring的DI介绍(依赖注入)
Spring的AOP介绍(横向切面技术)(->动态代码)
低侵入式的扩展新的功能
Spring和Mybatis的整合介绍 (SSM)
Spring中的JDBCTenplate
Spring中的事务配置
Spring中的设计模式
Spring的体系结构:
从图中可以看出Spring框架基本上是一些模块性的东西,我们需要用哪些就去添加其依赖就好,图中其大致可以分为Core Container核心容器,Data Access数据访问,Web页面部分,Test测试模块,以及中间的AOP,Aspects,Instrumentation等技术
核心容器
Spring的核心容器是有Spring-core、Spring-Beans\Spring-context\Spring-expression等模块组成
Spring-core:是Spring的基础组成部分,包括IOC和DI(依赖注入)等功能
Spring-beans:提供Beanfactory,容器工厂,管理和创建对象
Spring-context:是在core和beans的基础上建立,类似于JDNI的的方式来访问对象
Spring-expression:是Spring的表达式语言
数据访问和集成
数据访问集成层包括JDBC、ORM(对象关系模型框架)、OXM(解析XML或者流文件的框架)、JMS(消息模块框架类似于生产者消费者模型)和事务处理模块
WEB页面
WEB主要提供和页面相关的的模块组成
Spring的IOC
Spring的IOC的思想
Spring的核心思想之一:IOC(Inversion Of Control)控制反转
即把对象的创建交给外部的容器完成,这个就是控制反转
Spring使用控制反转来实现对象的使用不用在程序中写死
再通过依赖注入(Dependency injection)解决对象与对象之间的属性关系或者说依赖关系,在创建对象之后,对象的关系处理(比如赋值)就是依赖注入
控制反转是通过外部容器完成的,而Spring中提供了一个容器,称该容器为:IOC容器
无论对象的创建,处理对象之间的依赖关系,对象创建的时间,对象创建的数量,单例还是多例创建,都是在SPring索提供的IOC的容器上来配置对象的信息
IOC的思想的核心在于:资源不在是使用资源方来管理,而是将资源交给第三方管理(IOC容器),这样来处理带来很多好处:
• 资源的集中管理,实现资源的可配置和易管理
• 降低了使用资源双方的依赖程度,也就是耦合度问题
Spring 容器管理对象步骤
一.导入Spring的依赖(在pom.xml中)
<!--Spring核心依赖jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<!--log4j日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--注解相关jar包-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
这是其中四最基础也是最核心的依赖,其版本要统一
二.Spring的配置文件(applicationContect.xml)同样是在resources目录下(设置Resources Root的目录)
<?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-3.0.xsd">
</beans>
在官网上可以找到最外层的约束条件
三.创建资源(User.java)最好创建在bean目录下
public class User {
private String id;
private String name;
//getter和setter方法省略
}
四.使用IOC容器管理对象
以前是通过new User的方法创建对象User user = new User();
现在可以让IOC容器帮创建对象,在applicationContext.xml文件中添加User的对应信息
<!--使用bean节点来创建对象 id属性表示对象 class属性表示要交给容器管理的对象的全路径-->
<bean id="user" class="com.tulun.bean.User"/>
id可以随便起相当于起别名,但最好跟你要管理的对象名一样,class写其路径
//其实到这里对象就已经创建好了,后面的步骤是验证使用
五.通过容器来获取对象去使用
//获取IOC的容器
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过容器来获取当前的对象
User user = (User) applicationContext.getBean("user");
System.out.println(user);
通过日志可知,对象已经被创建出来了,并且可以打印出对象的地址
//先对IOC容器进行一个整体的了解,才能了解上述过程底层是如何实现的
Spring的IOC容器介绍
Spring中的core模块:IOC容器,解决对象的创建和对象之间的依赖关系
如何得到IOC容器?
这是Spring IOC容器中接口的继承关系,其中ApplicationContext是BeanFactory的子接口之一,换句话说,
Beanfactory是IOC容器中最底层的接口,而ApplicationContext四其高级接口之一,在于对BeanFactory做了许多的功能上的扩展。在大部分的应用场景下,都是使用ApplicationConext作为Spring IOC的容器
ApplicationContext的常见的实现类
1. ClassPathXmlApplicationContext
读取当前项目内的资源文件
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
2.FileSystemXmlApplicationContext
读指定路径资源即在我本地电脑的其他路径
FileSystemXmlApplicationContext xmlApplicationContext = new FileSystemXmlApplicationContext("c:/java/applicationContext.xml");
3.XmlWebApplicationContext
通过Web读取外部资源,使用时得添加其特定的依赖
XmlWebApplicationContext wa = new XmlWebApplicationContext()//并没有初始化容器
wa.setServletContext(sevletcontext);//需要指定servletContext对象
wa.setConfigLocation("/applicationContext.xml");//指定配置文件的路径,开头是以web为根目录的路径
wa.refresh();//初始化容器
Spring IOC框架工作模型:
Bean的实例化方式
Bean即对象,下文中亦是
Spring容器中配置Bean的方式主要有两种
基于配置形式
基于注解性
一.基于XML配置方式装配Bean
bean基于配置方式实例化有三种形式
1.通过无参构造实例化
上面的demo就是基于无参构造来实例化的对象
<!--使用bean节点来创建对象 id属性表示对象 class属性表示要交给容器管理的对象的全路径-->
<bean id="user" class="com.tulun.bean.User"/>
注意:如果不指定构造函数,系统JVM会生成默认的无参构造函数
如果指定有有参构造函数,必须显性的指定一个无参构造函数,否则实例化对象会抛出异常,即有参会覆盖默认的无参,我得自己在类里面写一个无参构造函数
2.基于静态工厂方法实例化
首先使用一个工厂的静态方法返回一个对象
public class Factory {
//创建User对象的静态方法
public static User getUserBean() {
return new User();
}
}
在配置文件中使用静态方法返回对象
<!--通过静态工厂方法创建对象,直接使用class来执行静态类,Factory-method指定方法就行-->
<bean id="user1" class="com.tulun.Factory" factory-method="getUserBean"/>
3.基于普通工厂的方式实例化
通过工厂的非静态方法得到当前的一个对象
public class Factory {
//创建User对象的普工方法
public User getUserBean1() {
return new User();
}
}
配置文件中使用工厂的非静态方法返回对象
<!--通过非静态工厂访问对象-->
<!--首先创建工厂对象-->
<bean id="factory" class="com.tulun.Factory"/>
<!--指定工厂对象和工厂方法-->
<bean id="user2" class="com.tulun.bean.User" factory-bean="factory" factory-method="getUserBean1"/>
涉及代码:
二.基于注解方式装配Bean
基于注解的形式要比xml配置文件的方式更加简洁
1.Spring配置文件引入context约束
单独创建一个ApplicationContext.xml的文件去引入
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
2.Spring 的配置文件中开启注解的扫描
<!--开启注解扫描: base-package(必填)指令包路径: 会扫描类方法、属性上是否有注解-->
<context:component-scan base-package="com.tulun.bean"></context:component-scan>
<!--扫描属性上面的注解(不建议使用)-->
<context:annotation-config></context:annotation-config>
路径写到包即可,会自动扫描包下的所有文件
注:必须要引入context约束,否则无法出现context标签
3.在类上添加@Component注解
@Component(value = "user")
public class User {
private String id;
private String name;
}
使用注解形式来获取对象:
Spring中主要提供了4个注解来标注Bean
@Component 通用的标注形式
@Repository 对Dao(跟数据库相关)实现类进行标注
@Service 对Service(业务逻辑相关)实现类进行标注
@Controller 对Controller(Web页面相关)实现类进行标注
后端的业务分层一般业务请求顺序:Controller(进行URL结束和返回)-》Service(业务逻辑)-》Dao(访问数据层)
@Component是Spring 提供的通用的组件注解
@Controller、@Service 、@Repository是@Component的衍生,功能一样,是可以互换的
使用不同的注解主要是为了区分被注解的类处于不同的业务层,使逻辑更加清晰
这四个注解主要定义bean,创建bean,使用上是要标注在类上,@Component(value=“user”)或者@Component(“user”)
Spring配置中bean标签属性介绍
id属性:给当前的对象取名字,可以使用特殊字符(例如*/之类的)
name属性:给当前对象取名字,不可以使用特殊字符
calss属性:表示要交给容器管理的对象的全路径
scope属性:表示当前的对象是单例还是多例 singleton:单例 prototype:多例 注解形式:@Scope("")
(单例即先后两次拿到的对象是一样的,不一样就为多例),默认是单例
Spring 中DI介绍
DI-Dependency Injection,即“依赖注入”,组件之间依赖关系由容器在运行期决定,即容器动态的将某个依赖关系注入到组件当中
谁依赖谁:应用程序依赖IOC容器
为什么需要以依赖:应用程序需要IOC容器来提供对象需要的外部资源
注入什么:注入某个对象所依赖的外部资源
说白了就是在一个对象中注入另一个对象,相当于一个类中需要调用另一个类的方法,你首先得得到这个类的对象
一.基于配置的形式注入依赖
1.有参构造函数注入依赖
<!--依赖注入方式1:有参构造-->
<bean id="user3" class="com.tulun.bean.User">
<!--id属性的注入-->
<constructor-arg name="id" value="22"></constructor-arg>
<!--name属性的注入-->
<constructor-arg name="name" value="zhangsan"></constructor-arg>
</bean>
有参构造函数的依赖注入主要使用标签 name属性:表示类中的属性名 value属性:当前属性名赋值
在类中必须包含有参构造函数:且和构造函数保持参数一致
2.set方法注入依赖
<!--依赖注入方式2:set方法-->
<bean id="user4" class="com.tulun.bean.User" >
<!--id属性注入-->
<property name="id" value="12"/>
<!--name属性赋值-->
<property name="name" value="李四"/>
</bean>
set方法注入依赖时,使用property标签 name属性表示类中的属性名 value属性表示当前属性的赋值
注入的属性可以是基本的类型,也可以是集合类型,也可以是自定义类型
<!--对象的注入-->
<!--在Person类中注入自定义的User-->
<bean id="user5" class="com.tulun.bean.User"/>
<bean id="person" class="com.tulun.bean.Person" >
<!--user属性通过set方式注入-->
<!--value:会按照String类型的字符串做解析 ref:Spring中管理对象的ID名-->
<property name="user" ref="user5"/>
</bean>
集合类型
注入List类型的依赖
<!--List的注入-->
<bean id="person1" class="com.tulun.bean.Person">
<property name="list" >
<list>
<value>hello</value>
<value>你好</value>
<value>1234</value>
</list>
</property>
</bean>
其他形式的集合配置
<!--数组的注入-->
<bean id="person2" class="com.tulun.bean.Person">
<property name="list" >
<!--array标签:注入数组-->
<array>
<!--value是直接给定值-->
<value></value>
</array>
</property>
</bean>
<!--set的注入-->
<bean id="person3" class="com.tulun.bean.Person">
<property name="list" >
<!--set标签:注入set类型的集合-->
<set>
</set>
</property>
</bean>
<!--map的注入-->
<bean id="person4" class="com.tulun.bean.Person">
<property name="map" >
<!--map标签:注入Map类型的集合-->
<map>
<entry key="1" value="zhangsan"/>
</map>
</property>
</bean>
二.基于注解的形式注入依赖
1. @Value 注入普通形式的依赖
2.@Resource:注入对象类型
3.@Autowired 注入对象类型
@Value注解
@Component(value = "user")
public class User {
@Value("1")
private String id;
@Value("张三")
private String name;
}
注:使用Value注解注入依赖前提是Bean的装配支持注解扫描
@Resource注解
@Autowired
@Component(value = "person")
public class Person {
//自定义类型属性
//和@Resource功能一样
@Autowired
private User user;
}
@Resource 和 @Aoutowire的异同点
在Spring中,@Resource 和 @Aoutowire都是做Bean的注入时使用,@Resource 和 @Aoutowire是可以替换使用的
共同点:
@Resource 和 @Aoutowire是可以作为注入属性的修饰,在为接口仅有单一实现类时,两个注解效果一样,可互相替换,不影响使用
不同点:
@Resource 是Java中提供的注解,@Resource存在两个属性,分别为name和type,
在Spring中是通过name来解释bean的名字,而type属性则解析为bean的类型,所以如果使用name属性时,使用byName自动注入策略,而使用type属性是则使用byType自动注入策略,如果不指定name或者type属性时,这是将通过反射机制使用byName 自动注入策略
@Autowired是Spring 提供的注解,在Spring的2.5版本引入,@Autowired只根据type进行注入,不会去匹配name,如果type无法识别中注入对象是,需要依赖@Qualifier或者是Primary注解一起修饰
依赖的解析过程
容器解析Bean的依赖过程:
• ApplicationContext是通过配置元数据来创建个初始化的,这些元数据描述了所有的bean,描述元数据可以通过XML,注解或者Java代码来指定
• 对于每一个bean,他的依赖注解,构造方法参数后者静态工厂方法参数的形式来表达。bean被创建后之后这些依赖会被提供给他
• 每一个属性或者构造方法的参数都要设定的值的实际定义,或者对容器内另一个bean的引用
容器在创建的时候,Spring容器会验证每一个bean的配置,在实际创建bean之前,bean的属性是不会被设置的。bean只会在需要他的时候被创建,创建bean的过程找那个可能会引起一些列的bean被创建,列如bean的依赖,其依赖的依赖等等会被一起创建和分配。注意:依赖之间解析不匹配可能会出现,即首循环创建有影响的bean。
循环依赖的问题
class User{
private Person person;
}
class Person{
private User user;
}
如果是通过构造方法的方式注入,就有可能造成无法解决的循环依赖,类似于死锁
例如:ClassA需要通过构造方法注入一个ClassB的实例,classB同样需要通过构造方法注入ClassA的实例,
如果为ClassA和ClassB配置bean并且相互注入,IOC容器在运行时会发现这个循环引用,抛出异常:BeanCurrentlyInCreationException
解决循环依赖的途径需要去编辑代码,让这些类通过setter方法注入,避免使用构造方法注入
Spring AOP
AOP(Aspect Oritented Programing)面向切面编程,扩展功能不需要修改源代码
面向切面主要应用在性能监控,事务管理,安全检查,缓存等等
AOP的设计原理和思想
AOP 横向抽象技术的介绍
public class User{
//添加用户方法
public void add(){
//业务逻辑
}
}
//扩展功能
添加日志功能,记录在什么时候添加了那个用户
如果同传统的纵向抽取机制解决,在示例中只有一个添加用户的方法,而实际的业务中可能有很多增删改查的方法都涉及要添加日志的功能,我总不能直接在所有的涉及方法里面直接去添加,工作量很多而且都是重复的代码,我把添加日志的功能单独抽象出来作为一个类,里面实现好这个业务方法
public class BaseUser{
//创建打印日志功能
public void writeLog{
//添加日志的逻辑
}
}
我直接用需要添加日志功能的类继承我刚才的业务类,直接用super调用就好,并且我就算日后要再次修改更新日志功能也只需要修改我的添加日志的业务类就好,其他地方都不用动
public class User extends BaseUser{
public void add() {
//用户添加逻辑
//扩展功能,添加日志操作
// 调用已存在的日志打印的功能
super.writeLog();
}
}
问题:父类的中方法名发生改变,在子类中的方法名也需要改变,可能方法名不太合适,那底下所有的功能类也要牵扯修改,可能你觉得不是问题,但是还是一种耦合性不太好的机制
AOP横向抽象机制
底层使用:使用的动态代理的方式实现
第一种方式:
public interface UserDao{
public void add();
}
该接口的真正实现类
public class UserIml implements UserDao() {
public void add() {
//业务方法
}
}
实现一个代理辅助类,实现InvocationHandler接口
public class UserProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//日志功能添
method.invoke(object,args);
return null;
}
}
这样的话看似复杂但是确实解决了连方法名都不用考虑的问题
使用动态代理的范式来实现日志添加功能,代理类和实现类是平级关系。在有接口情况下,使用的是JDK的动态代理,在没有接口情况下,使用CGLib的形式进行功能扩展。
AOP的实现核心思想:动态代理
Java程序的执行流
程序运行过程就是方法的调用的过程
基于时间序列,将方法的调用排成一条线,每个方法的调用则可以看成是Java执行流找那个的一个节点,在AOP的术语中,节点称之为
JoinPoint(连接点)
一个Java的程序运行的过程。就是若干个连接点连接起来依次执行的过程。
AOP中将每一个方法的调用,即连接点作为编程的入口,针对方法调用进行编程,相当于程序横向切割成若干个面,每个面被称之为横向切面。
AOP是针对方法调用的编程思路
AOP的针对切面进行编程的,需要选择那些切面(连接点)作为编程的对象呢
切面的本质是每一个方法的调用,选择切面实际是选择方法的过程,被选择的切面在AOP术语中被称之为切入点(Point Cut),切入点实际上是从所有的连接点(Join Point)挑选自己需要的连接点的过程
AOP是针对的是方法的调用(连接点)的编程,如何选择自己需要的连接点–切入点?
在Spring中,AOP如何来捕获方法的调用,使用了代理模式的Java程序执行流
使用代理模式的Java的程序执行流
假设在Java代码中,实例对象是通过代理模式创建的代理对象,访问实例对象必须通过代理。
代码模式属于Java中经常用到的,代理对象可以为某些对象提供除了本身功能外的其他的一些额外的功能
Spring的代理层可以知道所做的业务的每一次的实例对象的方法调用,Spring就可以在代理的过程中插入Spring的自己的业务代码
Spring 中AOP的工作原理
AOP的编程首先选择自己需要的连接点-即切入点,AOP对切入如何做编程呢?在代理即使下的某个连接点的细化
AOP是根据Proxy提供的类型名和方法签名,确定感兴趣的切入点,则返回advice,Proxy得到这写通知,然后执行通知
AOP相关术语
• Join point(连接点):所谓连接点是指那些被拦截的点,在SPring中,这些点值得是方法,Spring中只支持方法类型的连接点类的方法被增强,这些方法称之为连接点
• Pointcut(切入点):切入点值得是我们需要对那些方法进行拦截的定义,在类中有很多的方法可以被增强。例:在实际操作过程中,知识增强类的add方法,实际增强的方法称之为切入点
• advice(通知/增强):通知指拦截到joinpoint之后需要做的事情就是通知。通知分为前置通知,后置通知,异常通知,最终通知,环绕通知
前置通知:在方法之前执行
后置通知:在方法之后执行
异常通知:在方法出现异常时通知
最终通知:在后置之后执行
环绕通知:在方法之前和之后都通知
• Aspect(切面):是切入点和通知的结合,被增强应用到切入点的过程
• Introduction(引介):是一种特殊的通知在不修改代码的前提下,引介可以在运行期为类动态的添加方法和属性
• Target(目标对象):代理的目标对象(要增强的类)
• Weaving(织入):是把增强应用到目标的过程,把advice应用到target的过程
• Proxy(代理):一个类被AOP织入增强后,产生的一个结果代理类
AOP结合Aspectj的使用
在Spring实现AOP功能通过Aspect就实现
aspectj是一个基于Java的AOP框架
aspectj不是Spring的一部分,只是和Spring结合在一起完成AOP的操作
1.基于XML配置的方式实现
2.基于注解的形式实现
AOP结合Aspectj基于XML的实现方式
一.引入AOP需要的相关jar包
在Spring的基本jar包基础上,需要AOP相关的jar
<!--AOp相关jar-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
二.相关配置,导入AOP的相关约束条件
在resources包下的ApplicationContext.xml文件中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
三.原本的实现类
//基础类
public class Book {
//方法1:写方法
public void writeBook() {
//业务逻辑
System.out.println("writeBook");
}
//读方法
public void readBook() {
//业务逻辑
System.out.println("readBook");
}
}
四.增强类
需要增加的功能
/**
* 增强类
* 完成添加日志
*/
public class DiyLog {
public void log() {
//业务逻辑
System.out.println("打印日志");
}
}
五.使用表达式来配置切入点
在resources包下的ApplicationContext.xml文件中
execution函数介绍
在通知中定义切点,通过execution函数,可以定义切点的方法切入
切入点:实际增强的方法
常用的表达式
execution(<访问限定符>?<返回类型><方法名>(<参数>)<异常>)
execution(* com.tulun.bean.Book.writeBook(…)) 表示类Book里面的writeBook的方法
execution(* com.tulun.bean.Book.(…)) 表示类Book下的所有的方法
execution( .(…)) 表示所有的
例:
匹配所有的public方法 execution(public .(…))
匹配指定包路径下所有类的方法 execution(* com.tulun.bean.(…)) (不包含子包)
匹配指定包路径下所有类的方法 execution( com.tulun.bean…(…))(包含包,子包的所有类)
匹配指定类的所有方法 execution( com.tulun.bean.Book.(…))
匹配特定开头的方法 execution( com*(…))
<!--将基本对象交给spring管理-->
<bean id="book" class="com.tulun.bean.Book7"/>
<bean id="diyLog" class="com.tulun.bean.DiyLog"/>
<!--配置AOP操作-->
<aop:config>
<!--配置切入点:使用表达式,在实际的方法上添加通知的方法称之为切入点-->
<aop:pointcut id="pointcut1" expression="execution(* com.tulun.bean.Book7.writeBook(..))"/>
<!--配置切面:把增强用到方法-->
<aop:aspect ref="diyLog">
<!--配置增强类型 method:增强类中的那个方法作为前置增强-->
<aop:before method="log" pointcut-ref="pointcut1"/>
<!--
aop:before:前置通知
aop:after 后置通知
aop:after-returning:最终通知
aop:after-throwing:异常通知
aop:around:环绕通知
-->
</aop:aspect>
</aop:config>
六.使用
public static void main(String[] args) {
//获取IOC的容器
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext2.xml");
//通过容器来获取当前的对象(通过无参构造来实例对象方法)
//获取book对象
//验证前置通知
Book7 book = (Book7) applicationContext.getBean("book");
book.writeBook();
}
注意:环绕通知
//环绕通知 需要通过ProceedingJoinPoint类型的参数指定增强方法执行的时机
public void round(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("方法执行前");
//执行增强的方法
joinPoint.proceed();
System.out.println("方法执行之后");
}
AOP结合Aspect基于注解的方式实现
一.Bean对象装配
将接触类和增强类交给IOC容器管理(在resources包下的ApplicationContext.xml文件中
)
<bean id="book" class="com.tulun.bean.Book7"/>
<bean id="diyLog" class="com.tulun.bean.DiyLog"/>
二.在Spring的配置文件中,开启AOP操作
(在resources包下的ApplicationContext.xml文件中
)
<!--开启AOP的操作-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
三.在增强类上添加注解
直接在diyLog类的方法上
@Aspect
public class DiyLog {
//前置增强
@Before(value = “execution(* com.tulun.bean.Book7.readBook(…))”)
//等同于配置里面的<aop:before method=“round” pointcut-ref=“pointcut1”/>
public void log() {
//业务逻辑
System.out.println(“打印日志”);
}
}
基于注解的AOP实现方式:在增强类上添加@Aspect 注解。在该类中哪一个方法来作为增强,就在方法上添加以下注解
@Before(value = “execution(* com.tulun.bean.Book7.readBook(…))”) //前置通知
@After(value = “”) //后置通知
@AfterThrowing //异常通知
@Around(value = “”)//环绕通知 ,需要在方法入参上添加ProceedingJoinPoint参数
@AfterReturning //最终通知
Spring中的数据层面的介绍,首先Spring中对JDBC做了封装为JdbcTemplate
Spring的JdbcTemplate操作
jdbcTemplate是Spring提供的操作数据库的操作,是基于JDBC实现的
一.引入JDBC相关的jar包
在Spring的全局配置文件里
<!--Spring的JDBC模板操作-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.0.6.RELEASE</version>
</dependency>
JDBCTemplate的使用
最原始的Java代码使用方式,暂时没有用Spring
/**
* JDBC模板使用的介绍
*/
public class JDBCTemplateTL {
public static void main(String[] args) {
//创建对象,设置数据源信息
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mybatis");
dataSource.setUser("root");
dataSource.setPassword("123456");
//创建jdbcTemplate对象,设置数据源
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//调用jdbcTemplateTemplate提供的方法
//更新操作
String updateSql ="update user set sex =? where id = ?";
// jdbcTemplate.update(updateSql,new Object[]{1,1});
//删除操作
String deleteSql="delete from user where id = ?";
// jdbcTemplate.update(deleteSql,new Object[]{35});
//jdbcTemplate 对数据的变更(update\insert \delete)都可以通过update方法进行处理
//查询单个对象 queryForObject
String selectSql1="select * from user where id=? ";
// <T> T queryForObject(String sql, Object[] value, RowMapper<T> var3) throws DataAccessException;
User7 user7 = jdbcTemplate.queryForObject(selectSql1, new Object[]{1}, new UserMapper());
// System.out.println(user7);
//查询多个对象 query
String selectSql2 = "select * from user where sex=?";
List <User7> list = jdbcTemplate.query(selectSql2, new Object[]{1}, new UserMapper());
System.out.println(list);
}
}
RowMapper接口:
单个结果直接用一个对象参数即可,多个对象才需要用到接口封装
/**
* JDBC完成查询的结果
* 需要自定义实现一个RowMapper的实现类
* 该类存在的目的就是完成数据库对象到Java对象的映射
*/
public class UserMapper implements RowMapper<User7>{
@Override
public User7 mapRow(ResultSet resultSet,int i) throws SQLException {
User7 user7 = new User7();
user7.setId(resultSet.getLong(columnLable:"id"));
user7.setUsername(resultSet.getString(columnLable:"username"));
user7.setSex(resultSet.getLong(columnLable:"sex"));
user7.setAddress(resultSet.getString(columnLable:"address"));
return user7;
}
}
Spring结合连接池(C3p0)和jdbcTemplate使用
场景:操作mybatis库中的user表,
通过ID查询用户信息
dao层接口
public class UserDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public User7 getUserById(Long id){
//查询SQL
String sql = "select * from user where id = ?";
User7 user = jdbcTemplate.queryForObject(sql, new Object[]{id}, new UserMapper());
//使用jdbctemplate模板来获取数据库数据
return user;
}
}
XML配置文件
resources包下的ApplicationContext.xml文件中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.DriverManagerDataSource">
<!--配置连接数据库的核心配置4个参数-->
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis"/>
</bean>
<!--配置jdbc模板-->
<bean id="jdbcTenplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--配置数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置UserDao-->
<bean id="userDao" class="com.tulun.dao.UserDao">
<!--注入JDBC模板-->
<property name="jdbcTemplate" ref="jdbcTenplate"/>
</bean>
</beans>
Spring的事务管理
Spring中事务相关的概念
什么是事务:
事务的特征:ACID -》原子性、一致性、隔离性、持久性
隔离不当引起的脏数据问题:脏读、不可重复读、幻读
隔离级别不同:
Spring中的事务管理
事务管理的API接口
PlatformTransactionManager 事务管理器
TransactionDefinition:事务定义信息(隔离,传播、超时、只读)
TransactionStatus:事务具体运行状态
参考资料:
https://baijiahao.baidu.com/s?id=1624322378090716314&wfr=spider&for=pc
Spring对事务的管理
两种方式:
• 编程式的事务管理(很少使用)
• 使用声明式的事务管理
-基于XML配置形式实现
-基于注解实现
基于xml形式的事务管理
配置文件的思想AOP的思想实现
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.DriverManagerDataSource">
<!--配置连接数据库的核心配置4个参数-->
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis"/>
</bean>
<!--第一步:配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源DataSource-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--第二步:配置事务增强-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--做事务处理-->
<tx:attributes>
<!--
设定进行事务操作方法的匹配规则
add*指定增强的方法名 表示add开头的都可以
propagation:事务传播行为
isolation:指定隔离级别。。。
-->
<tx:method name="add*" propagation="REQUIRED" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
<!--第三步:配置切面-->
<aop:config>
<!--切入点-->
<aop:pointcut id="pointcut1" expression="execution(* com.tulun.dao.UserDao.*(..))"/>
<!--切面-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>
</beans>
基于注解形式的事务管理器
配置信息
<!--第一步:配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源DataSource-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--第二步:配置事务注解:开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
注解:@Transactional
@Transactional
public class UserDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Transactional
public User7 getUserById(Long id){
//查询SQL
String sql = "select * from user where id = ?";
User7 user = jdbcTemplate.queryForObject(sql, new Object[]{id}, new UserMapper());
//使用jdbctemplate模板来获取数据库数据
return user;
}
}
@Transactional表示是事务,该注解可以添加在类上或者是方法上,添加在类上即该类的所有方法都使用事务,添加在方法上即当前的方法是支持事务的