Spring
IOC(控制反转)
概念
把对象的创建、初始化、销毁等工作交给spring容器来做
helloWorld案例
环境
步骤
1、 写一个HelloWorld类
2、 写一个配置文件
3、 客户端
4、 说明:
Spring容器的作用就是为HelloWorld这个类创建对象
Spring容器的结构
创建对象
构造函数(用的最多)
在配置文件中进入如下的配置:
在客户端
HelloWorld类本身:
在控制台打印出了”create object”
可以看出:spring内部默认是调用了HelloWorld这个类的默认的构造函数创建对象
静态工厂
实例工厂
说明:
给工厂类创建了一个对象helloWorldFactory,再利用工厂对象调用工厂方法。
别名
对象的创建时机
案例
执行步骤为1,3,2
以上两种情况是默认值,当spring容器启动的时候创建对象
在bean有这样一个属性
Default 相当于false 在spring容器启动的时候,创建对象
True 在context.getBean时创建对象
False 在spring容器启动的时候创建对象
意义
如果把lazy-init设置为true,则当spring容器启动的时候,检测不到任何错误,这样会存在很大的安全性隐患,所以一般情况下应该设置lazy-init为default/false。但是如果一个bean中有一个属性,该属性含有大量的数据,这个时候不希望该bean过早的停留在内存中。
这个时候需要用到lazy-init为true。
对象的scope
默认情况(scope=singleton)
在默认情况下放入到spring中的bean是单例的
将来service层和dao层所有的类将放入到spring容器中,所以默认情况下这两个层的类的实例都是单例的,所以不能把数据声明到属性中。如果声明在属性中,将会成为共享的。
Scope为prototype
创建时机和scope的结合
Scope为prototype,lazy-init为true
在context.getBean时创建对象
Scopse为prototype,lazy-init为false
在context.getBean时创建对象,lazy-init为false失效
当scpose为prototype时,始终在context.getBean时创建对象
Scopse为singleton
是默认情况
Init和destroy
说明:
1、 init方法是由spring内部执行的
2、 只有当spring容器关闭以后才能执行destroy方法,spring容器一般情况下是不会关闭的。只有当web容器销毁掉的时候才可能关闭掉,所以只要一个对象在spring容器中,在spring容器关闭之前,会一直保留。
3、 如果一个bean的配置是scope为”prototype”,则spring容器不负责销毁。
Spring容器做的事情
总结
创建对象
1、 对象的创建方式
2、 对象的创建时机
3、 对象的创建的模式
4、 Init和destroy
5、 创建时机和创建模式的结合
初始化和销毁
DI(依赖注入)
概念
给属性赋值
给pid和name赋值的过程就是di
Xml
Setter方法
说明:
1、 spring容器实例化person和student两个对象
2、 利用java的反射机制调用属性的setter方法赋值
3、 在客户端利用context.getBean方法把spring容器中的一个对象获取了。
说明:
1、 启动spring容器
2、 实例化person对象和student对象
3、 给person中的属性赋值
4、 调用person的init方法初始化
5、 客户端利用context.getBean获取对象
说明:
1、 启动spring容器
2、 实例化person对象
3、 因为person对象依赖于student对象,所以在实例化person对象的时候必须实例化student对象,所以这个时候,在student对象上的lazy-init为true将失效。
说明:
1、 启动spring容器
2、 实例化student
3、 在客户端执行context.getBean方法获取person对象
4、 实例化person对象,调用person的构造函数
5、 调用person中的setStudent方法,给person中的student赋值
6、 执行person中的init方法
7、 Person对象调用方法
构造器
说明:
1、 constructor-arg代表指定的构造器函数的其中的一个参数
2、 可以利用index,ref,value,type来指定唯一的构造器
3、 如果一个bean的配置中没有constructor-arg属性,则必须利用默认的构造函数创建对象。
4、 所以在写一个javabean的时候,应该提供属性的setter方法,默认的构造器,带参数的构造器
注解
概念
1、 用来解释说明
2、 注解必须作用在类的某一个部分
3、 注解的作用域范围(java,class,jvm)
4、 注解解析器
自定义的注解
注解的使用
注解解析器
Spring中的注解
在spring的配置文件中
说明:
1、 启动spring容器
2、 spring容器内部创建了两个对象person和student
3、 当spring容器解析到
启动依赖注入的注解解析器:
4、 spring容器在容器中查找所有的bean(prerson,student)
5、 看哪些bean的属性上面是否有Resource注解
6、 如果属性上面有该注解,再次检查是否有name属性
7、 如果没有name属性,则会把该注解标注的属性的名称获取到和spring容器中的id做匹配,如果匹配成功,则赋值,如果匹配不成功,则按照类型进行匹配,如果匹配成功,则赋值,如果匹配不成功,则报错。
8、 如果有name属性,则把name属性的值解析出来和spring容器中的id做匹配,如果匹配成功,则赋值,如果匹配不成功,则报错。
9、 从上述的步骤可以看出注解的效率比较低,xml的效率比较高,注解书写比较简单,xml书写比较复杂。
Spring容器的关于di的注解
按照类型匹配
按照ID匹配
注解只能应用与引用类型
类扫描的注解
步骤
说明:在指定的包及子包中扫描
流程分析
1、 启动spring容器
2、 Spring容器解析类扫描的注解解析器,在base-package指定的包及子包中查找所有的类
3、 查看哪些类上面是否含有@Component注解
4、 如果该注解的value的属性的值为空,则把类名的第一个字母变成小写,作为id值,放入到spring容器中
5、 如果该注解的value的属性的值不为空,则用value的属性的值作为id值,放入到spring容器中
6、 再次查找在spring容器中的类的所有的属性,按照@Resource的规则给属性赋值
说明
使用了类扫描机制的做法,配置文件中的配置很简单了,但是效率越来越低。
继承
Xml的继承
注解的继承
IOC和DI的意义
案例1
需求
编写一个文档管理系统,在该系统中有如下的结构:
1、 Document:interface
readDocument
writeDocument
2、 WordDocument 是Document的实现类
readDocument
writeDocument
3、 ExcelDocument
readDocument
writerDocument
4、 PDFDocument
readDocument
writeDocument
5、 DocumentManager
Document document;
readDocument()
writeDocument()
做法1
说明:
上述的代码是不完全的面向接口编程
做法2
说明:
在代码端没有出现具体的类,完全的面向接口编程。
在spring容器的配置文件中决定了documentManager中的接口的实现类是什么。而这个过程和java代码端没有关系。
案例2
需求
把action调用service,service调用dao用spring来完成
实现
意义
实现了完全的面向接口编程,在代码端没有要关系一个接口的实现类是什么。
Aop
目的
让PersonDao的数据库的操作和Transaction事务的操作分离。
代理模式
静态代理模式
动态代理模式
Jdk动态代理
接口
目标类
拦截器
客户端
问题
1、 代理对象有多少方法,方法的名称是什么?
因为代理对象和目标类一样,同样的实现了接口,所以接口中有多少方法,代理对象中就有多少个方法,名称和接口中的方法的名称一样。
2、 拦截器中的invoke方法在什么时候执行的?
当在客户端,代理对象调用方法的时候,进入到了invoke方法
3、 拦截器中的invoke方法中的method参数在什么时候传递的值?
当在客户端,代理对象调用方法的时候,进入到了invoke方法,这个时候,method参数就是代理对象调用的方法。
4、 代理对象的方法体的内容是什么?
代理对象的方法体的内容就是invoke方法体的内容
代理对象的方法体:
1、 开启事务
2、 目标方法
3、 事务的提交
4、 代理对象的方法体就把事务和目标方法结合在一起了,这样做的目的就是为了让目标类的目标方法和事务的方法松耦合。
流程图
作用:把目标类和事务松耦合。
Cglib代理
1、 产生的代理类是目标类的子类
2、 是用字节码增强技术产生的代理类
案例
目标接口
目标类
日志
安全性框架
权限类
拦截器
拦截器把这些内容全部结合在一起了。
改进
可以把日志、安全性框架等作为一个接口出现
日志:
在拦截器中:
Aop的概念
切面
事务、日志、安全性的框架,权限等就是切面
通知
切面中的方法就是通知
切入点
只有符合切入点的条件,才能让通知和目标方法结合在一起
织入
形成代理对象方法体的过程
Aop的意义
说明:
1、 在开发的过程中,日志、权限、安全性的框架、目标方法完全是松耦合的
2、 在形成代理对象的方法的过程中就把这几个结合在一起了
Spring的aop
步骤
目标接口
目标类
切面
Spring的配置文件
执行流程
说明:
1、 context.getBean时,如果该类没有生成代理对象,则返回对象本身
2、 如果产生了代理对象,则返回代理对象
3、 如果目标类实现了接口,则采用jdkproxy生成代理对象,如果目标类没有实现接口,则采用cglibproxy生成代理对象,而生成代理对象是由spring容器内部完成的。
切入点表达式
![](https://i-blog.csdnimg.cn/blog_migrate/3cfe0a29db86d2fe964403d4205dabd7.png)
代表所有的公共方法
代表所有的以set开头的方法
代表com.xyz.service包下的AccoutService类的所有的方法
代表com.xyz.service包下的所有的类的所有的方法
代表com.xyz.service包及子包下的所有的类的所有的方法
代表com.itheima.spring.aop.xml包下的所有的类的有三个参数,第一个参数为Long,第二个参数为String,第三个参数为任意类型的所有的方法
通知
前置通知
在目标方法执行之前执行。
后置通知
在目标方法执行之后执行
可以获取目标方法的返回值
当目标方法遇到异常,不执行
最终通知
无论目标方法是否遇到异常都会执行,相当于代码中的finnaly
异常通知
获取目标方法抛出的异常
环绕通知
能够控制目标方法的执行
案例:异常处理
技术图
实现
切面
目标类
配置
从配置中可以看出,把service层所有的类当成目标类,只要service层所有的类的所有的方法抛出异常,则exceptionAspect中的异常通知就会获取到目标方法抛出的异常,所以在这里异常通知就是用来处理异常的,而且只有一个方法。并且该切面和所有的其他类都是松耦合的。
案例:权限的处理
技术图
组成
1、 写dao层和service层的类和接口
2、 自定义的注解@PrivilegeInfo
3、 注解解析器:解析目标方法上面的注解的name属性的值
4、 写一个权限类Privilege(name)
5、 写一个关于权限的判断的切面,在切面中写一个环绕通知
实现
参照:/day03-02-itheima09-springAOP-xml-ex-privilege
扩展作业
利用spring的aop的环绕通知,记录如下的信息:
目标类 目标方法 执行时间 方法的起始时间 方法的结束时间
把上述的几个内容保存在数据库中,用jfreechar或者用table显示出来
Spring与数据库
Spring与jdbc
引入dataSource
在客户端:
模板编程
类的结构图
方案
方案1
方案2
方案3
Spring与jdbc的查询
Spring的声明式事务处理
概念
程序员不再负责处理事务,事务处理交给spring容器来做。
具体的详解
程序员负责两个内容:
1、 对表的crud操作:目标类的目标方法
2、 告诉spring容器什么样的目标方法采用什么样的事务策略
Spring容器负责:(切面)
负责事务的处理
实现原理
采用了aop技术来实现的。
事务的架构
事务的定义
事务的状态
说明:通过spring的事务处理架构,再通过配置文件具体的实现事务的类,就可以让spring容器知道是什么样的技术来操作数据库,通过对事务状态的判断,通过事务的定义就可以知道具体的目标方法采用什么样的事务策略来处理了。
Spring与hibernate
组成
1、 hibernate的配置文件
2、 持久化类和映射文件
3、 Dao层和service层所有的类
4、 Spring的配置文件
5、 客户端
Spring的配置文件
关于session
从上图可以看出,程序员使用sessionFactory产生session,从而进行crud的操作
Spring容器利用sessionFactory产生session,进行事务的操作,所以spring容器产生
的session和程序员用的session肯定是同一个session,所以在spring声明式事务处理的
时候,session必须由当前线程产生。
Ssh的整合
项目整合
原则
谁能先测试先写谁
步骤
创建web project
把工程改成utf-8的编码
在lib下导包
数据库的驱动包
Struts2的jar包
struts2-spring-plugin-2.3.1.2.jar struts2与spring整合的jar包
hibernate的jar 包
spring的jar包
创建三个src folder
Src
存放源代码
Config
存放配置文件
Test
存放测试类
在src下创建一个包放持久化类和映射文件
在config下创建一个package:hibernate.cfg.xml
在该包下创建hibernate的配置文件
在classpath下准备jdbc.properties
在config下创建package:spring
在applicationContext-db.xml文件中:
在spring的配置文件中引入sessionFactory
对sessionFactory进行测试
创建dao层和service层的接口和类
在spring的配置文件中配置声明式事务处理
对声明式事务处理进行测试
创建action层的包和类
把action放入到spring的配置文件中
准备struts2的配置文件
编写struts-person.xml
写web.xml
配置一个监听器
配置一个过滤器
S2sh的整合的目的
问题
1、 struts2的action为什么必须交给spring容器产生?
Action与service要做到完全的松耦合,所以在action中的service必须由spring容器进行注入,那么要完成该注入,action必须在spring容器中。所以action必须由spring容器产生。
2、 在整合的整个过程中,spring容器用到了哪些知识点?
1、 为了松耦合action与service,service与dao,使用了ioc和di
2、 为了不让程序员接触到事务,使用了声明式的事务处理
3、 有可能会用springaop处理权限、日志等内容
3、 在整合的过程中,struts2用到了哪些知识点?
1、 mvc的作用
2、 使用插件的机制使得struts2与spring整合在一起了,实际上就是把
Struts2中的action交给spring处理了。
4、 在整合的过程中,hibernate充当了什么角色?
数据库的操作由hibernate充当