写点什么

Spring 知识点讲解

作者:Geek_43263f
  • 2022 年 9 月 07 日
    河南
  • 本文字数:8822 字

    阅读完需:约 29 分钟

Spring知识点讲解

目录


Spring


1.1 简介


1.2 优点


1.3 组成


1.4 拓展


2.IOC 理论推导


3.HelloSpring


4.IOC 创建对象的方式


5.Spring 配置


5.1 别名


5.2 Bean 的配置


5.3 import 导入


6.依赖注入


6.1 构造器注入


6.2set 方法注入【重点】


6.3 拓展方法注入


6.4bean 作用域


7.bean 的自动装配


7.1 测试


7.2ByName 自动装配


7.3ByType 自动装配


7.4 使用注解实现自动装配


8.使用注解开发


9.使用 java 的放手配置 Spring


10.代理模式


10.1 静态代理


10.2 动态代理


11.AOP


11.1 什么是 AOP?


11.2 AOP 在 Spring 中的作用


11.3 使用 Spring 实现 AOP


12.整合 Mybatis


12.1 回忆 mybatis


13.声明式事务


1.回顾事务


13.2 Spring 中的事务管理


Spring1.1 简介 Spring:春天 给软件行业带来了春天


2002,首次推出了 Spring 框架的雏形:interface21 框架


Spring 框架即是以 interface21 框架为基础经过重新设计,并不断丰富其内涵,于 2004 年 3 月 24 日发布了 1.0 正式版


Rod Johnson Spring Framework 创始人,著名作者。 Rod 在悉尼大学不仅获得了计算机学位,同时还获得了音乐学位。更令人吃惊的是在回到软件开发领域之前,他还获得了音乐学的博士学位。 有着相当丰富的 C/C++技术背景的 Rod 早在 1996 年就开始了对 Java 服务器端技术的研究


Spring 理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!


SSH :Struct2 + Spring + Hibernate


SSM:SpringMVC + SPring +Mybatis


官网:Spring | Home


官方下载地址:JFrog


GitHub:GitHub - spring-projects/spring-framework: Spring Framework


Spring 核心技术地址:Core Technologies


spring 是一个轻量级的,非入侵式的框架


控制反转(IOC),面向切面编程(AOP)


支持事务的处理对框架整合的支持


总结一句话:Spring 就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架


1.3 组成 1.4 拓展在 Spring 的官网有这个介绍:现代化的 java 开发,说白就是基于 Spring 的开发


Spring Boot


一个快速开发的脚手架


基于 SpringBoot 可以快速的开发单个微服务


约定大于配置


Spring Cloud


SpringCloud 是基于 SpringBoot 实现的


因为现在大部分公司都在使用 SpringBoot 进行快速开发,学习 SpringBoot 的前提,需要完全掌握 Spring 及 SpringMVC,承上启下的作用


弊端:发展了太久,违背了原来的理念,配置十分繁琐,人称:配置地狱


2.IOC 理论推导 UserDao 接口


UserDaoImpl 实现类


UserService 业务接口


UserServiceImpl 业务实现类


在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码,如果程序代码量十分大,修改一次的成本十分大


我们使用一个 set 接口实现,已经发生了革命性的变化


private UserDao userDao = new UserOracleImpl();​// 利用 set 进行动态值的注入 public UserDao getUserDao() {return userDao;}​public void setUserDao(UserDao userDao) {this.userDao = userDao;}之前,程序是主动创建对象,控制权在程序员手上


使用 set 注入后,程序不再具有主动性,而是变成了被动的接收对象


这种思想,从本质上解决了问题,我们程序员不用再去管理对象的创建了,系统的耦合性大大降低,可以更加专注的在业务上实现,这是 ioc 得原型


IOC 本质 控制反转 IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现 IoC 的一种方法,也有人认为 DI 只是 IoC 的另一种说法。没有 IoC 的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。


采用 XML 方式配置 Bean 的时候,Bean 的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean 的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。 控制反转是一种通过描述(XML 或注解)并通过第三方去生产或获取特定对象的方式。在 Spring 中实现控制反转的是 IoC 容器,其实现方法是依赖注入(Dependency Injection,DI)。


3.HelloSpring1.创建一个 maven 项目,编写实体类


public class Hello { private String str;


public String getStr() {return str;}​public void setStr(String str) {this.str = str;}​@Overridepublic String toString() {return "Hello{" +"str='" + str + ''' +'}';}}2.编写 xml 配置文件


3.测试


public class MyTest {public static void main(String[] args) {//获取 Spring 的上下文对象!ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");​//我们的对象现在都在 Spring 中的管理了,我们需要使用,直接去里面取出来就可以!Hello hello = (Hello) context.getBean("hello");System.out.println(hello.toString());}}​思考问题?


Hello 对象是谁创建的? Hello 对象是由 Spring 创建的。 Hello 对象的属性是怎么设置的? Hello 对象的属性是由 Spring 容器设置的。 这个过程就叫控制反转:


控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用 Spring 后,对象是由 Spring 来创建的。


反转:程序本身不创建对象,而变成被动的接收对象。


依赖注入:就是利用 set 方法来进行注入的。


IOC 是一种编程思想,由主动的编程变成被动的接收。


可以通过 new ClassPathXmlApplicationContext 去浏览一下底层源码。


OK,到了现在,我们彻底不用在程序中去改动了,要实现不同的操作,只需要在 xml 配置文件中进行修改,所谓的 IOC,一句话搞定:对象由 Spring 来创建,管理,装配!


4.IOC 创建对象的方式 1.使用无参构造创建对象,默认


2.假设我们要使用有参构造创建对象


下标赋值


<bean id="user" class="com.he.pojo.User"><constructor-arg type="java.lang.String" value="小饼干"/></bean>3.参数名


假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册在不同的 bean 中,我们可以利用 import 将所有人的 beans.xml 合并成一个总的


张三


李四


王五


aplicationContext.xml


<import resource="beans.xml"/><import resource="beans2.xml"/><import resource="beans3.xml"/>
复制代码


使用的时候,直接使用总的配置就可以了


6.依赖注入 6.1 构造器注入前面已经讲过啦


6.2set 方法注入【重点】依赖注入:Set 注入


依赖:bean 对象的创建依赖容器


注入:bean 对象中的所有属性,由容器注入


【环境搭建】


复杂类型


private String address;​public String getAddress() {return address;}​public void setAddress(String address) {this.address = address;}真实测试对象


private String name;private Address address;private String[] books;private List<String> hobbys;private Map<String,String> card;private Set<String> games;private String wife;private Properties info;3.beans.xml


public class MyTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");Student student = (Student) context.getBean("student");System.out.println(student.getAddress());}}完善注册信息


6.3 拓展方法注入我们可以通过 p 命名空间何 c 命名空间进行注入


官方解释:


@Testpublic void test2(){ApplicationContext context = new ClassPathXmlApplicationContext("userbean.xml");User user = context.getBean("user2", User.class);System.out.println(user);}注意点:


p 命名空间何 c 命名空间不能直接使用,需要导入 xml 约束


xmlns:p="http://www.springframework.org/schema/p"xmlns:c="http://www.springframework.org/schema/c"6.4bean 作用域 1.单例模式(Spring 默认机制)


<bean id="user2" class="com.he.pojo.User" c:name="小何" c:age="18" scope="singleton"/>2.原型模式:每次从容器中 get 的时候,都会产生新对象


<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>3.其余的 request session application 这些个只能在 web 开发中使用到


7.bean 的自动装配自动装配是 Spring 满足 bean 依赖的一种方式


Spring 会在上下文中自动寻找,并自动给 bean 装配属性


在 Spring 中有三种配置的方式


在 xml 中显示的配置


在 java 中显示配置


隐式的自动装配 bean【重要】


7.1 测试 1.搭建环境:一个人有两个宠物


byname 的时候,需要保证所有的 id 唯一,并且这个 bean 需要和自动注入的属性的 set 方法的值一致


bytype 的时候,需要保证所有的 class 唯一,并且这个 bean 需要和自动注入的属性的类型一致


7.4 使用注解实现自动装配 jdk1.5 支持的注解,Spring2.5 就支持注解了


基于注释的配置的引入提出了一个问题,即这种方法是否比 XML“更好”。简短的回答是“视情况而定”。


要使用注解须知:


导入约束 context 约束


配置注解的支持 context:annotation-config/


<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd">​context:annotation-config/​</beans>@Autowired


直接在类上使用即可,也可以在 set 方法上使用


使用 Autowired 我们可以不用编写 set 方法了,前提是你这个自动装配的属性在 IOC(Spring)容器中存在,且符合名字 byname


科普:


@Nullable 字段标注了这个注解,说明这个字段可以为 nullboolean required() default true;测试代码:


// 如果显示定义了 Autowired 的 required 的属性为 false,说明这个对象可以为 null,否则不允许为空 @Autowired(required = false)private Cat cat;@Autowiredprivate Dog dog;private String name;如果 @Autowired 自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用 @Qualifier(value = “xxx”)去配置 @Autowired 的使用,指定一个唯一的 bean 对象注入!


@Autowired@Qualifier(value = "cat1")private Cat cat;@Autowired@Qualifier(value = "dog1")private Dog dog;@Resource 注解


@Resource(name = "cat1")private Cat cat;@Resourceprivate Dog dog;小结:


@Resource 何 @Autowired 的区别


都是用来自动装配的,都可以放在属性字段上


@Autowired 通过 byType 的方式实现,而且必须要求这个对象存在【常用】


@Autowired 通过 byType 的方式实现,,如果找不到这个名字,则通过 byType 的方式实现,如果两个都找不到的情况下,则报错【常用】


执行顺序不同:@Autowired 通过 byType 的方式实现,@Autowired 通过 byType 的方式实现


8.使用注解开发在 Spring4 之后,要使用注解开发,必须保证 aop 的包导入了


使用注解需要导入 context 的约束,增加注解的支持


<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd">​context:annotation-config/​</beans>bean


属性如何注入


//@Component 组件 public class User {​public String name ;// 相当于<property name="name" value="牛牛"/>@Value("牛牛")public void setName(String name) {this.name = name;}}衍生的注解


@Component 有几个衍生的注解,我们在 web 开发中,会按照 mvc 三层架构分层


dao【@Repository】


service【@Service】


controller【@Controller】


自动装配置


  • @Autowired :自动装配通过类型,名字如果 @Autowired 不能唯一自动装配上属性,则需要通过 @Qualifier(value = “xxx”)

  • @Nullable : 字段标注了这个注解,说明这个字段可以为 null

  • @Resource : 自动装配通过名字,类型作用域


@Scope("singleton")@Component //等价于<bean id="user" class="com.he.pojo.User"/>//@Component 组件 public class User {​public String name ;// 相当于<property name="name" value="牛牛"/>@Value("牛牛")public void setName(String name) {this.name = name;}}小结


xml 与注解:


xml 更加万能,适用于任何场合,维护简单方便


注解 不是自己的类使用不了,维护相对复杂


xml 与注解最佳实践:


xml 用来管理 bean


注解只负责完成属性的注入


我们在使用过程中,只需要注意一个问题,必须要注解生效,就需要开启注解的支持


context:annotation-config/9.使用 java 的放手配置 Spring@Configuration//这个也会被 spring 容器托管,注册到容器中,因为它本来就是 @Component,@Configuration 这里代表一个配置类,就和我们之前看的 beans.xml 一样 @ComponentScan("com.he.pojo")@Import(MyConfig2.class)public class MyConfig {​// 注册一个 bean,就相当于我们写的一个 bean 标签// 这个方法的名字,就相当于 bean 中的 id 属性// 这个方法的返回值,就相当于 bean 中的 class 属性 @Beanpublic User getUser(){​return new User();//就是要返回要注入到 bean 的对象}​}


import com.he.config.MyConfig;import com.he.pojo.User;import org.springframework.context.ApplicationContext;import org.springframework.context.annotation.AnnotationConfigApplicationContext;​public class MyTest {public static void main(String[] args) {// 如果完全使用了配置类的方式去做,我们就只能通过 AnnotationConfig 上下文来获取容器,通过配置类的 class 对象加载 ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);User getUser = (User) context.getBean("user");System.out.println(getUser.getName());}}package com.he.config;​import com.he.pojo.User;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Import;import org.springframework.stereotype.Component;​@Configuration//这个也会被 spring 容器托管,注册到容器中,因为它本来就是 @Component,@Configuration 这里代表一个配置类,就和我们之前看的 beans.xml 一样 @ComponentScan("com.he.pojo")@Import(MyConfig2.class)public class MyConfig {​// 注册一个 bean,就相当于我们写的一个 bean 标签// 这个方法的名字,就相当于 bean 中的 id 属性// 这个方法的返回值,就相当于 bean 中的 class 属性 @Beanpublic User getUser(){​return new User();//就是要返回要注入到 bean 的对象}​}


package com.he.pojo;​import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Component;​​//这里这个注解的意思,就是说这个被 spring 接管了,注册到了容器中 @Componentpublic class User {private String name;​public String getName() {return name;}​@Value("大哈哈")//属性注入值 public void setName(String name) {this.name = name;}​@Overridepublic String toString() {return "User{" +"name='" + name + ''' +'}';}}


这种纯 java 的配置方式,在 springBoot 中随处可见


10.代理模式为什么要学代理模式?因为这是 springAOP 的底层 【springAOP 和 SpringMVC】


代理模式的分类:


静态代理


动态代理


10.1 静态代理角色分析:


抽象角色:一般会使用接口或者抽象类来解决


真实角色:被代理的角色


代理角色:代理真正角色,代理真实角色后,我们一般会做一些附属操作


客户:访问代理对象的人


代码步骤


接口


//租房 public interface Rent {public void rent();​}真实角色


//房东 public class Host implements Rent{​public void rent() {System.out.println("房东要出租房子");}}代理角色


public class Proxy implements Rent{private Host host;​public Proxy() {}​public Proxy(Host host) {this.host = host;}​public void rent() {seeHouse();host.rent();hetong();fare();}​// 看房 public void seeHouse(){System.out.println("中介带你看房");}​// 签租赁合同 public void hetong(){System.out.println("签租赁合同");}​// 收中介费 public void fare(){System.out.println("收中介费");}}


客户端访问角色


public class Client{public static void main(String[] args) {// 房东要租房子 Host host = new Host();// 代理,中介要帮房东租房子,但是呢,代理角色一般会有一些附属操作 Proxy proxy = new Proxy(host);// 你不用找房东,直接找中介租房即可 proxy.rent();}}代理模式的好处:


可以使真实角色的操作的操作更加纯粹,不用去关注一些公共的业务


公共的也就交给代理角色,实现了业务的分工


公共业务发生扩展的时候,方便集中管理


缺点:


一个真实角色就会产生一个代理角色,代码量会翻倍,开发效率会变低


10.2 动态代理动态代理和静态代理一样


动态代理的代理类是动态生成的,不是我们直接写好的


动态代理分为两大类:基于接口的的动态代理,基于类的动态代理


基于接口---JDK 动态代理【我们在这里使用】


基于类:cglib


java 字节码实现:javasist


需要了解两个类:Proxy:代理 InvocationHandler:调用处理程序


InvocationHandler


动态代理的好处:


可以使真实角色的操作更加纯粹!不用去关注一些公共的业务


公共角色就交给代理角色!实现了业务的分工!


公共业务发生扩展的时候,方便集中管理!


一个动态代理类代理的是一个接口,一般就是对应的一类业务


一个动态代理类可以代理多个类,只要是实现了同一个接口即可!


11.AOP11.1 什么是 AOP?AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续,是软件开发中的一个热点,也是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。


11.2 AOP 在 Spring 中的作用提供声明式事务;允许用户自定义切面


横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等… 切面(ASPECT):横切关注点被模块化的特殊对象。即,它是一个类。 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。 目标(Target):被通知对象。 代理(Proxy):向目标对象应用通知之后创建的对象。 切入点(PointCut):切面通知执行的“地点”的定义。 连接点(JointPoint):与切入点匹配的执行点。


11.3 使用 Spring 实现 AOP【重点】 使用 AOP 注入,需要导入一个依赖包


方式二:自定义来实现 AOP【主要是切面定义】


方式三:使用注解实现


12.整合 Mybatis 步骤:


导入相关 jar 包


junit


mybatis


mysql 数据库


spring 相关的


aop 注入


mybatis-spring[new]


编写配置文件


测试


12.1 回忆 mybatis 编写实体类


编写核心配置文件


编写接口


编写 Mapper.xml


测试


13.声明式事务 1.回顾事务把一组业务当成一个业务来做,要么都成功,要么都失败


事务在项目开发中,十分的重要,涉及到数据的一致性问题,不能马虎


确保完整性和一致性


事务 ACID 原则:


原子性(atomicity) 事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用。


一致性(consistency) 一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中。


隔离性(isolation) 可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。


持久性(durability) 事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中。


13.2 Spring 中的事务管理 Spring 在不同的事务管理 API 之上定义了一个抽象层,使得开发人员不必了解底层的事务管理 API 就可以使用 Spring 的事务管理机制。Spring 支持编程式事务管理和声明式的事务管理。


编程式事务管理


将事务管理代码嵌到业务方法中来控制事务的提交和回滚 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码 声明式事务管理


一般情况下比编程式事务好用。 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。 将事务管理作为横切关注点,通过 aop 方法模块化。Spring 中通过 Spring AOP 框架支持声明式事务管理。


spring 事务传播特性: 事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring 支持 7 种事务传播行为:


propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。


propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。


propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。


propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。


propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。


propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。


propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 propagation_required 类似的操作。


Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。


为什么需要事务?


如果不配置事务,可能存在数据提交不一致的情况;


如果我们不在 Spring 中去配置声明式事务,我们就需要在代码中手动配置事务!


事务在项目的开发中十分重要,涉及到数据的一致性和完整性问题,不容马虎!

用户头像

Geek_43263f

关注

还未添加个人签名 2022.09.01 加入

还未添加个人简介

评论

发布
暂无评论
Spring知识点讲解_后端_Geek_43263f_InfoQ写作社区