本文适合已学人士,仅供复习参考。全程手打,纯TXT,无代码参考,特告知
笔记网盘链接,新页面导航栏有地址和提取码
一、 Ioc:控制反转
1、IOc是一个概念,一个思想。用来指导我们如何创建、管理、使用对象。
控制:控制对象的创建,属性的赋值,依赖关系的管理,以及控制对象从创建到销毁的整个生命周期。
反转:把开发人员在代码中创建的对象的权限转移给代码之外的容器(spring)实现,由容器实现对对象的创建和管理。
正转:在源代码中,有开发人员,new出构造方法创建对象
Ioc:简单来说是由容器(spring)来创建对象,而我们来使用创建好的对象。spring可以创建和管理对象,管理依赖关系。
spring可以看作是一个工厂,负责生产java对象。
2、使用Ioc思想的技术:servlet、fileter、listener
3、Ioc技术的实现
1)、DL依赖查找
2)、DI依赖注入
只需在代码中提供要使用的对象名称,对象如何创建、赋值则不需要考虑,由spring容器来完成
spring使用的DI技术实质上是使用反射机制来完成的。spring这个容器中,替你管理着一系列的类,前提是你需要将这些类交给spring容器进行管理,
然后在你需要的时候,不是自己去定义,而是直接向spring容器索取,当spring容器知道你的需求之后,就会去它所管理的组件中进行查找,然后直接给你所需要的组件.
注入方式: 1.set方式注入 2.构造方法注入 3.字段注入
注入类型: 1.值类型注入 2.引用类型注入
好处:
1.降低组件之间的耦合度,实现软件各层之间的解耦.
2.可以使容器提供众多服务如事务管理消息服务处理等等。当我们使用容器管理事务时,开发人员就不需要手工 控制事务,也不需要处理复杂的事务传播
3.容器提供单例模式支持,开发人员不需要自己编写实现代码.
4.容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能
5.容器提供众多的辅佐类,使这些类可以加快应用的开发.如jdbcTemplate HibernateTemplate
4、ApplicationContext & BeanFactory区别
BeanFactory接口
(1) spring的原始接口,针对原始接口的实现类功能较为单一
(2)BeanFactory接口实现类的容器,特点是每次在获得对象时才会创建对象
ApplicationContext接口
(1)每次容器启动时就会创建容器中配置的所有对象
(2)提供了更多功能
(3)从类路径下加载配置文件: ClassPathXmlApplicationContext
从硬盘的绝对路径下加载配置文件:FileSystemXmlApplication
5、spring配置详解
5.1、元素属性
bean元素:使用该元素描述需要spring容器管理对象
name属性:给被管理的对象起个名字,获得对象时getBean("name值")
class属性:被管理对象的完整类名
id属性:与name属性一模一样,名称不可重复,不能使用特殊字符
name和id之间的一些注意点:
1、配置两个相同的 id 或者 name 都不能通过。
2、如果既配置了 id ,也配置了 name ,则两个都生效。如果id和name都没有指定,则用类全名作为name,如,
则可以通过getBean("com.stamen.BeanLifeCycleImpl")返回该实例。
3、如果配置基本类的时候,注解和配置文件都使用的时候,注解和配置文件中 name 相同的时候, 则两个冲突,配置文件生效。
如果配置基本类的时候,注解和配置文件都使用的时候,注解和配置文件中 name 不相同的时候, 则两个不冲突,都能够生效。
5.2、bean元素的装配
(1)、bean的默认装配
Spring调用bean类的无参构造方法,创建具体的实现类
(2)、bean的作用域:bean对象的存在范围与可见性
当Spring创建一个bean的实例时不仅可以完成bean的实例化,还可以通过scope属性为bean实例指定作用域范围
【1】singleton:单例模式。即在Spring容器中,使用singleton定义的bean对象的是单例的。默认为单例模式
创建时间:Spring容器被创建的时候被创建
【2】prototype:原型模式。即在每次使用getBean方法获取到的同一个bean的实例都是一个新的实例
创建时间:被调用的时候被创建
【3】request:对于每次HTTP请求,都将会产生一个不同的Bean对象
【4】session:对于每个不同的HTTP session,都将会产生一个不同的Bean实例
注意:对于scope的值request、session只有在Web应用中使用Spring时,该作用域才有效
6、Spring的注入方式(di依赖注入,注入给属性赋值)
6.1、 注入方式: 1、使用xml中的标签和属性(set注入) 2、使用注解
注入类型: 1.值类型注入 2.引用类型注入
设值注入:Spring调用类的set方法,完成赋值,最为常用
构造注入:Spring调用类的有参构造方法完成注入
简单类型:Java的String类型和基本数据类型
6.2、简单类型set注入
语法格式:
····
····
注意:无论是何种简单类型的属性值都在双引号里
6.2、引用类型set注入
引用类型set设值注入语法格式:使用ref属性来声明要引用的对象
····
····
6.3、构造注入语法格式:既可以使用name,也可以使用index(形式参数下标,从0开始,可以不写,默认从0递增)
--->>>index可以省略,默认从0开始,此处表示了该对象构造方法的第一个参数
····
····
6.4:引用类型的自动注入
对于引用类型的注入,可以不在配置文件中显示的注入。可通过 标签的autowire属性值来为引用类型进行隐式注入(默认不自动注入)
根据自动注入的方式可分为两种:
byName:根据名称自动注入
byType:根据类型自动注入
【byName】当前声明的bean对象具有引用类型的属性,可以通过设置
Spring可以自动将被调用者(引用类型)bean注入给调用者bean(当前bean)。实现原理是容器通过调用者的bean类的属性名与配置文件的被调用者bean的
id进行比对而实现自动注入的!
例:
【被调用者】
【调用者】
<-- -->自动调用与此句等同
class School{
private String name;
private String address;
private Student stu; //引用类型的Student属性名要和被调用者的id相同
}
【byType】通过类型来实现自动注入,只需改动 autowire = "byType"
spring容器通过进行类型比对如果配置文件中有和该bean实例的引用类型的属性相同类型的bean对象,就会自动将此对象赋给调用者的bean对象
【同源类型】
1、java类中引用类型的数据类型和配置文件中的某一bean对象的数据类型一致
2、java类中引用类型的数据类型和配置文件中的某一bean对象是父子关系
3、java类中引用类型的数据类型和配置文件中的某一bean对象是接口与实现者的关系
6.5:多个配置文件,对于项目比较复杂可以分模块进行配置,一个配置文件代表一个项目模块,便于管理和阅读。大型项目中如果只使用一个配置文件那么显然
配置文件的内容会显得很臃肿且影响阅读,提高维护难度,增加程序的响应时间。因此对于大型项目使用多个配置文件进行分模块管理显然是最为明智的!
例:
spring-dao.xml
spring-tools.xml
Total.xml 总配置文件,一般不进行bean的声明,只进行引用其他配置文件的工作
具体实现:
在Total.xml这个总的配置文件中声明要引用的配置文件
····
也可使用通配符:
【注意】总配置文件不能在spring-下
附:java项目分层结构
view层作用: 视图层,即项目中的界面
controller层作用: 控制层, 获取界面上的数据,为界面设置数据; 将要实现的功能交给业务层处理
service层作用: 业务层, 功能的实现, 与controller控制层和数据访问层DAO交互, 将对数据库的操作交给DAO数据访问层来处理(java逻辑)
dao层作用: 数据访问层, 用来操作数据库表的数据
db数据库: 这里指MySQL
domain 实体包: 存放JavaBean
tools工具包:存放项目中使用到的工具类
test 测试包: 存放项目功能测试的代码
7、注解
7.1、注解使用步骤
1、创建maven仓库
2、加入Sprig依赖
3、创建实体类,声明注解
4、在配置文件中声明组件扫描器:指定注解所在的包名让容器找到注解
5、测试类
声明组件扫描器的方法在配置文件中:
7.1、具体的注解
1、创建类的注解:
component:创建类的对象的注解
value属性:相当于bean标签的id,即创建类的名称
等同于:
假如不写括号内的值(即name或id),默认使用类名首字母小写作为搜索
比如Student类中使用了@Component 没有书写括号和值,那么默认搜索id或name为student。
与component相同的功能可以创建类的注解
@repository :放在Dao层的类上,创建Dao层的对象。Dao层的对象是访问数据库的
@service : 放在service层的类上,创建service层的对象。service层表示业务层,具有事务功能
@Control : 放在Control层的类上,创建Control层的对象。Control层表示控制层,接受用户的请求
2、为简单类型赋值注解
@Value(value = "属性值")
value可以省略@Value("属性值")
注解位置:属性声明的上方、set方法上
3、为引用类型赋值注解
①使用Spring框架中提供的注解自动注入
@Autowired : 引用类型自动注入,为引用类型赋值
可以为byName 也可以是 byType 默认为byType
位置:可以在声明属性的上方也可以在set方法上
byName 方式:
@Autowired
属性:requerd: boolean类型
为真:引用类型必须赋值成功,如果失败,报错(默认为真)
为假:赋值可以不成功,但对象仍可成功创建,被调用的对象赋值为null
@Qualifier(value = "被调用对象的id")
例:
@Autowired
@Qualifier(value = "stu")
private Student student;
为以声明交由Spring创建的Student类型的id为stu的bean对象赋值给这个类
②使用jdk中提供的自动注解
@resource
属性:name : 通过byName的方式完成自动注入
【注意】使用resource如果不声明name属性的值,即指定通过byName引用的类名,那么
如果通过byName注入失败,那么就接着使用byType的方式自动注入
8、注解与配置文件的有缺点
8.1xml配置文件方式优点:
1、降低耦合,使容易扩展。
2、对象之间的关系一目了然。
3、xml配置文件比注解功能齐全,还可创建java类库中的对象等
xml配置文件方式缺点:
1、配置文件配置工作量相对注解要大,开发时需要不断切换,不利于开发人员的业务开发思路。
8.2注解方式优点:
1、在class文件中,可以降低维护成本
2、提高开发效率。
注解方式缺点:
1、如果对annotation进行修改,需要重新编译整个工程。
2、业务类之间的关系不如XML配置那样一目了然。
3、程序中过多的annotation,对于代码的简洁度有一定影响。
4、annotation貌似功能没有xml配置文件齐全
总结:注解逐渐走向主流,但配置文件暂时看来不会没落,因为相比注解其仍有注解不可替代的作用。因此程序开发中主要以注解为主,配置文件为辅
二、Aop
1、Aop简介
Aop是面向向切面编程,从动态角度考虑程序的运行过程
Aop底层使用动态代理模式(动态代理使用反射机制),可以使用jdk动态代理与第三方提供的CGLIB动态代理
Spring容器集成了动态代理(采用本地jdk代理)
2、表面理解
A: Aspert 切面
o: orient 面向
P: programming 编程
即为面向切面编程
3、具体理解
切面:指要增强的功能,常见的如日志,事务,方法的参数检查,权限,统计执行时间,
其都有一个特点:不影响业务功能,即为非业务功能,一般可以单独使用的
面向切面开发:
1、识别切面,从项目中找出能够作为切面的功能。形成单独的模块
2、把切面加入合适的位置,合适的时间
面向切面开发的好处:
1、减少重复
2、专注业务
4、Aop相关专业术语
1)、切面(Aspect)
切面泛指交叉业务逻辑,实际上就是对业务逻辑的增强
2)、连接点(JoinPoint)
连接点指可以被切面织入的具体方法。通常的业务接口中的方法均为连接点
3)、切入点(Pointcut)
切入点指声明的一个或者多个连接点的集合。通过切入点指定一组方法.切入点表示切面执行的位置
4)、目标对象 :要增强功能的类
5)、通知(Advice)
通知也叫增强,是切面在程序中的表示,通知表示切面执行时间。通知可以是接口也可以是注解,例如在方法前,方法后,方法前后等
通知分类:前置、后置、环绕、异常、最终
一个切面要执行需要有切入点(位置) 和通知(时间)
5、Spring实现Aop的方式: aspectj框架
6、aspectj框架
6.1、实现方式
注解(主要)
配置文件(事务中使用)
6.2、实现Aop的步骤
1、新建maven
2、加入依赖
加入Spring依赖
加入aspectj依赖
3、创建业务接口和实现类
4、创建切面类
在类的上方使用@Aspect注解
在切面类的方法声明通知的位置与execution表达式
5、使用注解或者在配置文件中将对象交由spring创建管理
在配置文件中声明自动代理生成器
6.3、具体的注解
1、@Aspect:表示当前类是切面类
使用位置:切面类的定义上方
2、JoinPoint:表示连接点(业务方法),作为通知方法的一个参数
连接点是切入点的一个方法
参数作用:可以获得目标方法的方法定义,方法名,参数信息等
目标方法定义:jp.getSignature()
目标方法名称:jp.getSignature().getName()
获取切入点表达式:p.getStaticPart()
获取目标对象参数数组 :jp.getArgs()
3、@Before:表示该方法放在目标方法之前执行
属性:value: execution 切点表达式,设置切面执行位置
特点:
1、在目标方法之前执行
2、不会影响目标方法的执行
3、不会改变目标方法的执行
4、@AfterReturning:将此通知放在目标方法的之后
属性
value:切入点表达式
returning :自定义变量,可以获得目标对象的返回值,注意必须和通知方法的参数名相同
特点:
1、在目标方法的最后执行
2、能够返回目标方法的返回值
5、@Author 环绕通知:可以在目标方法的前、后执行
属性:value :切入点表达式
特点:
1、可以控制目标方法是否执行
2、可以改变目标方法的执行结果
通知方法定义:
1、要有返回值:推荐返回Object
2、通知方法要必须要参数proceedingJoinPoint
注意:ProceedingJoinPoint继承了JoinPoint所以通过ProceedingJoinPoint可以获取到
目标对象的方法定义、方法名、参数数组等信息
6、 @AfterThrowing:异常通知,在目标方法抛出异常时执行
属性
value:切入点表达式
throwing :自定义变量,表示目标方法的异常对象,注意必须和通知方法的参数名相同
特点:
1、在目标方法抛出异常时执行
2、不是异常处理程序,可以看作是异常监控
通知方法中的参数要有java.long.Throwable
7、 @After:最终通知,在目标方法最后执行
属性: value: 切入点表达式
特点:
1、在目标方法之后执行
2、一定会被执行(与finally类似)
与后置通知不同的是最终通知一定会被执行,无论程序是否抛出异常
8、 @Pointcut:定义和管理切入点
属性: value :切入点表达式
位置:在自定义方法名上
作用:如果同一个切入点有多个通知,可以考虑使用这个注解,他的切入点表达式为要通知的目标方法,
方法名称(带括号)作为其他通知的切入点表达式
【注意】:其他切入点引用使用@Pointcut的方法名作为切入点表达式的时候一定不要忘记括号
该方法内部无需定义
总结:在五大通知中,前置、后置、环绕通知最为常用,其中环绕通知的功能强大,可以控制目标方法的执行以及影响目标方法的执行结果
7、spring的动态的代理模式
7.1分类:
1)、JDK动态代理,基于接口(默认代理模式)
缺点是只能为接口创建代理,返回的代理对象也只能转到某个接口类型
2)、CGLIB动态代理(若要使用需要进行配置)
CGLIB的实现机制与JDK的实现机制不同,它是通过继承实现的,它也是动态的创建一个类,但这个类的父类是被代理类
7.2、指定代理方式
在配置文件中 true使用CGLIB产生代理对象 false 使用jdk 默认false
8、使用xml实现Aop
8.1、实现Aop的步骤
1、新建maven
2、加入依赖
加入Spring依赖
加入aspectj依赖
3、创建业务接口和实现类
4、创建切面类
5、使用注解或者在配置文件中将对象交由spring创建管理
在配置文件中声明通知
8.2、声明实例
以上不论是基于注解还是xml都是使用Spring集成的aspectj框架来完成的,Spring中也有自己的方式完成Aop操作,但是过于繁琐,故开发时很少考虑
三、Spring的事务管理
1、Spring整合了mybatis,在Spring中使用mybatis的步骤
1、创建maven项目
2、加入依赖
1)、Spring依赖 spring-context
2)、mybatis依赖 mybatis
3)、mybatis-spring依赖 mybatis-spring
4)、mysql依赖 mysql-connector-java
5)、jdbc依赖 spring-jdbc
5)、druid数据库连接池依赖 druid
3、新建domain实体类
4、新建Dao层,Dao接口与sql映射文件
5、新建mybatis主配置文件
6、新建service接口和实现类,service接口中有Dao属性
7、新建spring的配置文件(重要)
1)、声明数据源DateSource对象
2)、创建SqlSessionFactory对象
3)、创建Domain具体实现类对象
4)、把domain对象赋值给service的实现类
8、新建测试类
2、什么是事务?
事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。也就是事务具有原子性,
一个事务中的一系列的操作要么全部成功,要么一个都不做。(最为典型的是转账操作)
3、事务特性
事务是恢复和并发控制的基本单位。
事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。
1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,
会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
2、一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
3、隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
4、持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
附:1、事务的并发问题
1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,
当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
2、mysql事务的隔离级别
事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted) 是 是 是
不可重复读(read-committed) 否 是 是
可重复读(repeatable-read) 否 否 是
串行化(serializable) 否 否 否
mysql默认的事务隔离级别为repeatable-read可重复读
4、 PlatformTransactionManager 事务管理器接口
spring封装了事务管理的代码(打开,提交,回滚事务)事务操作对象,因为在不同平台,操作事务的代码各不相同.spring提供了PlatformTransactionManager 接口
不同的访问数据库方法(jdbc、mybatis、hibernate)实现了这一接口,因此我们就可直接使用接口中的事务提交方法和回滚方法,而不需要考虑不同的数据库访问技术的具体实现
5、事务定义接口:TransactionDefinition
TransactionDefinition的作用是定义了控制和管理事务的一些常量值。指定事务的属性(控制事务时怎么样的,怎么操作的)
1、事务隔离级别:5个隔离级别
2、事务超时TOMEUP
超时:事务的最长执行时间,即一个方法的最长执行时间,如果超过规定时间则进行回滚操作
3、事务的传播行为
所谓事务传播行为是指,处于不同事务中的方法在相互调用时,执行期间事务的维护情况。如A事务中的方法Dosome()
调用B事务中的方法Doother(),在调用执行期间事务的维护情况,就称事务传播行为。事务传播行为是加在方法之上的
Spring中共有7个不同的事务行为,这里主要讨论一下三种
a、PROPAGATION_REQUIRED
指定的方法必须在事务内执行。若当前方法存在事务就加到当前事务中;若没有事务,就创建一个新事务。这种传播行为是最为常见的,也是Spring默认的传播行为
b、PROPAGATION_SUPPORTS
指定的方法支持当前事务,若没有事务也可以以非事务方法执行
c、PROPAGATION_REQUIRES_NEW
总是新建一个事务,若当前存在事务就将当前事务挂起,直到新事务执行完毕!
6、使用注解完成事务
在sevice的业务方法之上使用@Transactional:设置事务注解
* propagation:传播行为
* isolation:事务隔离级别
* read-only:是否只读
* timeout:超时时间
* rollbackFor:回滚
例:@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,
timeout = 20,rollbackFor = {NullPointerException.class,Mythrow.class})