# spring6 **Repository Path**: meijindeng/spring6 ## Basic Information - **Project Name**: spring6 - **Description**: Spring是一个开源的Java开发框架,它提供了一种全面的解决方案,用于构建企业级应用程序。 自 2004 年 4 月,Spring 1.0 版本正式发布以来,Spring 已经步入到了第 6 个大版本,也就是 Spring 6。本课程采用Spring当前最新发布的正式版本6.0.2。在Spring6中,对于JDK的要求最低为 17+。(17 - 19) - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-08-31 - **Last Updated**: 2023-09-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # spring6 #### 一、介绍 Spring是一个开源的Java开发框架,它提供了一种全面的解决方案,用于构建企业级应用程序。 自 2004 年 4 月,Spring 1.0 版本正式发布以来,Spring 已经步入到了第 6 个大版本,也就是 Spring 6。本课程采用Spring当前最新发布的正式版本6.0.2。在Spring6中,对于JDK的要求最低为 17+。(17 - 19) #### 1.1、Spring 的狭义和广义 在不同的语境中,Spring 所代表的含义是不同的。下面我们就分别从“广义”和“狭义”两个角度,对 Spring 进行介绍。 ##### 1.1.1、广义的 Spring:Spring 技术栈 经过十多年的发展,Spring 已经不再是一个单纯的应用框架,而是逐渐发展成为一个由多个不同子项目(模块)组成的成熟技术,例如 Spring Framework、Spring MVC、SpringBoot、Spring Cloud、Spring Data、Spring Security 等,其中 Spring Framework 是其他子项目的基础。 ##### 1.1.2、狭义的 Spring:Spring Framework 狭义的 Spring 特指 Spring Framework,通常我们将它称为 Spring 框架。 Spring 框架是一个分层的、面向切面的 Java 应用程序的一站式轻量级解决方案,它是 Spring 技术栈的核心和基础,是为了解决企业级应用开发的复杂性而创建的。 Spring 有两个最核心模块: IoC 和 AOP。 IoC:Inverse of Control 的简写,译为“控制反转”,指把创建对象过程交给 Spring 进行管理。 AOP:Aspect Oriented Programming 的简写,译为“面向切面编程”。AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。 #### 1.2、Spring Framework特点 1. 非侵入式:使用 Spring Framework 开发应用程序时,Spring 对应用程序本身的结构影响非常小。对领域模型可以做到零污染;对功能性组件也只需要使用几个简单的注解进行标记,完全不会破坏原有结构,反而能将组件结构进一步简化。这就使得基于 Spring Framework 开发应用程序时结构清晰、简洁优雅。 2. 控制反转:IoC——Inversion of Control,翻转资源获取方向。把自己创建资源、向环境索取资源变成环境将资源准备好,我们享受、资源注入。 3. 面向切面编程:AOP——Aspect Oriented Programming,在不修改源代码的基础上增强代码功能。 4. 容器:Spring IoC 是一个容器,因为它包含并且管理组件对象的生命周期。组件享受到了容器化的管理,替程序员屏蔽了组件创建过程中的大量细节,极大的降低了使用门槛,大幅度提高了开发效率。 5. 组件化:Spring 实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用 XML 和 Java 注解组合这些对象。这使得我们可以基于一个个功能明确、边界清晰的组件有条不紊的搭建超大型复杂应用系统。 6. 一站式:在 IoC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库。而且 Spring 旗下的项目已经覆盖了广泛领域,很多方面的功能性需求可以在 Spring Framework 的基础上全部使用 Spring 来实现。 问题 1:Spring是如何创建对象的呢?原理是什么? 答:解析beans.xml文件,从中获取class属性值,类的全类名。通过反射机制调用无参数构造方法创建对象 问题 2:把创建好的对象存储到一个什么样的数据结构当中了呢? 答:bean对象最终存储在spring容器中,在spring源码底层就是一个map集合,存储bean的map在DefaultListableBeanFactory类中,Spring容器加载到Bean类时 , 会把这个类的描述信息, 以包名加类名的方式存到beanDefinitionMap 中, Map , 其中 String是Key , 默认是类名首字母小写 , BeanDefinition , 存的是类的定义(描述信息) , 我们通常叫BeanDefinition接口为 : bean的定义对象。 #### 1.3、容器:IoC ##### 1.3.1、控制反转(IoC) IoC 是 Inversion of Control 的简写,译为“控制反转”,它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序。 Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系。我们将由 IoC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别。 IoC 容器是 Spring 框架中最重要的核心组件之一,它贯穿了 Spring 从诞生到成长的整个过程。 1. 控制反转是一种思想。 2. 控制反转是为了降低程序耦合度,提高程序扩展力。 3. 控制反转,反转的是什么? 1.将对象的创建权利交出去,交给第三方容器负责。 2.将对象和对象之间关系的维护权交出去,交给第三方容器负责。 4. 控制反转这种思想如何实现呢? 1.DI(Dependency Injection):依赖注入 ##### 1.3.2、依赖注入 DI(Dependency Injection):依赖注入,依赖注入实现了控制反转的思想。 1. 依赖注入:指Spring创建对象的过程中,将对象依赖属性通过配置进行注入; 2. 依赖注入常见的实现方式包括两种: 1.set注入 2.构造注入 所以结论是:IOC 就是一种控制反转的思想, 而 DI 是对IoC的一种具体实现。 Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)。 ##### 1.3.3、IoC容器在Spring的实现 Spring 的 IoC 容器就是 IoC思想的一个落地的产品实现。IoC容器中管理的组件也叫做 bean。在创建 bean 之前,首先需要创建IoC 容器。Spring 提供了IoC 容器的两种实现方式: 1. BeanFactory:这是 IoC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给开发人员使用。 2. ApplicationContext:BeanFactory 的子接口,提供了更多高级特性。面向 Spring 的使用者,几乎所有场合都使用 ApplicationContext 而不是底层的 BeanFactory。 #### 1.4、基于XML管理Bean ##### 1.4.1、获取bean > 位置:spring-2—>bean包—>TestUser测试类 1. 方式一:根据id获取 由于 id 属性指定了 bean 的唯一标识,所以根据 bean 标签的 id 属性可以精确获取到一个组件对象。上个实验中我们使用的就是这种方式。 2. 方式二:根据类型获取 当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个 3. 方式三:根据id和类型 问题 1:如果组件类实现了接口,根据接口类型可以获取 bean 吗? 可以,前提是bean唯一 问题 2:如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型可以获取 bean 吗? 答:不行,因为bean不唯一 结论: 根据类型来获取bean时,在满足bean唯一性的前提下,其实只是看:『对象 instanceof 指定的类型』的返回结果,只要返回的是true就可以认定为和类型匹配,能够获取到。 java中,instanceof运算符用于判断前面的对象是否是后面的类,或其子类、实现类的实例。如果是返回true,否则返回false。也就是说:用instanceof关键字做判断时, instanceof 操作符的左右操作必须有继承或实现关系。 ##### 1.4.2、依赖注入之setter注入 > 位置:spring-2—>di_xml包—>TestBook测试类 ##### 1.4.3、依赖注入之构造器注入 > 位置:spring-2—>di_xml包—>TestBook测试类 ##### 1.4.4、为对象类型属性赋值 > 位置:spring-2—>di_xml包—>TestBook测试类 ##### 1.4.5、为数组类型属性赋值 > 位置:spring-2—>di_xml包—>TestBook测试类 ##### 1.4.6、为集合类型属性赋值 > 位置:spring-2—>di_xml包—>TestBook测试类 ##### 1.4.7、引入外部属性文件 > 位置:spring-2—>TestJdbc测试类 > ##### 1.4.8、bean的作用域 > 位置:spring-2—>scope包—>TestOrders测试类 ##### 1.4.9、bean生命周期 > 位置:spring-2—>cycle包—>TestStudent测试类 ##### 1.4.10、FactoryBean > 位置:spring-2—>factory包—>TestFactoryBean测试类 FactoryBean 是 Spring 提供的一种整合第三方框架的常用机制。和普通 bean 不同,配置一个 FactoryBean 类型的 bean,在获取 bean 的时候得到的并不是 class 属性中配置的这个类的对象,而是 getObject() 方法的返回值。通过这种机制,Spring 可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。 将来整合 mybatis 时,Spring 就是通过 FactoryBean 机制来帮我们创建 SqlSessionFactory 对象的。 ##### 1.4.11、基于 xml 自动装配 > 位置:spring-2—>factory包—>TestFactoryBean测试类 自动装配:根据指定的策略,在 IOC 容器中匹配某一个 bean,自动为指定的 bean 中所依赖的"类"类型或者"接口"类型属性赋值。 #### 1.5、基于注解管理Bean Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean。 1. @Component:该注解用于描述 Spring 中的 Bean,它是个泛化的概念,仅仅表示容器中的一个组件(Bean); 2. @Repository:该注解用于将数据访问层(Dao)的类标识为 Spring 中的 Bean,其功能与@Component相同; 3. @Service:该注解同常作用在业务层(Service),将业务层的类表示为 Spring 中的 Bean,其功能与@Component相同; 4. @Controller:该注解用于控制层(Controller),将控制层的类表示为 Spring 中的 Bean,其功能与@Component相同。 ##### 1.5.1、注解:@Autowired 注入 > 位置:spring-3—>autowired包 单独使用@Autowired注解,**默认根据类型装配【默认为byType】** ```java @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { boolean required() default true; } ``` 源码中有两处需要注意: - 一、注解可以标注在哪里? - 属性 - 构造方法 - 方法 - 形参 - 注解 - 二、该注解有一个 required 属性,默认为 true,表示**注入的时候要求被注入的 Bean 必须是存在的**,如果不存在则报错;如果属性设置为 false,表示**注入的 Bean 存在或者不存在都没关系,存在的话就注入,不存在也不报错**。 ###### 1.5.1.1、场景一:属性注入 根据类型找到对应对象,完成注入。 ```java @Controller public class UserController { //第一种:属性注入 @Autowired private UserService userService; public void add(){ System.out.println("controller add方法执行了。。。"); userService.add(); } } ``` ###### 1.5.1.2、场景二:set 注入 ```java @Controller public class UserController { private UserService userService; //第二种:set 注入 @Autowired public void setUserService(UserService userService) { this.userService = userService; } } ``` ###### 1.5.1.3、场景三:构造方法注入 ```java @Controller public class UserController { private UserService userService; //第三种:构造方法注入 @Autowired public UserController(UserService userService) { this.userService = userService; } } ``` ###### 1.5.1.4、场景四:形参注入 ```java @Controller public class UserController { private UserService userService; //第四种:形参注入 public UserController(@Autowired UserService userService) { this.userService = userService; } } ``` ###### 1.5.1.5、场景五:只有一个有参构造方法,无注解 **当有参数的构造方法只有一个时,@Autowired 注解可以省略。** 说明:有多个构造方法时呢,可以测试(再添加一个无参构造函数),测试报错 ```java @Controller public class UserController { private UserService userService; //第五种:只有一个有参构造方法,无注解 public UserController(UserService userService) { this.userService = userService; } //多个构造方法,测试报错 /*public UserController() { }*/ } ``` ###### 1.5.1.6、场景六:@Autowired 和 @Qualifier 联合使用 当一个接口有多个实现类时,根据类型注入的话程序不知道注入哪个,导致出现如下错误: > Error creating bean with name 'userServiceImpl': Unsatisfied dependency expressed through field 'userDao': No qualifying bean of type 'com.meijin.spring6.autowired.dao.UserDao' available: expected single matching bean but found 2: userDaoImpl,userRedisDaoImpl 此时,可以根据@Qualifier(value = "根据名称注入,类首字母小写")注解来判断使用哪一个实现类,“value =” 可省略。 ```java @Service public class UserServiceImpl implements UserService { @Autowired @Qualifier(value = "userRedisDaoImpl") private UserDao userDao; @Override public void add() { System.out.println("service add方法执行了。。。"); userDao.add(); } } ``` ##### 1.5.2、注解:@Resource 注入 @Resource 注解也可以完成属性注入,那它和 @Autowired 有什么区别呢? - @Resource 是 JDK 扩展包中的,也就是说属于 JDK 的一部分。所以该注解是标准注解,更加具有通用性(JSR-250标准中制定的注解类型,JSR 是 Java 规范提案); - @Autowired 是 Spring 框架自己的; - **@Resource 默认根据名称(byName)装配,未指定 name 时,使用属性名作为 name。通过 name 找不到的话会自动启动通过类型(byType)装配;** - **@Autowired 默认根据类型(byType)装配,如果想要根据名称装配,需要配合@Qualifier 联合使用;** - @Resource 用在属性、setter 方法上; - @Autowired 用在属性、setter 方法、构造方法、构造方法参数上。 注意:@Resource 注解属于 JDK 扩展包,所以不在 JDK 中,需要额外引入以下依赖【**jdk8不需要,高于 jdk11 或者低于 jdk8 需要 **】: ```xml jakarta.annotation jakarta.annotation-api 2.1.1 ``` ###### 1.5.2.1、场景一:根据 name 注入 ###### 1.5.2.2、场景二:name 未知注入 ###### 1.5.2.3、场景三:其他情况 ##### 1.5.3、Spring 全注解开发