Spring学习

Spring框架概述

  1. Spring是一个轻量级的开源的JavaEE框架
  2. Spring可以解决企业应用开发的复杂性
  3. Spring有两个核心部分:IOC和AOP
    1. IOC:控制反转,把创建对象过程交给Spring进行管理
    2. Aop:面向切面编程,不修改源代码进行功能的增强
  4. Spring特点
    1. 方便解耦,简化开发
    2. Aop编程支持
    3. 方便程序测试
    4. 方便和其他框架进行整合
    5. 方便进行事务操作
    6. 降低API开发难度

IOC容器

IOC(概念和原理)

  1. 什么是IOC
    1. IOC又名控制反转,把对象的创建和对象之间的调用的过程,交给Spring进行管理
    2. 使用IOC的目的:为了降低耦合度
  2. IOC的底层原理
    1. xml解析、工厂模式、反射
      IOC实现原理

IOC接口

  1. IOC思想是基于IOC容器完成的,IOC容器底层是对象工厂

  2. Spring提供了IOC容器的两种实现方式(两个接口)

    1. BeanFactory: IOC容器的最基本的实现,是Spring内部使用的接口,不提供开发人员使用
    2. ApplicationContext: BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用

    注:BeanFactoryApplicationContext我们在开发的时候都可以用,但值得注意的是如果你使用BeanFactory那么Spring在加载配置文件的时候不会立即创建对象,而是在你要使用的时候才会给你创建,而ApplicationContext则会在加载配置文件的时候就会把被配置的对象进行创建。

  3. ApplicationContext接口的实现类
    ApplicationContext实现类

IOC操作Bean

Bean 管理指的就是两个操作: Spring对象创建Spring对象注入属性
Bean管理操作有两种方式:基于xml配置文件实现基于注解实现

IOC操作Bean(基于xml)

  • 基于xml创建对象
  1. 在Spring配置文件中,使用bean标签,在标签里添加对应的属性,就可以实现对象的创建
  2. bean标签的常见属性:
  3. id属性:该bean的唯一标识
  4. class属性:定义 bean 的类型并使用完全限定的类名
  5. 创建对象时,默认使用无参构造器创建对象
  • 基于xml进行依赖注入
  • DI: 依赖注入,就是注入属性
  • 第一种注入方式,使用set方式进行依赖注入
  1. 使用property标签实现
<bean id="" class="">
   <property name="" value="" />
   <property name="" ref="" />
</bean>

name的值是属性名,value用于对基本数据类型+String的赋值,ref用于对引用对象的赋值,ref的值是bean对象的id
例子:

<bean id="UserDaoImpl" class="com.spring.dao.impl.UserDaoImpl"/>
<bean id="UserSeviceImpl" class="com.spring.service.UserSeviceImpl">
   <property name="name" value="例子"/>
<property name="userDao" ref="UserDaoImpl"/>
</bean>
  1. p命名空间实现
1. xml中加入命名空间
xmlns:p="http://www.springframework.org/schema/p"

<bean id="" class="" p:属性名1="" p:属性名2="" />
例子:
<bean id="UserMapperImpl" class="com.spring.dao.impl.UserMapperImpl" />
<bean id="UserServiceImpl" class="com.spring.service.impl.UserServiceImpl" 
p:userMapper-ref="UserMapperImpl"/>
  • 第二种注入方式,使用有参构造进行依赖注入
    使用constructor-arg标签实现
<bean id="user" class="com.spring.pojo.User">
<constructor-arg name="id" value="12"/>
<constructor-arg name="password" value="123" />
<constructor-arg name="userName" value="张三" />
<constructor-arg name="userCode" value="VTB1233123" />
</bean>
  • 特殊值的依赖注入

  • 空值和特殊符号
    (1) null值:标签null
    (2)属性值中包含特殊符号<![CDATA[属性值]]>

  • Array、List、Map

  • FactoryBean
    Spring有两种Bean:普通类型工厂Bean
    普通bean:再配置文件中定义的bean类型就是返回类型
    工厂bean:在配置文件定义的bean类型可以和返回值类型不一样
    第一步:创建类,让这个类作为工厂bean,实现接口FactoryBean
    第二步:实现接口里面的方法,在实现的方法里面定义bean类型

  • bean的作用域

我们在Spring中定义一个bean时,必须要声明该bean的作用域,默认为singletno,即,单例模式,Spring框架支持六个作用域singletno,prototype、request、session、application、websocket

作用域描述
singleton在Spring IoC容器中仅存在一个Bean实例,Bean以单例方式存在,默认值
prototype每次从容器中调用bean时,都会放回一个新的实例
request将单个bean定义的范围限定为单个HTTP请求的生命周期。也就是说,每个HTTP请求都有一个自己的bean实例,它是在单个bean定义的后
面创建的。仅在可感知网络的Spring ApplicationContext上下文中有效。
session将单个bean定义的范围限定为单个HTTP请求的生命周期。也就是说,每个HTTP请求都有一个自己的bean实例,它是在单个bean定义的后
面创建的。仅在可感知网络的Spring ApplicationContext上下文中有效。
application将单个bean定义的作用域限定为ServletContext的生命周期。仅在可感知网络的Spring ApplicationContext上下文中有效。
websocket将单个bean定义的作用域限定为WebSocket的生命周期。仅在可感知网络的Spring ApplicationContext上下文中有效。
  • Bean的生命周期

生命周期:对象从创建到销毁的过程

Bean的生命周期:

  1. 通过构造器创建Bean实例(无参构造)
  2. 为Bean的属性设置值和对bean引用
  3. 调用bean的初始化方法(需要进行配置初始化的方法)
    1. 定义一个初始化时要执行方法
    2. bean属性:init-method
  4. bean可以使用了(对象获取到)
  5. 当容器关闭时,调用bean的销毁的方法(需要进行配置销毁的方法)
    1. 定义一个初始化时要执行的方法
    2. bean属性:destroy-method

Bean的后置处理器:
1. 定义Bean的后置处理器后,会在bean的初始化前和初始化后会分别执行后置处理器方法
2. 要想创建一个Bean的后置处理器,需要创建一个类,并且这个类要实现接口BeanPostProcess
3. 有后置处理器的Bean的生命周期

1. 通过构造器创建Bean实例(无参构造)
2. 为Bean的属性设置值和对bean引用
-------------------------
3. 后置处理器初始化前的操作
-------------------------
4. 调用bean的初始化方法(需要进行配置初始化的方法)
------------------------- 	
5. 后置处理器初始化后的操作
-------------------------
6. bean可以使用了(对象获取到)
7. 当容器关闭时,调用bean的销毁的方法(需要进行配置销毁的方法)

生命周期例子:

bean.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="com.spring.beanpostproess.pojo.User" 
          init-method="init" destroy-method="destroy">
        <property name="name" value="123"/>
    </bean>
    <bean class="com.spring.beanpostproess.MyBeanPost" />
</beans>

User.java

public class User {
    private String name;
    public User() {
        System.out.println("无参构造器创建Bean");
    }
    public void setName(String name) {
        System.out.println("调用set设置方法设置属性值");
        this.name = name;
    }
    public void init(){
        System.out.println("执行初始化方法");
    }
    public void destroy(){
        System.out.println("执行销毁销毁方法");
    }
}

MyBeanPost.java

public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("before");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("after");
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

IOC操作Bean(基于注解)

  • 自动装配

  • Autowired:根据属性类型进行自动装配

  • Qualifier: 根据属性名称进入注入

  • Resource:既可以根据类型注入,也可以根据名称注入

  • Value:注入普通类型属性

  • 完全注解开发

  • 创建配置类,替代xml配置文件

@Configuration	// 作为配置类,替代xml配置文件
@ComponentScan(basePackages={"扫描包路径"})  // 开启组件扫描
public class SpringConfig{}
  • 加载配置类
ApplicationContext context = 
    new AnnotationConfigApplicationContext(SpringConfig.class);

AOP

AOP(概念)

什么是AOP

  1. 面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各个方面之间的耦合度降低,提高程序的可可从用性,提高了开发的效率
  2. 通俗理解:不通过修改代码的方式,在主干功能里面添加新功能

AOP(底层原理)

AOP底层使用的是动态代理,动态代理分两种情况:

  1. 有接口情况,使用JDK动态代理

创建接口实现类代理对象,增强类的方法

  1. 没有接口情况,使用CGLIB动态代理

创建子类的代理对象,增强类的方法

  1. JDK动态代理简单实现:

  2. 使用JDK动态代理,使用Proxy类里面的方法创建代理对象

调用newProxyInstance方法

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 
返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。  
ClassLoader loader: 代理类的类加载器
Class<?>[] interfaces:代理类实现的接口实现类class文件列表
InvocationHandler h: 调度方法调用的调用处理函数(增强方法类)
  1. 实现代码
// 代理类:Demo.java
public class Demo {
  public static void main(String[] args) {
      Class[] interfaces = {UserDao.class};
      UserDaoImpl userDaoImpl = new UserDaoImpl();
      UserDao userDao = 
          (UserDao) Proxy.newProxyInstance(
          Demo.class.getClassLoader(), 
          interfaces, 
          new UserDaoProxy(userDaoImpl));
      int add = userDao.add(1, 2);
      System.out.println(add);
  }
}

class UserDaoProxy implements InvocationHandler {
  // 被代理的对象
  private Object obj;
  // 通过构造器获取
  public UserDaoProxy(Object obj) {
      this.obj = obj;
  }
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      // 方法之前
      System.out.println("方法执行前" + method.getName() + "  方法参数:" + args);
// 被增强的方法执行
      Object res = method.invoke(obj, args);
      // 方法之后
      System.out.println("方法执行后" + method.getName());
      return res;
  }
}

// 接口:UserDao.java
public interface UserDao {
  int add(int a,int b);
}

// 三系列:UserDaoImpl.java
public class UserDaoImpl implements UserDao {
  public int add(int a, int b){
      return a+b;
  }
}

JdbcTemplate

什么是JdbcTemplate

JdbcTemplate是Spring框架对JDBC进行的封装,使用它可以更方便的对数据库进行操作

事务

什么是事务

事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败

事务四个特性(ACID)

  1. 原子性:操作不可分割,要么都成功,一个失败都失败

  2. 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。

    这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

  3. 隔离性:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的

  4. 持久性:一个事务被提交之后,它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响

事务的实现

事务操作基本流程
  1. 开启事务
  2. 进行业务操作
  3. 没有发生异常,提交事务;出现异常,事务回滚
spring事务管理介绍
  1. 事务一般添加到JavaEE三层架构的Service层中

  2. 在Spring进行事务管理操作

    1. 编程式事务(不常用)
    2. 声明式事务
  3. 声明式事务管理

    1. 基于注解实现(常用)
    2. 基于xml配置文件方式
  4. 在Spring进行声明式事务管理,底层使用AOP原理

  5. Spring事务管理API

    1. 提供一个接口(PlatformTransactionManager),代表事务管理器,这个接口针对不同框架,有不同实现类

事务管理

Spring事务操作(注解声明式事务管理)

Spring事务操作步骤
  1. 在Spring配置文件配置事务管理器

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
  2. 在Spring配置文件,开启事务

    1. 添加命名空间

      xmlns:tx="http://www.springframework.org/schema/tx"
      xsi:schemaLocation="http://www.springframework.org/schema/tx 
      http://www.springframework.org/schema/tx/spring-tx.xsd
      
    2. 开启事务注解

      <tx:annotation-driven transaction-manager="transactionManager" />
      
  3. 在Service类上面(或Service类里面的方法上面)添加事务注解

    1. @Transactional,这个注解可以添加到类上,也可以添加到方法上
    2. 添加到类上,这个类里面的所有的方法都添加事务
    3. 添加到方法上,为这个方法添加事务
    @Service
    @Transactional
    public class UserServiceImpl implements UserService {
        
    }
    
参数配置
参数名描述
propagation事务的传播类型
isolation隔离级别
timeout超时时间
readOnly是否只读
rollbackFor回滚
rollbackForClassName
noRollbackFor不回滚
noRollbackForClassName

propagation: 当一个事务方法被另一个事务方法调用时这个事务如何进行

传播属性描述
REQUIRED如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行
REQUIRED_NEW当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起
SUPPORTS如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中
NOT_SUPPORTS当前的方法不应该运行在事务中,如果有运行的事务,将它挂起
MANDATORY当前的方法必须运行在事务内部,如果没有正在运行的事务,就抛异常
NEVER当前的方法不应该运行在事务内部,如果有正在运行的事务,就抛异常
NESTED如果事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行

isolation: 事务有特性为隔离性,多事务操作之间不会产生影响。如果不考虑隔离性在并发访问数据库时,读取数据时会产生很多问题:

脏读: 读取未提交数据

时间顺序转账事务取款事务
1开始事务
2开始事务
3查询账户余额为2000元
4取款1000元,余额被更改为1000元
5查询账户余额为1000元(产生脏读)
6取款操作发生未知错误,事务回滚,余额变更为2000元
7转入2000元,余额被更改为3000元(脏读的1000+2000)
8提交事务
备注按照正确逻辑,此时账户余额应该为4000元

不可重复读: 前后多次读取,数据内容不一致

时间顺序事务A事务B
1开始事务
2第一次查询,小明的年龄为20岁
3开始事务
4其他操作
5更改小明的年龄为30岁
6提交事务
7第二次查询,小明的年龄为30岁
备注按照正确逻辑,事务A前后两次读取到的数据应该一致

幻读: 前后多次读取,数据总量不一致

时间顺序事务A事务B
1开始事务
2第一次查询,数据总量为100条
3开始事务
4其他操作
5新增100条数据
6提交事务
7第二次查询,数据总量为200条
备注按照正确逻辑,事务A前后两次读取到的数据总量应该一致

隔离性级别: ×(未解决)、√(解决)

隔离级别脏读不可重复读幻读
读未提交(Read uncommitted)×××
读已提交(Read committed)××
可重复读(Repeatable read)(mysql默认)×
可串行化(Serializable)

timeout: 事务必须在一定时间内进行提交,如果规定时间内没有提交,事务就会回滚(默认值-1,一直不超时)

readOnly: 是否只读

  1. 读:查询操作;写:添加、修改,删除操作
  2. readOnly默认值false,表示增删改查都可以
  3. 设置readOnly值为true后,表示只能查询,不能增删改

rollbackFor: 设置出现那些异常进行回滚

noRollbackFor: 设置出现那些异常不进行回滚

xml配置方式实现事务

完全注解开发

Spring5的新功能

整个Spring5框架代码基于JDK8

  • 通过使用泛型等特性提高可读性
  • 对java8提高直接的代码支撑
  • 运行时兼容JDK9
  • Java EE 7API需要Spring相关的模块支持
  • 运行时兼容Java EE8 API
  • 取消的包,类和方法
  • 包 beans.factory.access
  • 包 dbc.support.nativejdbc
  • 从spring-aspects 模块移除了包mock.staicmock,不在提AnnotationDrivenStaticEntityMockingControl支持
  • 许多不建议使用的类和方法在代码库中删除

核心特性

  • 访问Resuouce时提供getFile或和isFile防御式抽象

  • 有效的方法参数访问基于java 8反射增强

  • 在Spring核心接口中增加了声明default方法的支持一贯使用JDK7 Charset和StandardCharsets的增强

  • 兼容JDK9

  • Spring 5.0框架自带了通用的日志封装
    Spring5移除了Log4jConfigListener,官方建议使用Log4j2
    Spring5框架整合Log4j

    1. 导入jar包
    2. 创建log4j.xml
    <?xml version="1.0" encoding="utf-8"?>
    <!-- 日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
    <!-- Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出 -->
    <configuration status="INFO">
        <!-- 先定义所有的appender -->
        <appenders>
            <!-- 控制日志输出的格式 -->
        	<console name="Console" target="SYSTEM_OUT">
            	<PatternLauout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
            </console>
        </appenders>
        <!-- 定义logger,只有定义了logger并引入了appender,appender才会生效 -->
        <!-- root: 用于指定项目的根让着你,如果没有单独指定Logger,则会使用root作为默认的日志输出 -->
        <loggers>
        	<root level="info">
            	<appender-ref ref="Console" />
            </root>
        </loggers>
    </configuration>
    
  • 持续实例化via构造函数(修改了异常处理)

  • Spring 5.0框架自带了通用的日志封装

  • spring-jcl替代了通用的日志,仍然支持可重写

  • 自动检测log4j 2.x, SLF4J, JUL(java.util.Logging)而不是其他的支持

  • 访问Resuouce时提供getFile或和isFile防御式抽象

  • 基于NIO的readableChannel也提供了这个新特性

核心容器

  • 支持候选组件索引(也可以支持环境变量扫描)
  • 支持@Nullable注解
    • @Nullable注解可以使用在属性方法方法参数
    • 使用在属性上面,属性值可以为空
    • 使用在方法上面,方法返回值可以为空
    • 使用在方法参数上面,参数值可以为空
  • 函数式风格GenericApplicationContext/AnnotationConfigApplicationContext
  • 基本支持bean API注册
  • 在接口层面使用CGLIB动态代理的时候,提供事物,缓存,异步注解检测
  • XML配置作用域流式
  • Spring WebMVC
  • 全部的Servlet 3.1 签名支持在Spring-provied Filter实现
  • 在Spring MVC Controller方法里支持Servlet4.0 PushBuilder参数
  • 多个不可变对象的数据绑定(Kotlin/Lombok/@ConstructorPorties)
  • 支持jackson2.9
  • 支持JSON绑定API
  • 支持protobuf3
  • 支持Reactor3.1 Flux和Mono

SpringWebFlux

  • 新的spring-webflux模块,一个基于reactive的spring-webmvc,完全的异步非阻塞,旨在使用enent-loop执行模型和传统的线程池模型。
  • Reactive说明在spring-core比如编码和解码
  • spring-core相关的基础设施,比如Encode 和Decoder可以用来编码和解码数据流;DataBuffer 可以使用java ByteBuffer或者Netty ByteBuf;ReactiveAdapterRegistry可以对相关的库提供传输层支持。
  • 在spring-web包里包含HttpMessageReade和HttpMessageWrite

测试方面的改进

  • 完成了对JUnit 5’s Juptier编程和拓展模块在Spring TestContext框架
  • SpringExtension:是JUnit多个可拓展API的一个实现,提供了对现存Spring TestContext Framework的支持,使用@ExtendWith(SpringExtension.class)注解引用。
  • @SpringJunitConfig:一个复合注解
  • @ExtendWith(SpringExtension.class) 来源于Junit Jupit
  • @ContextConfiguration 来源于Srping TestContext框架
  • @DisabledIf 如果提供的该属性值为true的表达或占位符,信号:注解的测试类或测试方法被禁用
  • 在Spring TestContext框架中支持并行测试
  • 具体细节查看Test 章节 通过SpringRunner在Sring TestContext框架中支持TestNG, Junit5,新的执行之前和之后测试回调。
  • 在testexecutionlistener API和testcontextmanager新beforetestexecution()和aftertestexecution()回调。MockHttpServletRequest新增了getContentAsByteArray()和getContentAsString()方法来访问请求体
  • 如果字符编码被设置为mock请求,在print()和log()方法中可以打印Spring MVC Test的redirectedUrl()和forwardedUrl()方法支持带变量表达式URL模板。
  • XMLUnit 升级到了2.3版本。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学编程的小猫猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值