一、概述
1、spring简介
- Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架;
- 核心就是控制反转和面向切面编程;
2、简单入门程序
- 导包,四个核心包和一个logging的包;
- 写一个类并在 xml 中配置相应的bean;
- 测试:calssPathXmlApplicationContext----ctx.getBean()----调用方法;
二、IOC 和 DI
1、IOC 和 DI 的简单理解
(1)IOC(Inversion of Control,控制反转)
- IOC是spring的核心,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系;
- 所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转;
(2)DI(依赖注入)
- IOC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象,这一点是通过DI来实现的;
- 接管对象的创建工作,并将对象的引用注入到需要该对象的组件;
- 依赖注入的形式有:setter、构造、注解Autowired(基于字段);
2、bean的配置
(1)基本配置
- id 是唯一标识,通过他,我们可以在容器中找到这个 bean,class 配全限定名,以便spring通过反射来创建bean,所以这个类必须要有空参构造器;
- bean 的创建有两种方法:beanfactory 和 Applicationcontext(一般用这个);
- 依赖注入的方式:有属性注入和构造器注入,属性注入有name 和 value,构造器注入只有value,可以通过index 和 参数的类型(type)来区分参数的对应;
(2)细节
- 属性配置:String、基本类型及其包装类赋值直接用 value 即可;但是引用类型要用 ref;
- 属性配置:spring 支持级联属性的写法,但是在使用级联属性的时候,一定要先初始化 bean;
- 属性配置:属性是集合类型的list,用 list--ref
- 属性配置:属性是集合类型的map,用 map--entry--key--value
- 属性配置:属性是集合类型的properties,用 props--prop
- 属性配置:使用 p 命名空间可以直接在bean 标签里直接配置属性 P:name = value
- 内部 bean:不能为外部所引用,property-bean
- 独立集合 bean:方便在其他地方引用,引入命名空间<util:list>
(3)属性的自动装配(*)
- 名称:属性名和 id 名一致才能自动装配,否则就是 null;autowire="byName"
- 类型:通过属性的类型自动匹配,如果两个属性的类型一样就会装配失败;autowire="byType"
- 构造器:用的少
(4)bean 之间的关系
- 抽象 bean :abstract=“true” ;抽象bean可以不用指定 class,不可以实例化,同时不能被依赖;
- 继承:parent属性指定,可以从父 bean 继承的属性用 ^ 标记;
- 依赖:depends-on来指定;被依赖的会在以前就创建好;
(5)bean 的作用域
- scope="singleton":单例,只创建一个实例;
- scope="prototype":每次 get 都会创建一个新的实例;
(6)使用外部属性文件:context:place-holder------${}
(7)spEL:有点类似于 jsp 中的 el 表达式,具体的作用如下:
3、bean 的生命周期
(1)init/destroy-method 指定bean 创建和销毁时要调用的方法
(2)执行的顺序:construtor--set--before--init--after--Car [brand=audi]
4、工厂方法配置 bean
(1)静态工厂
(2)实例工厂
(3)通过 factoryBean 来配置
5、bean 的注解配置
(1)四个注解
- @component、@repository、@service、@controller;
- 作用就是当作标识,让 spring 能够找到这些bean,并且实例化;
(2)组件扫描
- <ontext:component-scan>
- 属性 package 和 useDefaultfilter
(3)扫描过滤
- 用resource-pattern 属性过滤:
- include-filter 和 exclude-filter 标签来实现过滤:注意在 include 的时候一定要指定 udf 为 false;除了可以用注解过滤还可以用类指定过滤的策略;
(4)依赖注入
- 可以使用注解:@autowire、@resource、@injec;一般用第一个;
- 说明:先找类型,再找bean 的名称匹配的;
- 说明:相同类型的bean 有很多个,要么在组件的注解里申明bean 的名字,要么在autowire‘的下面用@qualifier标签指定bean 的默认的名字;
- 说明:@AutoWired注解可以用在属性、方法和构造器上;
(5)泛型依赖注入
- 实际上就是带泛型的父类之间有依赖的关系,子类继承之后会自动拥有这个关系,并且注入的是确定泛型的子类
三、AOP(面向切面编程)
1、概述
(1)原理:aop底层就是用动态代理来实现的,基于aspectJ框架实现的
(2)几个概念
- 切面(Aspect):跨越应用程序多个模块的功能;
- 通知():切面必须要完成的工作;
- 连接点(joinpoint):需要增强的类的方法是哪一个,在这个方法之前还是之后进行增强;
- 切点(cutpoint):通过切点可以找到连接点,切点通过类和方法作为条件来找连接点,所以一个切点可以映射多个连接点;
- 目标对象和代理对象;
2、通知
(1)前置通知
- 导包4个并在配置中加入aop 的命名空间;
- 把横切关注点的逻辑提取到切面类中,该类通过注解@Component注入到容器,通过@Aspect标记为切面,在具体的方法上用@before(具体的类和方法)声明切点;before括号中的内容可以用 * 作为通配符;
- 配置文件中开启aop的注解支持;
- 进行测试;
(2)后置通知
- 和前置不同的就是before 变成了 after;
- 实际上后置通知的执行位置应该是方法执行后返回结果前;所以后置通知中无法获取到返回的结果;
- 后置通知无论方法是否发生异常都会执行;
- 所有的通过都可以在参数中加一个joinpoint 来获取连接点的信息;
(3)返回通知@AfterReturning(value="",returning="")
- 没有发生异常的情况下可以获取到方法的返回值;
(4)异常通知@AfterThrowing(value="",throwing="")
- 发生异常的情况下会执行异常通知;
- 可以针对特点的异常来触发通知;在异常通知里可以获取到异常的相关信息;
(5)环绕通知(*)
- 本身就类似于一个代理对象了,可以实现所有的前置后置之类的通知;
- @Around();其中重要的参数是 ProceedingJoinPoint,这个参数可以控制目标对象方法的执行;
(6)切面优先级和切点重用
- 优先级:在类的上方用 @Order(1)来指定,数字越小优先级越高;
- 重用:在类中用 @Pointcut 来指定一个空的方法为切点,后面直接在通知的注解里写方法的名称即可引用;
3、在配置文件中配置 AOP
(1)配置目标对象的bean;
(2)配置切面的 bean;
(3)配置 Aop:
- 配置切点
- 配置切面-----配置通知
4、jdbctemplate 和 jdbcdaosurpport 使用
(1)jdbctemplate:完成增删改查的操作
- 在spring 的配置文件中配置数据源和 jdbctemplate;
- 从数据库从得到一条记录结果应该映射为一个对象,这时拥 queryForObject方法要用到一个RowMapper来指定结果集的映射规则;
(2)jdbcdaosurpport:
- 不推荐使用,使用的时候要注入datasource 或者 jdbctemplate
- 本质上还是通过jdbctemplate 来操作数据库
(3)NamedparameterJdbctemplate
- 这个 template 的特点是在sql使用占位符的时候指定一个名字,而不是使用?,指定名字的格式为(:name);
- 其中的指定的名称要和 bean 的属性一致才能正确设置参数;
四、spring 事务
1、事务概述
⑴ 原子性(Atomicity)
- 事务包含的所有操作要么全部成功,要么全部失败回滚;
⑵ 一致性(Consistency)
- 事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态;
⑶ 隔离性(Isolation)
- 多个并发事务之间要相互隔离(事务的隔离级别参考数据库部分);
⑷ 持久性(Durability)
- 一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作;
2、spring 的声明式事务
(1)使用步骤:
- 配置一个 transactionManager,注入 dataSource;
- 配置事务的注解驱动;
- 在需要加入事务管理的 service 方法上加上@Transactional 的注解;
(2)xml 方式配置事务
- 正常配置 bean;
- 配置 transactionManager;
- 配置事务属性 tx:advice;
- 在 aop:config 配置切点 ,并把切点和属性关联;
3、事务的属性
(1)传播行为
- 指的就是一个事务方法对另一个事务方法的影响(二者有调用的关系);
- 默认的传播行为是 required ,在事务注解里加上参数propagation = propagation.required,required 就是被调用方法沿用调用者的事务;
- 另一个属性的值是 require new 就是被调用方法用自己的事务,方法执行时调用者的事务挂起;
(2)隔离级别 | 回滚 | 只读 | 过期
- 隔离级别:在事务注解中用 isolation 配置;
- 回滚:norollBackfor 一般不用配,默认即可;
- 只读:readOnly 只是查询的话可以配置为true,有利于数据库引擎的优化;
- 过期:timeout 可以避免一个事务长时间占用数据库资源;
五、SSH整合
1、spring 和 hibernate 整合
(1)整合目的:就是让spring 管理 hibernate 的sessionFactory ,并且实现声明式事务管理;
(2)整合步骤
1、加入hibernate
- 加入 jar;
- 配置 hibernate.cfg.xml 和 *.hbm.xml 文件;
- hibernate 的配置文件里只用配置数据库方言、缓存啥的,甚至是可以不要cfg 配置文件;
2、加入spring
- 加入 jar;
- 编写配置文件:dataSource-->sessionFactory(dataSource、configLocation、mappingLocations、hibernateProperties)-->事务配置;
- 事务配置还是老样:配置 transactionManager----tx:advice---aop:config
(3)spring 管理 hibernate 事务流程(就是 AOP 的思想)
- 方法开始之前:获取 session 和当前线程绑定,这样就可以在 dao 中用sessionFactory的getCurrentSession()方法来获取,并开启事务;
- 方法正常结束:提交事务,解除session 和当前线程的绑定,关闭 session;
- 方法发生异常:回滚,解除绑定,关闭session;
2、spring 和 struts 整合
(1)web 环境下使用Spring
- 加入两个 jar,一个 web 和一个 webmvc;
- spring 配置文件无特殊配置;
- web xml 文件中需要加入两个配置,一个spring配置文件位置的全局变量和一个监听器,监听器的作用就是在servletContext创建的时候,创建一个 ioc 容器,并把 ioc 容器放到servletContext 中;
(2)spring 整合 struts 的目标是让 spring 来管理 struts 的Action
(3)具体整合步骤:
- 正常加入 struts;
- 在 spring 的 ioc 容器中配置 Action,配置 action 需将 scope 属性设置为 prototype;
- 配置 struts 的配置文件:class属性的值不能再是全路径名了,而是 spring 中的bean id,具体的原理就是先根据bean 的id 到 ioc 容器中去找action,找不到再自己创建一个;
- 加入 struts-spring-plugin 的jar 包,这个 jar 包中有一个对象工厂;