Loading

Spring入门笔记简要

总览: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创建对象

实现步骤:
  1. 创建maven项目

  2. 加入maven依赖

    ​ spring依赖、junit依赖

  3. 创建类(接口和他的实现类)

    ​ 和没有使用框架一样,就是普通类

  4. 创建spring需要使用的配置文件

    ​ 声明类的信息,由spring创建和管理

仅限于初学的写法:

2.2 DI(依赖注入)的实现方式:

1、基于xml配置文件:在Spring配置文件中,使用标签和属性完成

2、基于注解的实现:使用spring中的注解,完成属性赋值

2.2.1 基于xml配置文件

​ 适合经常需要修改

DI的语法分类:

1、 注入(set设值, 注入就是赋值):spring调用类的set方法,在set方法中实现属性的赋值(最常用)

2、构造注入,spring调用类的有参构造方法,创建对象,在构造方法中完成赋值

set注入:

  1. 简单类型的set注入:

property设值时name属性必须在相应的类中有set方法,且有set方法没有相应的变量也不会报错

​ 2.引用类型的set注入:

​ 引用类型的自动注入:

​ 1、byName:java类中引用类型的属性名和spring容器中(配置文件)的id名称一样,且数据类型一致,这样的容器中的bean,spring能够赋值给引用类型

<bean id="xx" class="yy" autowire="byName"></bean>

让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=“”,但是必须按照参数的定义顺序书写

多配置文件优势:

  1. 每个文件的大小比一个文件小很多,效率高

  2. 避免多人竞争带来的冲突

    按文件的分配方式:

  3. 按功能模块,一个模块一个配置文件

  4. 按类的功能,数据库相关的配置一个配置文件,做事务的功能一个配置文件,做service功能的一个配置文件

2.2.2 基于注解的实现

​ 快捷,方便,适合不经常修改的

实现步骤:

  1. 加入maven依赖spring-context(间接加入了spring-aop依赖)

  2. 创建类,在类中加入spring 注解@Component(value=“xxx”),省略value=也可以(常用),如果只写@Component则会默认value=首字母小写的类名

    还有
    @Repository(用在持久层):放在dao的实现类,表示创建dao对象,dao对象是能访问数据库的
    @Service(用在业务层):service对象是做业务处理,可以有事务等功能的
    @Controller(用在控制器上):放在控制器(处理器)类的上面,创建控制器对象的,控制器对象能够接受用户提交的参数,显示请求的处理结果
    以上三个适用语法和@Component一样,都能创建对象,但是他们三个还有额外的功能
    
    

    引用类型-@Autowired

    引用类型@Resource

  3. 在spring配置文件中,加入一个组件扫描器的标签,说明注解在项目中的位置

    需要指定多个包时:

3、AOP面向切面编程

3.1 动态代理

​ 动态代理能创建对象,在原有类代码不变的情况下,实现功能的增加,功能增强。

3.1.1 JDK 动态代理

​ 要求目标对象必须实现接口,java语言通过java.lang.reflect包提供三个类支持代理模式Proxy,Method和InvcationHandler,要求目标类和方法不能是final的,因为final不能被继承,不能被重写啊

实现步骤:

  1. 创建目标类,SomeserviceImpl目标类,给它的doSome,dother增加输出时间,事务。

  2. 创建InvocationHandler接口的实现类,在这个类实现给目标方法增加功能。

  3. 使用jdk中类Proxy ,创建代理对象。实现创建对象的能力。

作用:

  1. 在目标类源码不改变的情况下,增加功能

  2. 减少代码的重复

  3. 专注业务代码逻辑

  4. 解耦合,让业务与日志扥,事务非业务功能分离

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编程术语

  1. AOP:切面,表示增强的功能,就是一堆代码,完成某一个功能,非业务功能

    ​ 常见的切面功能有日志,事务,统计信息,参数检查,权限验证

  2. JoinPoint:连接点,连接业务方法和切面的位置,就是某类中的业务方法

  3. PointCut:切入点,指多个连接方法的集合,多个方法

  4. 目标对象:给哪个类的方法这个价功能,这个类就是目标对象

  5. Advice:通知,表示切面功能 执行的时间,方法之前还是之后

切面三个关键要素:

  1. 切面的功能代码,切面干什么
  2. 切面的执行位置,使用PointCut表示切面执行的位置
  3. 切面的执行时间,使用Advice表示时间,在目标方法之前还是之后

3.4 AOP的实现

​ AOP是一个规范,是动态的一个规范化,一个标准

​ aop的技术实现框架:

  1. spring:spring内部实现了aop的规范,能做aop的工作

    ​ spring在处理事务时使用aop

    ​ 在项目开发中很少使用spring的aop实现,因为spring的aop比较笨重

  2. Aspect:一个开源的专门做aop的框架,spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能

    aspectj框架实现aop的两种方式:

    1. 使用xml的配置文件:配置全局事务
    2. 使用注解,在项目中要做aop功能,一般使用注解

3.4 AspectJ框架的使用

  1. 切面的执行时间,这个执行时间在规范中叫做Advice(通知,增强)

    在aspect框架中使用注解表示,也可以使用xml配置文件中的标签

    <!-- 5个常用注解
    @Before
    @AfterReturning
    @Around
    @After
    @AfterThrowing
    -->
    
  2. 表示切面执行的位置,使用的是切入表达式

    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的基本步骤:
  1. 新建maven项目

  2. 加入依赖

    1. spring依赖
    2. aspectj依赖
    3. junit单元测试(可有可无)
  3. 创建目标类:接口和他的实现类

    要做的是给类中的方法增加功能

  4. 创建切面类:普通类

    1. 在类上加入注解@Aspect

    2. 定义方法,方法就是切面要执行的功能代码

      ​ 在方法上面加入aspectj中的注解,例如@Before,

      ​ 有需要指定切入点表达式execution()

  5. 创建spring配置文件:声明对象,把对象交给容器统一管理

    ​ 声明对象可以使用xml配置文件或者注解

    1. 声明目标对象

    2. 声明切面类对象

    3. 声明aspectj框架中的自动代理生成器标签。

      ​ 自动代理生成器:用来完成代理对象的自动创建功能的。

    <!--把对象交给spring容器,由spring容器统―创建,管理对象-->
    <! --声明目标对象-->
    <bean id="someservice" class="com.bjpowernode.bao1.SomeserviceImpl"/>
    <! --声明切面类对象-->
    <bean id="myAspect" class="com.bjpowernode.ba01.MyAspect”/>
    <!--
    声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象。
    创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象所以目标对象就是被修改后的代理对象
    aspectj-autoproxy:会把spring容器内的所有目标对象,一次性都生成代理对象
                               -->   
    <aop: aspectj-autoproxy />
    
  6. 创建测试类,从spring容器中获取目标对象(代理对象)

    ​ 通过代理对象实现aop

六个注解:

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的事务管理

  1. 什么是事务?

    ​ 指的是一组sql语句的集合,集合中有多个sql语句,增删查改,希望这些sql语句斗殴成功或者都失败,这些sql 的执行是一致的,作为一个整体执行。

  2. 什么时候用到事务?

    ​ 当操作涉及多个表或者多个sql语句的增删改,需要保证这些sql语句都成功才能完成功能,或者都失败,保证操作是符合要求的。

    ​ 在java代码中写程序,控制事务,需要写在service类的业务方法上,因为业务方法汇调用多个dao方法,执行多个sql语句

  3. jdbc、Mybatis访问数据库处理事务?

    //jdbc
    Connection conn;
    conn.commit();
    conn.rollback();
    //mybatis
    SqlSession.commit();
    SqlSession.rollback();
    
  4. 问3中处理事务的方式是不同的,所以有哪些不足:

    1. 不同的数据库访问技术,处理事务的对象、方法不同,需要掌握了解不同数据库访问技术使用事务的原理

    2. 掌握多种数据库中事务的处理逻辑,提交、回滚等

      多种数据库访问技术,有不同的事务处理的机制,对象、方法

  5. 解决不足

    ​ spring提供一种统一处理事务的统一模型,能使用统一步骤,方式完成多种不同数据库访问技术的事务处理。

    ​ 使用spring的事务处理机制,可以完成mybatis、hibernate等访问数据库的事务处理。

  6. 处理事务,需要怎么做,做什么
    spring处理事务的模型,使用的步骤都是固定的。把事务使用的信息提供给spring就可以了

    1. 事务内部提交,回滚事务,使用的事务管理器对象,代替你完成commit,rollback

      事务管理器是一个接口和他的众多实现类。

      接口:PlatformTransactionManager ,定义了事务重要方法commit , rollback

      实现类: spring把每一种数据库访问技术对应的事务处理类都创建好了。
      mybatis访问数据库---spring创建好的是DatasourceTransactionManagerhibernate

      ​ 访问数据库----spring创建的是HibernateTransactionManager
      怎么使用:你需要告诉spring 你用是那种数据库的访问技术,怎么告诉spring呢?
      声明数据库访问技术对于的事务管理器实现类,在spring的配置文件中使用声明就可以了例如,你要使用mybatis访问数据库,你应该在xml配置文件中

      <bean id="xxx" class=" . ..DataSourceTransactionManager">
      
    2. 业务方法需要什么样的事务,说明需要事务的类型。

      ​ 说明方法需要的事务:

      ​ 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
      
    3. 事务提交事务,回滚事务的时机
      1)当你的业务方法,执行成功,没有异常抛出,当方法执行完毕,spring在方法执行后提交事务。事务管理器commit

      2)当你的业务方法抛出运行时异常或ERROR,spring执行回滚,调用事务管理器的rollback
      运行时异常的定义: RuntimeException 和他的子类都是运行时异常,例如Ntul1PointException , MunberFormatzxcept.
      3)当你的业务方法抛出非运行时异常,主要是受查异常时,提交事务
      受查异常:在你写代码中,必须处理的异常。例如IOException,SQLException

总结Spring事务:

  1. 管理事务的是 事务管理 和他的实现类
  2. spring的事务是一个统一模型
    1. 指定使用的事务管理器的实现类,使用
    2. 指定哪些类,哪些方法需要加入事务的功能
    3. 指定方法需要的隔离级别,传播行为,超时

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

posted @ 2022-03-10 10:06  醉千灯  阅读(143)  评论(0编辑  收藏  举报