ToB企服应用市场:ToB评测及商务社交产业平台

标题: (史上最全的)Spring6框架学习教程 [打印本页]

作者: 张国伟    时间: 2024-7-29 09:43
标题: (史上最全的)Spring6框架学习教程
一、什么是Spring

1.javaWeb框架发展史


1、Servlet+JSP+JavaBean(跳转页面、业务逻辑判断、数据库查询)

2、MVC三层架构(M Model =pojo(User)V-view(USP)C-(controller-servlet))
(
web-跳转页面
service-业务逻辑判断   new UserService0;
dao-数据库查询 new UserDao();
)

3、使用EJB进行应用的开发,但是EJB是重量级框架(在使用的时间,过多的接口和依赖,侵入性强),在使用上比较麻烦 UserService imp extends

4、Struts1/Struts2+Hibernate+Spring
Spring
(
web-跳转页面 Struts
service-业务逻辑判断
dao-数据库查询Hibernate
)--------SSH
5、SpringMVC+Mybatis+Spring
(
web-跳转页面 SpringMVC(出现BUG,使用毕竟麻烦)
service-业务逻辑判断
dao-数据库查询 myBatis
)-------SSM
6、SpringBoot开发,约定大于配置SSM搭建架构需要大量XML配置文件
7、mvvm架构
Model(模子):负责处置惩罚应用程序的数据逻辑,比如数据库读写等数据源的操纵。
View(视图):负责表现数据(即模子层的数据)而且吸收用户操纵界面的界面。
ViewModel(视图模子):作为Model和View之间的桥梁,从Model层获取数据后,处置惩罚并返回给View层表现。ViewModel 还负责处置惩罚View层的用户界面操纵,将相关事件转发到Model层。
2.Spring框架简介

Spring框架英文全称Spring framework,是由Spring团队研发的模块化、轻量级开源框架。其告急目标 是为了简化项目开发。在项目开发中,可以说没有刻意使用Spring,却处处有着Spring存在,用官网对Spring框架的先容:Spring框架核心功能包罗依赖注入、事务管理、Web应用、数据访问、消息发送等等。

Spring框架的计划理念基于以下核心原则:
轻量级计划:
   轻量级计划是Spring框架的主要原则之一。通过采用轻量级的计划,Spring能够在应用程序开发中提供高效、简朴的办理方案。相比于其他重型框架,Spring注重简洁性,使得开发者能够更专注于业务逻辑的实现,而不必被繁琐的框架细节所困扰。
  非侵入性的计划:
   Spring框架夸大非侵入性,这意味着开发者不需要修改已有的Java类来适应框架,从而保持了代码的整洁性和可维护性。非侵入性计划的上风在于,开发者可以更灵活地选择使用和配置框架的功能,而不会影响到已有的代码结构。
  3.Spring loC/Dl 详解

3.1、IoC/DI简介

 因为loC/Dl是 Spring Framework的底子。Spring Framework 其他所有功能都是在loC/DI 底子上 研发的。
loc: Inversion of Control控制反转
DlependencyInjection 依赖注入
   控制(对象创建权利)被反转:
之前:由程序员控制对象创建
UserService(new UserDao())-------->UserDao ;强耦合,再小的代码变更都会引起BUG的大概性之后:依赖Spring注入(DI)
Spring(newUserService(); new UserDao();)如果需要用到Spring管理的对象,需要依赖Spring注入(DI)
  下图是没有使用IoC/DI前和使用了之后的对比图 
 

 3.2、IoC/DI的优缺点

优点:
     缺点:
     3.3、IoC/DI在项目中的应用场景

Java EE企业应用开发
IoC和DI是解耦组件之间复杂关系的利器。Spring IoC模块就是IoC模式的一种实现,通过依赖注入和AOP切面加强了为JavaBean如许的POJO对象赋予事务管理、生命周期管理等基本功能。
EJB模式
在EJB模式中,应用开发人员需要编写EJB组件,满意EJB容器的规范,才能运行在EJB容器中。Spring通过IoC提供了一个基本的JavaBean容器,管理依赖关系,降低了应用开发对传统J2EE技术规范的依赖。
Web应用程序
在Web应用程序中,控制器(Controller)和视图(View)之间的依赖关系可以通过DI来管理。如许可以降低代码的耦合度,提高可维护性和可扩展性。
服务层
在服务层中,服务类之间也可以通过DI来传递依赖对象。这种方式使得组件可以独立于其他组件进行开发和测试,提高了开发服从和代码质量。
数据访问层
在数据访问层中,DAO(Data Access Object)对象也可以通过DI来注入数据库毗连信息。这种方式简化了代码的配置,使得依赖关系管理更加灵活和可维护。
二、基于Springboot快速启动Spring


点击下一步就可以创建一个SpringBoot项目而且Springboot项目我们也可以从下面图片看到SpringBoot中是依赖了Spring的。

三、SpringIoc核心容器

1.什么是Bean

1.1 Bean的简述

 Bean 是由Spring容器创建并管理的对象实例。Spring通过依赖注入(DI)和控制反转(IoC)机制管理这些对象的生命周期和依赖关系。
1.2 如何配置Bean

1.3 实例化Bean

1.3.1 使用默认构造函数

这是最常见的方式,Spring容器会调用Bean类的默认无参构造函数来创建实例。
  1. @Component
  2. public class MyBean {
  3.     public MyBean() {
  4.         // 构造函数逻辑
  5.     }
  6. }
复制代码
1.3.2 使用实例工厂方法实例化--@Bean

        可以自由的选择构造函数进行实例化

1.3.3 使用工厂类

        通过实现BeanFactory接口或使用FactoryBean接口来创建Bean实例。这种方式提供了更高的灵活性,答应你控制Bean的创建和初始化过程。
  1. public class MyBeanFactory implements FactoryBean<MyBean> {
  2.     public MyBean getObject() throws Exception {
  3.         return new MyBean();
  4.     }
  5.     public Class<MyBean> getObjectType() {
  6.         return MyBean.class;
  7.     }
  8. }
复制代码

2.依赖注入

2.1 @Autowired注解

 要实现自动装配一定要用@Autowired
@Autowired特性
@Autowired可以写在构造函数、方法、字段、参数
            2.参数:
        如果想设置构造函数上面的参数为不是必须注入:单独去设置
          @Autowired(required = false)
          @Autowired(value = "specificBean")
  2.2 @Inject和@Resource

 @Inject和@Resource
都是由JDK官方提供的。
Idea为什么不建议在字段上面使用@autowired
@Inject
不能设置required=false属性
  1. <dependency>
  2.     <groupId>jakarta.inject</groupId>
  3.     <artifactId>jakarta.inject-api</artifactId>
  4.     <version>2.0.1</version>
  5. </dependency>
复制代码
@Resource
会先根据名字找,再根据类型找 
2.3 @Value

接受前端哀求参数---pojo , 把数据库查询到的数据---pojo
user{ name ,age ..}

1. 直接值(基本类型,String等)
  1.   @Value("ltx")
  2.     private String name;
  3.     @Value("18")
  4.     private Integer age;
复制代码
2.对外部属性(SpringBoot配置文件)文件的引用 
  1. @Component
  2. public class MovieRecommender {
  3.     private final String catalog;
  4.     public MovieRecommender(@Value("${catalog.name}") String catalog) {
  5.         this.catalog = catalog;
  6.     }
  7. }
复制代码
3.默认值
  1. @Component
  2. public class MovieRecommender {
  3.     private final String catalog;
  4.     public MovieRecommender(@Value("${catalog.name:defaultCatalog}") String catalog) {
  5.         this.catalog = catalog;
  6.     }
  7. }
复制代码

3.自动注入次序

3.1  @Order改变自动注入次序

 用于改变自动装配时:如果一个类型, 有多个bean, 可以List来承接装备的类型。 在List里面的bean可以通过@Order来改变。
  1. @Component
  2. //@Order(9)
  3. class A implements I {
  4.     public A() {
  5.         System.out.println("A");
  6.     }
  7. }
  8. @Component
  9. //@Order(0)
  10. public class B implements I{
  11.     public B() {
  12.         System.out.println("B");
  13.     }
  14. }
  15. @SpringBootTest
  16. public class TestOrder {
  17.     @Test
  18.     public void test(@Autowired List<I> i){
  19.         System.out.println(i);
  20.         // 输出的A 在前面B在后面
  21.     }
  22. }
复制代码
  1. @Component
  2. @Order(9)
  3. class A implements I {
  4.     public A() {
  5.         System.out.println("A");
  6.     }
  7. }
  8. @Component
  9. @Order(0)
  10. public class B implements I{
  11.     public B() {
  12.         System.out.println("B");
  13.     }
  14. }
  15. @SpringBootTest
  16. public class TestOrder {
  17.     @Test
  18.     public void test(@Autowired List<I> i){
  19.         System.out.println(i);
  20.         
  21.         // 输出的B 在前面A在后面
  22.     }
  23. }
复制代码
 
3.2 @DependsOn改变Bean创建次序

 Bean创建: (@Componet class A --b---> 容器加载 new ApplicationContext()------>
new A(); DI ... ; )


new A () 负载数据库查询
new B()数据库毗连
  1. @DependsOn("d")
  2. public class C {
  3.     public C() {
  4.         System.out.println("C");
  5.     }
  6. }
复制代码
4.懒加载bean

懒加载作用:
默认的bean会在启动的时间就会创建, 如果说某些Bean非常大, 如果在启动的时间就创建就会影响启动速率, 就可以把那些大的Bean设置成懒加载, 如许可以优化启动速率
懒加载Bean创建: (@Componet class A --b---> 容器加载 new ApplicationContext()------> )
用到的时间才会创建(new A(); DI ... ; ):

SpringBoot将所有的bean都配置为懒加载
  1. spring.main.lazy-initialization=true
复制代码
5.@Scope作用域


默认Bean单例(只会new 一次,不管@autowired多少次,只会创建一次)
利益: 节省内存空间(有线程安全风险)
多例Bean(只会new 一次,不管@autowired多少次,只会创建一次)
利益: 节省内存空间(有线程安全风险)

Bean 是单例的,会不会有线程安全题目?
   线程安全题目: 多线程并发的情况下, 同时对同一个共享资源(Bean)进行读写,就出现线程不安全,题目:(脏读、数据串改)
  会不会有线程安全题目: 会!
但是! 只要不在单例bean中声明一些共享的类成员变量(共享资源),而且不对共享资源进行读写, 也不会出现线程安全题目, 所以基本上bean就会使用默认的单例(节省内存开销)。
   单例
  1. @Scope("singleton")
  2. @Component
  3. public class SingletonBean {
  4.     // ...
  5. }
复制代码
原型
  1. @Scope("prototype")
  2. @Component
  3. public class PrototypeBean {
  4.     // ...
  5. }
复制代码
6.循环依赖

new applicationContext(); ----> new BeanA(); ——>剖析@autowired----->去容器中获取BeanB(容器容器中没有B,创建B)----> ----> new BeanB(); ——>剖析@autowired----->去容器中获取BeanA(容器容器中没有A,创建A)---->循环执行......

题目的根本Bean要经过依赖注入完(剖析@autowired之后)后才会放到spring容器

办理
1.在配置文件中放开循环依赖的限制
  1. # 放开循环依赖的限制
  2. #spring.main.allow-circular-references=true
复制代码
2.代码计划层面:
        a. 把依赖的方法, 直接写在本类中,断绝其中一方依赖关系
        b. 添加一个中间类, 中间类去依赖A、B, 然后让中间类去组织他们的依赖方法。
3.耽误注入
        a.添加需要依赖的构造函数参数
        b.添加@Lazy注解
  1. @Lazy
  2. public BeanA(BeanB beanb) {
  3.     this.beanb = beanb;
  4. }
  5. @Lazy
  6. public Bean(BeanA beana) {
  7.     this.beana = beana;
  8. }
复制代码
四、SpringAOP面相切面编程

 AOP:Aspect Oriented Programming 面向切面编程 编程头脑
4.1 为什么要用到AOP

所有业务功能都已经实现,但是末了我想在所有的功能里面加一个公共的功能,(记录所有的哀求的用时), 使用AOP, 切面(需要加强的公共的、跟业务没有关系的公共代码)。可以在不改变原有业务代码的底子上进行了加强。
如安在Spring中创建一个所谓切面?
切面里面的代码怎么运行在业务方法(之前、之后)

4.2 AOP快速上手

第一步:引入pom.xml依赖
  1.         <dependency>
  2.             <groupId>org.springframework.boot</groupId>
  3.             <artifactId>spring-boot-starter-aop</artifactId>
  4.         </dependency>
复制代码
 通过下面的图片我们可以看到AOP包中实在另有aspect,aspect是一个成熟的AOP框架
 
第二步:编写业务代码
  1. package com.ltx.springtest.service;
  2. import org.springframework.stereotype.Service;
  3. @Service
  4. public class UserService {
  5.     //添加用户
  6.     public void addUser(){
  7.         System.out.println("添加用户");
  8.     }
  9.     //删除用户
  10.     public void deleteUser(){
  11.         System.out.println("删除用户");
  12.     }
  13.     //修改用户
  14.     public void updateUser(){
  15.         System.out.println("修改用户");
  16.     }
  17. }
复制代码
第三步:编写aop切面类
之前说过AOP就是面向切面编程, OK大家现在可以直观的看到切面了,我们现在就是要面向这个切面类来编程,加强业务方法,记录日志:
  1. package com.ltx.springtest;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. import org.aspectj.lang.annotation.Around;
  4. import org.aspectj.lang.annotation.Aspect;
  5. import org.springframework.stereotype.Component;
  6. @Aspect
  7. @Component
  8. public class LogAspect {
  9.     /**
  10.      * 切面环绕通知,针对UserService接口的所有方法执行进行监控。
  11.      * 使用 ProceedingJoinPoint 参数来获取方法信息并控制方法的执行。
  12.      * 该通知将在方法执行前、执行后以及发生异常时打印日志信息。
  13.      *
  14.      * @param proceedingJoinPoint AOP联盟提供的 ProceedingJoinPoint 类型的参数,用于获取方法信息和继续方法的执行。
  15.      * @return 返回方法的执行结果。
  16.      * @throws Throwable 如果方法执行过程中抛出异常,则重新抛出异常。
  17.      */
  18.     @Around("execution(* com.ltx.springtest.service.UserService.*(..))")
  19.     public Object before(ProceedingJoinPoint proceedingJoinPoint){
  20.         System.out.println("方法进入");
  21.         Object proceed=null;
  22.         try {
  23.             proceed = proceedingJoinPoint.proceed();
  24.         } catch (Throwable e) {
  25.             System.out.println("方法异常");
  26.             throw new RuntimeException(e);
  27.         }
  28.         finally {
  29.             System.out.println("方法执行完毕");
  30.         }
  31.         System.out.println("方法返回");
  32.         return proceed;
  33.     }
  34. }
复制代码
第四步:测试
测试类
  1. package com.ltx.springtest;
  2. import com.ltx.springtest.service.UserService;
  3. import org.junit.jupiter.api.Test;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.boot.test.context.SpringBootTest;
  6. @SpringBootTest
  7. class SpringTestApplicationTests {
  8.     @Test
  9.     void contextLoads(@Autowired UserService userService) {
  10.         userService.addUser();
  11.     }
  12. }
复制代码
效果如下所示:
 
所以spring可以在不改变原有业务代码的底子上进行了加强
如安在Spring中创建一个所谓切面?
   @Aspect+@Component+通知+切点
  4.3 AOP具体使用

 4.3.1 @EnableAspectJAutoProxy

 启用AOP,没有这个注解AOP功能无法使用

@EnableAspectJAutoProxy是否一定要加?
为什么没有加AOP也起作用了?
SpringBoot实在会通过启动类自动帮我们加上@EnableAspectJAutoProxy,所以可以省略。
但是依然建议加上@EnableAspectJAutoProxy,在Spring中是要加的。

4.3.2 通知

 通知分类
   后置通知@After:目标方法之后执行
  异常通知@AfterThrowing:目标方法出现了异常执行
返回通知@AfterReturning:目标方法返回值执行
环绕通知@Around:可以把代码加强在目标方法的恣意地方,更通用
  前置通知实例
  1. // 前置通知
  2. @Before("execution(* com.example.c4_aop.advice.UserServce.*(..) )")
  3. public void before(JoinPoint joinPoint){
  4. // 记录当前方法的方法名,参数
  5. String methodName = joinPoint.getSignature().getName();
  6. // 参数
  7. Object[] args = joinPoint.getArgs();
  8. // 目标对象
  9. Object target = joinPoint.getTarget();
  10. System.out.println("当前执行的方法是"+target.getClass()+"."+methodName+";参数"+ Arrays.toString(args));
  11. }
复制代码
  执行次序:
正常:前置-->目标方法-->返回通知--->后置通知(finally)
异常: 前置-->目标方法-->异常通知--->后置通知(finally)
  4.3.3 切点 

4.3.3.1 表达式抽取

  1. @Pointcut("execution( public int cn.ltx.inter.MyCalculator.*(int,int))")
  2.     public void myPoint(){}
  3.    
  4.     @Before("myPoint()")
  5.     public static void start(JoinPoint joinPoint){
  6.         Object[] args = joinPoint.getArgs();
  7.         String name = joinPoint.getSignature().getName();
  8.         System.out.println(name+"方法开始执行,参数是:"+ Arrays.asList(args));
  9.     }
  10.     @AfterReturning(value = "myPoint()",returning = "result")
  11.     public static void stop(JoinPoint joinPoint,Object result){
  12.         String name = joinPoint.getSignature().getName();
  13.         System.out.println(name+"方法执行完成,结果是:"+result);
  14.     }
  15.     @AfterThrowing(value = "myPoint()",throwing = "exception")
  16.     public static void logException(JoinPoint joinPoint,Exception exception){
  17.         String name = joinPoint.getSignature().getName();
  18.         System.out.println(name+"方法出现异常:"+exception.getMessage());
  19.     }
  20.     @After("myPoint()")
  21.     private int end(JoinPoint joinPoint){
  22.         String name = joinPoint.getSignature().getName();
  23.         System.out.println(name+"方法执行结束了......");
  24.         return 0;
  25.     }
  26. }
复制代码
4.3.3.2 切点表达式 

Spring AOP支持使用以下AspectJ切点标识符(PCD),用于切点表达式:
切点标识符:规定匹配的位置




五、Spring声明式事务

5.1 事务是什么

  一组关联的数据库操纵 (转账);要么都乐成,要么都失败,保证业务操纵完备性的一种数据库机制。

ACID四大特性
   A  原子性:原子性指的是 在一组业务操纵下 要么都乐成 要么都失败
在一组增编削查的业务下 要么都提交 要么都回滚
C  同等性:事务前后的数据要保证数据的同等性
在一组的查询业务下 必须要保证前后关联数据的同等性
I  隔离性:在并发情况下 事物之间要相互隔离。
D  恒久性:数据一旦保存就是恒久性的。
  5.2 使用@Transactional注解

Spring的@Transactional注解是最常用的声明式事务管理方式。你可以将其添加到类或方法上,来声明事务的边界。
示例代码:
  1. import org.springframework.stereotype.Service;
  2. import org.springframework.transaction.annotation.Transactional;
  3. @Service
  4. public class UserService {
  5.     // 声明类级别的事务,类中的所有方法都会应用这个事务配置
  6.     @Transactional
  7.     public void createUser(User user) {
  8.         // 创建用户的业务逻辑
  9.     }
  10.     public void updateUser(User user) {
  11.         // 更新用户的业务逻辑
  12.     }
  13.     // 声明方法级别的事务,只对这个方法生效
  14.     @Transactional(readOnly = true)
  15.     public User getUser(Long id) {
  16.         // 获取用户的业务逻辑
  17.         return user;
  18.     }
  19. }
复制代码
5.3. 事务属性

@Transactional注解支持多个属性来定义事务的举动:

示例代码
  1. @Transactional(readOnly = true, propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
  2. public User getUser(Long id)
  3. {
  4.     // 获取用户的业务逻辑 return user;
  5. }
复制代码
5.4. 事务传播举动

事务的传播举动定义了当事务方法被另一个事务方法调用时,事务如何传播:

示例代码
  1. @Transactional(propagation = Propagation.REQUIRES_NEW)
  2. public void createUser(User user)
  3. {
  4.     // 创建用户的业务逻辑
  5. }
复制代码
5.5. 事务隔离级别

事务的隔离级别定义了事务在执行过程中对数据的可见性:

   脏读(Dirty Read):一个事务读取到了另一个事务未提交的数据。如果谁人事务终极回滚,读取到的数据将是无效的。
  不可重复读(Non-repeatable Read):在一个事务中,多次读取同一数据聚集时,由于其他事务的修改,大概会得到不同的效果。这违反了事务的隔离性。
  幻读(Phantom Read):一个事务在执行过程中,由于其他事务的插入或删除操纵,导致读取到之前不存在的行,或者丢失了之前存在的行。
  丢失更新(Lost Update):两个或多个事务同时修改同一数据,其中一个事务的修改大概会覆盖另一个事务的修改。特别是当两个事务读取同一数据,然后各自修改并提交时
  死锁(Deadlock):两个或多个事务相互等待对方持有的资源,导致无法继承执行。这通常发生在事务试图获取多个资源的锁时。
  示例代码
  1. @Transactional(isolation = Isolation.REPEATABLE_READ)
  2. public void updateUser(User user)
  3. {
  4.     // 更新用户的业务逻辑
  5. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4