总览:https://www.processon.com/view/link/605b14ab5653bb2225e6b0c5
一、Spring
1、概述
1、spring框架简介
为简化企业级开发而生,有效的降低代码的耦合度,极大的方便项目的后期维护、升级和扩展。
2、优点
轻量、AOP支持、支持对各种框架的集成
3、体系结构
1、数据访问
2、Web开发
3、AOP
4、集成消息等
5、核心容器 IOC
2、IOC控制反转
ioc(Inversion of Control)是一种设计思想,把对象的创建、赋值、管理工作都交给代码之外的容器实现,也就是对象的创建是有其他外部资源完成。
控制:创建对象,对象赋值,对象之间的关系管理
反转:把原来开发人员管理、创建对象的权限转交给代码之外的容器实现,由容器代替开发人员管理对象,创建、赋值等
正转:由开发人员在代码中,使用new构造方法创建对象,开发人员主动管理对象‘;
容器:是一个服务器软件(Tomcat),一个框架(spring)等
目的:
减少对代码的改动,也能实现不同的功能,实现解耦合
所以:java中创建对象的方式:
1、new
2、反射,class的newInstance()方法,constructor的newInstance()方法
3、反序列化
4、克隆
5、ioc
ioc的技术实现:
DI 是 ioc 的技术实现
DI (Dependency Injection)依赖注入:只需要在程序中提供使用的对象名称就可以,至于对象如何在容器中创建、赋值、查找都由容器内部实现。
spring是使用的 DI 实现了 ioc 的功能,spring底层创建对象,使用的是反射机制。
2.1 由spring创建对象
实现步骤:
-
创建maven项目
-
加入maven依赖
spring依赖、junit依赖
-
创建类(接口和他的实现类)
和没有使用框架一样,就是普通类
-
创建spring需要使用的配置文件
声明类的信息,由spring创建和管理
2.2 DI(依赖注入)的实现方式:
1、基于xml配置文件:在Spring配置文件中,使用标签和属性完成
2、基于注解的实现:使用spring中的注解,完成属性赋值
2.2.1 基于xml配置文件
适合经常需要修改
DI的语法分类:
1、 注入(set设值, 注入就是赋值):spring调用类的set方法,在set方法中实现属性的赋值(最常用)
2、构造注入,spring调用类的有参构造方法,创建对象,在构造方法中完成赋值
set注入:
- 简单类型的set注入:
property设值时name属性必须在相应的类中有set方法,且有set方法没有相应的变量也不会报错
2.引用类型的set注入:
引用类型的自动注入:
1、byName:java类中引用类型的属性名和spring容器中(配置文件) 的id名称一样,且数据类型一致,这样的容器中的bean,spring能够赋值给引用类型
让Student类中所有的引用类型都按照byName规则完成赋值
2、byType(按类型注入):java类中引用类型的数据类型和spring容器中(配置文件) 的class属性是同源关系的,这样的bean能够赋值给引用类型
同源:1、java类中引用类型的数据类型和bean中的class值一样
2、java类中引用类型的数据类型和bean中的class值父子类关系的
3、java类中引用类型的数据类型和bean中的class值接口和实现类关系的
注:只能有一个符合条件的,多个会报错
class是Student类中引用的School的值:
构造注入
name属性实现构造注入
index属性实现
可以省略index=“”,但是必须按照参数的定义顺序书写
多配置文件优势:
-
每个文件的大小比一个文件小很多,效率高
-
避免多人竞争带来的冲突
按文件的分配方式:
-
按功能模块,一个模块一个配置文件
-
按类的功能,数据库相关的配置一个配置文件,做事务的功能一个配置文件,做service功能的一个配置文件
2.2.2 基于注解的实现
快捷,方便,适合不经常修改的
实现步骤:
-
加入maven依赖spring-context(间接加入了spring-aop依赖)
-
创建类,在类中加入spring 注解@Component(value=“xxx”),省略value=也可以(常用),如果只写@Component则会默认value=首字母小写的类名
还有 @Repository(用在持久层):放在dao的实现类,表示创建dao对象,dao对象是能访问数据库的 @Service(用在业务层):service对象是做业务处理,可以有事务等功能的 @Controller(用在控制器上):放在控制器(处理器)类的上面,创建控制器对象的,控制器对象能够接受用户提交的参数,显示请求的处理结果 以上三个适用语法和@Component一样,都能创建对象,但是他们三个还有额外的功能
引用类型-@Autowired
引用类型@Resource
-
在spring配置文件中,加入一个组件扫描器的标签,说明注解在项目中的位置
需要指定多个包时:
3、AOP面向切面编程
3.1 动态代理
动态代理能创建对象,在原有类代码不变的情况下,实现功能的增加,功能增强。
3.1.1 JDK 动态代理
要求目标对象必须实现接口,java语言通过java.lang.reflect包提供三个类支持代理模式Proxy,Method和InvcationHandler,要求目标类和方法不能是final的,因为final不能被继承,不能被重写啊
实现步骤:
-
创建目标类,SomeserviceImpl目标类,给它的doSome,dother增加输出时间,事务。
-
创建InvocationHandler接口的实现类,在这个类实现给目标方法增加功能。
-
使用jdk中类Proxy ,创建代理对象。实现创建对象的能力。
作用:
-
在目标类源码不改变的情况下,增加功能
-
减少代码的重复
-
专注业务代码逻辑
-
解耦合,让业务与日志扥,事务非业务功能分离
3.1.2 CGLB动态代理(了解)
CDLIB(Code Generation Library)是一个开源项目,原理是生成目标类的子类,子类是代理对象。
3.2 AOP简介
AOP(Aspect Orient Programming) 面向切面编程,底层的实现就是采用动态代理模式实现的,采用了JDK的动态代理和CGLIB的动态代理。
Aspect:切面,给目标类增加的功能
特点:一般都是非业务方法,独立使用的
如何理解AOP:
以切面为核心,围绕切面来开发程序:
1)分析项目功能时找到切面
2)合理安排执行时间,(在目标方法前还是后)
3)合理的安排切面执行的位置, 在哪个类,哪个方法增加增强功能
3.3 AOP编程术语
-
AOP:切面,表示增强的功能,就是一堆代码,完成某一个功能,非业务功能
常见的切面功能有日志,事务,统计信息,参数检查,权限验证
-
JoinPoint:连接点,连接业务方法和切面的位置,就是某类中的业务方法
-
PointCut:切入点,指多个连接方法的集合,多个方法
-
目标对象:给哪个类的方法这个价功能,这个类就是目标对象
-
Advice:通知,表示切面功能 执行的时间,方法之前还是之后
切面三个关键要素:
- 切面的功能代码,切面干什么
- 切面的执行位置,使用PointCut表示切面执行的位置
- 切面的执行时间,使用Advice表示时间,在目标方法之前还是之后
3.4 AOP的实现
AOP是一个规范,是动态的一个规范化,一个标准
aop的技术实现框架:
-
spring:spring内部实现了aop的规范,能做aop的工作
spring在处理事务时使用aop
在项目开发中很少使用spring的aop实现,因为spring的aop比较笨重
-
Aspect:一个开源的专门做aop的框架,spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能
aspectj框架实现aop的两种方式:
- 使用xml的配置文件:配置全局事务
- 使用注解,在项目中要做aop功能,一般使用注解
3.4 AspectJ框架的使用
-
切面的执行时间,这个执行时间在规范中叫做Advice(通知,增强)
在aspect框架中使用注解表示,也可以使用xml配置文件中的标签
-
表示切面执行的位置,使用的是切入表达式
execution(访问权限 方法返回值 方法参数 异常类型)
在其中可以使用以下符号: * :0至多个任意字符 .. : 用在方法参数中,表示任意多个参数;用在包名后,表示当前包及其子包 + :用在类名后,表示当前类及其子类;用在接口名后,表示当前接口及其实现类
指定切入点为:任意公共方法 execution(public * *(..)) 指定切入点为:任意一个以set开始的方法 execution(* set*(..)) 指定切入点为:com.mhz.service包中的任意类中的任意方法,不包含子包 execution(* com.mhz.service.*.*(..)) 指定切入点为:com.mhz.service或者子包包中的任意类中的任意方法 execution(* com.mhz.service..*.*(..)) 指定切入点为:所有service包下的任意类的任意方法 execution(* *..service.*.*(..))
使用aspectJ实现aop的基本步骤:
-
新建maven项目
-
加入依赖
- spring依赖
- aspectj依赖
- junit单元测试(可有可无)
-
创建目标类:接口和他的实现类
要做的是给类中的方法增加功能
-
创建切面类:普通类
-
在类上加入注解@Aspect
-
定义方法,方法就是切面要执行的功能代码
在方法上面加入aspectj中的注解,例如@Before,
有需要指定切入点表达式execution()
-
-
创建spring配置文件:声明对象,把对象交给容器统一管理
声明对象可以使用xml配置文件 或者注解
-
声明目标对象
-
声明切面类对象
-
声明aspectj框架中的自动代理生成器标签。
自动代理生成器:用来完成代理对象的自动创建功能的。
六个注解: 1、@Before:
前置通知注解 属性: value,是切入点表达式,表示切面的功能执行的位置。 位置: 在方法的上面 特点: 1.在目标方法之前先执行的 2.不会改变目标方法的执行结果 3.不会影响目标方法的执行。
/* * 指定通知方法中的参数:JoinPoint * JoinPoint:业务方法,要加入切面功能的业务方法 * 作用是:可以在通知方法中获取方法执行时的信息,例如方法名称,方法的实参。 * 如果你的切面 功能中需要用到方法的信息,就加入JoinPoint. * 这个JoinPoint参数的值是由框架赋予,必须是第一个位置的参数 */ @Before(value = "execution(void *..SomeServiceImpl.doSome(String, Integer))") public void myBefore(JoinPoint jp){ //获取方法的完整定义 system.out.println("方法的签名(定义)="+jp.getsignature()); system.out.println("方法的名称="+jp.getsignature().getName());//获取方法的实参 object args []= jp.getArgs(); for (object arg:args){ system.out.println("参数="+arg); } }
2、@AfterReturning:
后置通知定义方法,方法是实现切面功能的。 方法的定义要求: 1.公共方法 public 2.方法没有返回值 3.方法名称自定义 4.方法有参数的,推荐是object,参数名自定义 @AfterReturning:后置通知 属性: 1.value切入点表达式 2.returning自定义的变量,表示目标方法的返回值的。自定义变量名必须和通知方法的形参名一样。 位置:在方法定义的上面 特点: 1. 在目标方法之后执行的。 2. 能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能 3. 可以修改这个返回值
@AfterReturning(value="execution(* *..SomeServiceImpl.doOther(..))",returning="res") // 此处returning的res名称=Object的res名称就行 public void myAfterReturing(object res){ // object res:是目标方法执行后的返回值,根据返回值做你的切面的功能处理 // 思考:如果是对类对象res的更改会不会影响在程序执行后得到的输出结果? system.out.println("后置通知:在目标方法之后执行的,获取的返回值是:"+res); if(res.equals("abcd")) { //做―些功能 } e1se { //做其它功能 } }
3、@Around
环绕通知 方法的定义格式: 1.public 2.必须有一个返回值,推荐使用object 3.方法名称自定义 4.方法有参数,固定的参数ProceedingjoinPoint
@Around:环绕通知 属性:value切入点表达式位宣:在方法的定义什么 特点: 1.它是功能最强的通知 2.在目标方法的前和后都能增强功能。 3.控制目标方法是否被调用执行 4.修改原来的目标方法的执行结果。影响最后的调用结果 等同于jdk动态代理的,InvocationHandler接口 参数:ProceedingJoinPoint 等同于Method 作用:执行目标方法 返回值:就是目标方法的执行结果,可以被修改
@Around(value = "execution(* *..SomeService1mpl.doFirst(..))") public object myAround(ProceedingJoinPoint pjp) throws Throwable { // 获取第一个参数值 Object[] args = pjp.getArgs(); String name = ""; if(args != null && args.length > 1){ Object arg = args[0]; name = (String)arg; } //实现环绕通知 object result = null; system.out.println("环绕通知:在目标方法之前,输出时间:"+ new Date()); //1.目标方法调用 if("xxx".equals(name)){ // 控制是否执行目标方法 result = pjp.proceed(); //method.invoke(); object result = doFirst(); } system.out.println("环绕通知:在目标方法之后,提交事务"); //2.在目标方法的前或者后加入功能 //返回目标方法的执行结果 return result; }
4、 @AfterThrowing
异常通知: 1、public 2、没有返回值 3、方法,名称自定义 4、方法有一个Exception,如果还有就是JoinPoint
@AfterThrowing:异常通知 属性:1、value 2、throwing自定义变量,表示目标方法抛出的异常对象,变量名和方法的参数名一样 特点:1、在目标方法抛出异常时执行 2、可以做异常的监控程序,如果有异常,可以发邮件,短信通知等 执行时: 没有异常就走正常逻辑,有异常就走定义的@AfterThrowing注解的方法 try{ SomeServiceImpl.doSecond(..); } catch(Exception ex){ myAfterThrowing(ex); }
@AfterThrowing(value = "execution(* *..SomeServiceImpl.doSecond(..))",throwing = "ex") public void myAfterThrowing(Exception ex){ system.out.println("异常通知:方法发生异常时,执行: "+ex.getMessage());//发送邮件,短信,通知开发人员 }
5、@ After
最终通知 方法的定义格式 1.public 2.没有返回值 3.方法名称自定义 4.方法没有参数,如果还有是JoinPoint
@After:最终通知 属性:value 切入点表达式 位置:方法上面 特点: 1、总是执行 2、目标方法后执行,即使抛出了异常 类似于: try/catch中的finally代码块
@After(value = "execution(* *..SomeserviceImpl.doThird(..))") public loidmyAfter(){ //一般做资源清除工作的。 systemyout.println("执行最终通知,总是会被执行的代码"); }
6、 @PointCut
定义管理切入点 如果项目中很多个切入点表达式是重复的,,使用@PointCut 属性:value 切入点表达式 位置:方法上面 特点: 当使用@Pointcut定义在一个方法的上面,此时这个方法的名称就是切入点表达式的别名。其它的通知中,value属性就可以使用这个方法名称,代替切入点表达式了
@Pointcut(value = "execution(* *..SomeserviceImpl.doThird(..))”) private void mypt(){ //无需代码, } // 然后: @Before(value="mypt()") public void myBefore(){ }
4、Spring事务
4.1 Spring的事务管理
-
什么是事务?
指的是一组sql语句的集合,集合中有多个sql语句,增删查改,希望这些sql语句斗殴成功或者都失败,这些sql 的执行是一致的,作为一个整体执行。
-
什么时候用到事务?
当操作涉及多个表或者多个sql语句的增删改,需要保证这些sql语句都成功才能完成功能,或者都失败,保证操作是符合要求的。
在java代码中写程序,控制事务,需要写在service类的业务方法上,因为业务方法汇调用多个dao方法,执行多个sql语句
-
jdbc、Mybatis访问数据库处理事务?
//jdbc Connection conn; conn.commit(); conn.rollback(); //mybatis SqlSession.commit(); SqlSession.rollback();
-
问3中处理事务的方式是不同的,所以有哪些不足:
-
不同的数据库访问技术,处理事务的对象、方法不同,需要掌握了解不同数据库访问技术使用事务的原理
-
掌握多种数据库中事务的处理逻辑,提交、回滚等
多种数据库访问技术,有不同的事务处理的机制,对象、方法
-
-
解决不足
spring提供一种统一处理事务的统一模型,能使用统一步骤,方式完成多种不同数据库访问技术的事务处理。
使用spring的事务处理机制,可以完成mybatis、hibernate等访问数据库的事务处理。
-
处理事务,需要怎么做,做什么
spring处理事务的模型,使用的步骤都是固定的。把事务使用的信息提供给spring就可以了-
事务内部提交,回滚事务,使用的事务管理器对象,代替你完成commit,rollback
事务管理器是一个接口和他的众多实现类。
接口:PlatformTransactionManager ,定义了事务重要方法commit , rollback
实现类: spring把每一种数据库访问技术对应的事务处理类都创建好了。
mybatis访问数据库---spring创建好的是DatasourceTransactionManagerhibernate 访问数据库----spring创建的是HibernateTransactionManager
怎么使用:你需要告诉spring 你用是那种数据库的访问技术,怎么告诉spring呢?
声明数据库访问技术对于的事务管理器实现类,在spring的配置文件中使用 声明就可以了例如,你要使用mybatis访问数据库,你应该在xml配置文件中 -
业务方法需要什么样的事务,说明需要事务的类型。
说明方法需要的事务:
1)事务的隔离级别:
DEFAULT:采用 DB默认的事务隔离级别。Mysql的默认为REPEATABLE_READ;Oracle默认为 READ_COMITTED.READ
UNCOMMITTED:读未提交。未解决任何并发问题。
READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。 REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读SERIALIZABLE:串行化。不存在并发问题。
2)事务的超时时间:表示一个方法的最长执行时间,如果方法执行超过了时间,事务就回滚
3)事务的传播行为:控制业务方法是不是有事务的,是什么样的事务
7个传播行为,表示业务方法调用时,事务在方法之间是如何使用的
<!--!!! PROPAGATION REQUIRED PROPAGATION_REQUIRES_NEW PROPAGATIONsUPPORTS --> PROPAGATIONMANDATORY PROPAGATION_NESTED PROPAGATION_NEVER PROPAGATIONNOT_SUPPORTED
-
事务提交事务,回滚事务的时机
1)当你的业务方法,执行成功,没有异常抛出,当方法执行完毕,spring在方法执行后提交事务。事务管理器commit2)当你的业务方法抛出运行时异常或ERROR,spring执行回滚,调用事务管理器的rollback
运行时异常的定义: RuntimeException 和他的子类都是运行时异常,例如Ntul1PointException , MunberFormatzxcept.
3)当你的业务方法抛出非运行时异常,主要是受查异常时,提交事务
受查异常:在你写代码中,必须处理的异常。例如IOException,SQLException
-
总结Spring事务:
- 管理事务的是 事务管理 和他的实现类
- spring的事务是一个统一模型
- 指定使用的事务管理器的实现类,使用
- 指定哪些类,哪些方法需要加入事务的功能
- 指定方法需要的隔离级别,传播行为,超时
4.2 Spring的事务传播机制
**Required **解义:如果上下文中已经存在事务,就加入到事务当中
上下文有事务 上下文没有事务 Required 加入到事务当中 新建事务 Supports 加入到事务当中 非事务方式运行 Mandatory 必须要有事务 抛出异常 Requires_New 新建事务 新建事务 Not_Supported 事务挂起,方法结束后恢复事务 Never 抛出runtime异常,强制停止执行 Nested 嵌套事务执行 新建事务 二、SpringMVC
1.1 MVC在B/S下的应用
mvc是一个设计模式
1.2 springmvc框架
过程
1、发起请求到前端控制器
2、前端控制器请求HandlerMapping查找Handler
根据xml配置、注解进行查找
3、处理器映射器HandlerMapping向前端控制器返回Handler
4、前端控制器用处理器适配器去执行Handler
5、理器适配器执行Handler
6、Handler执行完成给适配器返回ModelAndView
7、处理器向前端控制器返回ModelAndView
ModelAndView是springmvc框架的一个底层对象,包括model 和 view
8、前端控制器请求视图解析器去进行视图解析
根据逻辑视图名解析程真正的视图jsp
9、视图解析器向前端控制器返回View
10、前端控制器进行视图渲染
视图渲染将模型数据(在ModelAndView中)填充到request域
11、前端控制器向用户返回响应结果
组件:
1、前端控制器DispatcherServlet,(不需要程序员开发)
接收请求,响应结果,相当于转发器,中央处理器
减少其他组件之间的耦合度
2、处理器映射器HandlerMapping,(不需要程序员开发)
根据请求的url查找Handler
3、处理器适配器HandlerAdapter(不需要程序员开发)
按照特定规则(HandlerAdapter要求的规则)去执行Handler
编写Handler时按照HandlerAdapter的要求去做才能正确执行Handler
4、处理器Handler,(需要程序员开发)
5、视图解析器View Resolver
视图解析,根据逻辑视图域名解析成真正的视图View
6、视图View,(需要程序员开发jsp)
是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf...)
2、 json数据交互
2.1、使用json交互的原因:
json数据格式在接口调用中、html页面中常用,json格式简单,解析比较方便
2.2、springmvc进行json交互
springmvc中使用jackson的jar包进行json转换
客户端请求key / value串 请求的是json串
contenttype=application/json请求的是key / value
contenttype=@RequestBody将json串转成java对象 不需要@RequestBody将json串转成java对象 @ResponseBody将java对象转成json输出 @ResponseBody将java对象转成json输出 最后都输出json数据,为了在前端页面方便对请求结果进行解析 1、请求json、输出json,要求请求的是json串,所以在前端页面中需要将请求的内容转成json,不太方便
2、请求key / value ,输出json,比较常用
3、Restful支持
restful是一种开发理念,是对http的一个诠释,即表现层状态的转化
对url进行规范,写restful格式的url,就是简洁
非rest的url:http://.../finditems.action?id=001
rest的url风格:http://.../items/001
-