第八天—Spring框架

复习Spring框架的核心概念和特点。

spring的核心概念

Spring是一个开源的Java应用程序框架,提供了一种轻量级的解决方案来开发企业级应用程序。Spring框架的核心是IoC控制反转和AOP面向切面编程容器。它提供了一系列的模块,包括数据访问、事务管理、Web开发等,使得开发者可以通过配置和依赖注入的方式更加灵活地开发应用程序。

Spring 的特点

spring采用了轻量级的设计思路,提供了一系列可选的模块和功能,我们可以按需选择,保持应用程序的简介和灵活性。通过DI依赖注入和IOC控制反转,实现了组件之间的松耦合。还提供了强大的面向切面编程的支持,通过AOP将日志记录挥着事务管理等这些从业务逻辑中分离出来,并将其统一管理和织入到程序中。统一的配置管理,可以通过配置文件或者注解来管理应用程序的行为和依赖关系。

复习spring 容器的概念和作用;

spring容器是用于管理和组织应用程序中的对象。
spring容器有两个主要的实现接口:BeanFactory和ApplicationContext

  1. BeanFactory
    BeanFactory是Spring容器的基础接口,提供了基本的IOC功能。负责实例化、配置和管理Bean对象。
    使用延迟初始化策略,即在需要回去Bean时才会实例化。这种延迟初始化的方式可以节省系统资源。
  2. ApplicationContext
    ApplicationContext是一个高级的spring容器,是BeanFactory的子接口,提供了跟多的企业级功能和特性。
    在BeanFactory的基础上增加了更多的功能,如食物传播、资源加载、AOP等。
    BeanFactory和ApplicationContext的区别
    BeanFactory是spring基本的容器接口,提供了IOC功能,可以实例化、配置和管理Bean对象。使用延迟初始化策略。
    applicationContext是BeanFactory的扩展,继承了BeanFactory的功能,并增加了国际化、事件传播、资源加载、AOP等功能。更适用于大多数企业级的应用程序开发。

复习spring配置方式,像xml配置,注解配置(@Component、@Autowired)和java配置(如@Configuration、@Bean)

spring提供了很多配置方式有xml配置、注解配置、java配置。我们现在最常用的配置方式是注解配置和java配置。
注解配置使得可以在类、字段、方法上添加注解,告诉spring如何创建和管理Bean。我们常用的注解有@component、@Autowirde、@Configurationjava配置是使用纯java代码来配置Spring应用程序,通过编写java类,使用特定的注解和API来定义Bean、注入依赖关系和配置Spring 特性。常用的java配置类包括@Configuration@Bean

复习Spring的IoC和DI容器,掌握Bean的定义和管理。

IOC

IOC是spring框架的核心部分,负责管理bean对象,通过控制反转的方式将对象的创建和依赖关系交由容器来完成,而不是由应用程序主动获取和管理对象。IOC容器还实现了依赖查找和依赖注入的机制,使得对象之间的依赖关系解耦,提高了代码的可维护性和可测试性。
如何实现的控制反转

  1. 什么是循环依赖
    循环依赖是指两个或多个Bean之间相互依赖的情况,形成了一个闭环依赖关系。比如说
    Bean A正在创建,并且需要引用Bean B。
    Bean B也正在创建,并且需要引用Bean A。
    由于Bean A尚未完成创建,无法提供给Bean B,同时Bean B也无法提供给Bean A。

  2. 如何解决
    在Spring框架中,默认情况下是不支持循环依赖的,因为它会导致无限递归或对象引用不完整的问题。然而,Spring提供了一些机制来解决或预防循环依赖问题:
    主要的解决逻辑就是对对象创建分层,以及对象创建的时机

  3. 提前暴露:spring容器会提前解析到次创建对象会出现循环依赖的情况了,因此先去创建对象,先不给属性赋值,创建完对象后再去给属性赋值。

  4. 使用@Lazy注解:延迟bean的加载。这样,当循环依赖发生时,Spring会返回一个代理对象,以延迟依赖注入的完成,从而打破循环依赖。

  5. 重新设计应用程序结构:如果出现复杂的循环依赖问题,可能需要重新设计应用程序的结构,以减少或避免循环依赖的发生。

DI

DI是IOC的具体实现方式,通过依赖关系注入到对象中,实现对象之间的解耦。依赖注入的方式有,构造方法注入、setter方法注入、接口注入、注解注入等方式。

IOC的优点

IOC容器将控制权交给了容器,降低了对象之间的耦合性。通过IOC管理对象,可以方便的添加、修改和替换Bean的实现,实现应用程序的灵活性和可扩展性。 可以耿容易的进行单元测试和模块测试。

Bean

Bean 是应用程序中的一个对象,它由特定的类或接口实例化而来。
Bean的生命周期:
在Spring框架中,Bean的生命周期包括以下几个阶段:

  1. 实例化:在这个阶段,容器会根据Bean的定义信息创建Bean的实例。根据配置方式的不同,实例化可以通过构造函数实例化、工厂方法实例化或其他方式实现。

  2. 属性赋值:在实例化之后,容器会根据配置的属性信息将相应的值赋给Bean的属性。这个阶段可以通过Setter方法、字段注入或其他方式来完成属性的赋值。

  3. 初始化:在属性赋值之后,容器会调用Bean的初始化方法来执行一些额外的初始化逻辑。这个阶段可以通过实现InitializingBean接口或使用自定义的初始化方法来完成。

  4. 使用:在初始化之后,Bean可以被容器或其他组件使用。在这个阶段,Bean会参与应用程序的业务逻辑和功能实现。

  5. 销毁:在应用程序关闭或容器销毁时,容器会调用Bean的销毁方法来执行一些清理工作。这个阶段可以通过实现DisposableBean接口或使用自定义的销毁方法来完成。

**Bean的作用域:**单例(singleton)、原型(Prototype)、会话(session)、请求(request)

复习Spring的AOP思想和实现方式。

代理模式

1.静态代理

AspectJ静态代理(也称编译增强)
AOP框架会在编译阶段生成AOP代理类,并将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。

2.动态代理

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:

① JDK动态代理只提供接口的代理,不支持类的代理,要求被代理类实现接口。JDK动态代理的核心是InvocationHandler接口和Proxy类,在获取代理对象时,使用Proxy类来动态创建目标类的代理类(即最终真正的代理类,这个类继承自Proxy并实现了我们定义的接口),当代理对象调用真实对象的方法时, InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;
InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最终生成的代理对象; method 是被代理目标实例的某个具体方法; args 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用。
② 如果被代理类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

  1. 静态代理与动态代理的区别???

静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。

动态代理技术

动态代理技术分为jdk动态代理和cglib动态代理
1.jdk动态代理
jdk动态代理是不需要第三方库的支持,只需要jdk环境就可以进行代理,使用条件:

1.业务目标对象实现接口
2.实现InvocationHadler接口
3.使用proxy.newproxyInstance( )方法生成代理对象
JDK动态代理有个限制,只能为接口创建代理实例
JDK动态代理是基于拦截器和反射来实现的

2.cglib动态代理
通过继承的方式实现代理,在子类中采用拦截技术拦截所有父类的方法的调用并顺势植入横切逻辑

3.spring中何时使用JDK或Cglib

如果目标对象实现了接口默认采用jdk动态代理
如果目标对象实现了接口,可以强制使用Cglib
如果目标对象没有实现接口,必须采用Cglib,spring会自动在JDK动态代理与Cglib之间转换

介绍

Aop 是面向切面编程,AOP的的核心是切面。AOP在不修改源代码本身的前提下使用运行时的动态代理技术对已有的代码逻辑增强。AOP可以实现组件化,可拔插式的功能扩展,通过简单配置即可将功能增强到指定的切入点。可用于权限认证、日志、事务处理。

术语

Target目标对象:被代理的原始对象
proxy代理对象:目标对象被织入通知后的产物
JoinPoint连接点:目标对象的所属类中定义的所有方法均为连接点
PointCut切入点:被切面拦截增强的连接点(切入点一定是连接点,连接点不一定是切入点)
Advice通知:增强的逻辑代码,即拦截到目标对象的连接点之后要做的事情
Aspect 切面:切入点+通知
introduction引介:特殊的通知类型,可以在不修改原有类的代码的前提下,在运行期为原始类动态添加新的属性/方法

原理

Aop的底层是由运行时动态代理支撑,在bean初始化流程中,借助BeanPostProcessor(后置处理器)将原始目标对象织入通知,生成代理对象,AOP设计原理是对原有的业务逻辑进行横切增强,使用不同的通知织入方式,她有不同的底层原理支撑(编译期,类加载器,对象创建期)

执行时机

@Before前置通知:目标对象的方法调用之前触发
@After 后置通知:目标对象的方法调用之后触发
@AfterReturning 返回通知:目标对象的方法调用完成,在返回结果之后触发
@AfterThrowing 异常通知:目标对象的方法运行中抛出/触发异常后触发
@Around环绕通知:编程式控制目标对象的方法调用。环绕通知是所有通知类型中可操作范围最大的一种,他可以直接拿到目标对象,以及要执行的方法,所以环绕通知可以任意的在目标对象的方法调用前后搞事甚至不调用目标对象的方法
注意:AfterReturning与AfterTrowing两者是互斥的!如果方法调用成功无异常,则会有返回值;如果方法抛出了异常,则不会有返回值

aop的实现过程

1.首先创建一个java类作为切面。使用@Aspect注解进行标识,并使用@Comment 注解将切面对象加入到bean容器中,需要使用@Comment是因为@Advice是java的注解spring 无法直接识别到,因此需要@Comment注解将切面对象加入到spring中。然后再使用@Pointcut注解定义切入点,支持三种切入点的用法,分别是使用方法签名,通配符的方式,自定义注解的方式进行。再结合执行时机@Before前置通知、@After后置通知、@Around环绕通知、@AfterReturning返回通知 、@AfterThrowing异常通知。声明执行的时机在切入点的前后做操作。spring会自动注入桥接对象(代表目标对象) 使用ProceedingJoinPoint对象的proceed()方法显式地执行目标方法。

@Pointcut
当使用Spring AOP的@Pointcut注解时,有几种常用的用法。下面是一些常见的@Pointcut用法示例:

  1. 使用方法签名:可以通过方法签名来定义切入点,表示匹配特定的方法。
@Pointcut("execution(public void com.example.MyService.myMethod())")
public void myMethodPointcut() {}

上述示例中的切入点myMethodPointcut()匹配了com.example.MyService类中的myMethod()方法。

  1. 使用通配符:可以使用通配符来模糊匹配类名、方法名和参数。
@Pointcut("execution(public * com.example.*.*Service.*(..))")
public void serviceMethodsPointcut() {}

上述示例中的切入点serviceMethodsPointcut()匹配了com.example包下所有以Service结尾的类中的任意方法。

  1. 使用注解:可以使用注解来标记目标方法,并通过@within@annotation来匹配带有特定注解的方法。
@Pointcut("@annotation(com.example.MyAnnotation)")
public void annotatedMethodsPointcut() {}

@Pointcut("@within(com.example.MyAnnotation)")
public void withinAnnotatedClassesPointcut() {}

上述示例中的切入点annotatedMethodsPointcut()匹配了被com.example.MyAnnotation注解标记的方法,而切入点withinAnnotatedClassesPointcut()匹配了类上标记有com.example.MyAnnotation注解的所有方法。

桥接对象

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @Around("execution(* com.example.MyService.*(..))")
    public Object aroundMethodExecution(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Before method execution");
        
        // 执行目标方法
        Object result = joinPoint.proceed();
        
        System.out.println("After method execution");
        
        return result;
    }
}

使用@Around注解来标记aroundMethodExecution()方法作为环绕通知。在方法体内部,我们可以自定义处理逻辑,并使用ProceedingJoinPoint对象的proceed()方法显式地执行目标方法。

复习spring MVC

5.1五个组件

		前端控制器DispatcherServlet
		HandlerMapping处理器映射器
		HandlerAdapter处理器适配器
		ModelAndView
		ViewReslover视图解析器

5.2 运行流程

客户端发送HTTP请求到前端控制器DispatcherServlet。
DispatcherServlet根据请求的URL和配置的请求映射规则,将请求转发给对应的处理器(Controller)。
处理器(Controller)接收请求并进行相应的业务处理,包括数据处理、调用服务层方法等。
处理器(Controller)处理完业务逻辑后,通常会返回一个逻辑视图名或ModelAndView对象,表示要展示的视图以及传递给视图的数据。
DispatcherServlet根据配置的视图解析器(ViewResolver),将逻辑视图名解析为实际的视图对象。
视图对象根据数据模型和模板文件,生成最终的视图内容。
DispatcherServlet将生成的视图内容返回给客户端,完成请求的响应。

在整个流程中,前端控制器DispatcherServlet起到了中心协调的作用,负责接收请求、路由请求、选择处理器(Controller)、选择视图解析器(ViewResolver)、渲染视图等。处理器(Controller)负责处理具体的业务逻辑,包括数据处理、调用服务层方法等。视图解析器(ViewResolver)负责将逻辑视图名解析为实际的视图对象。视图对象根据数据模型和模板文件生成最终的视图内容,并由DispatcherServlet返回给客户端。

复习spring的事务管理

spring事务的种类

spring 事务分为编程式事务与声明式事务
编程式事务

编程式事务管理使用TransactionTemplate。

声明式事务

声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前启动一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
优点
声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中,减少业务代码的污染。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。

隔离级别

1.三个问题

「脏读」 :表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。
「不可重复读」 :是指在一个事务内,多次读同一数据。
「幻读」 :指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了。

2.隔离级别

1.读未提交,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
2.提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;
3.可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;
4.序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。

失效问题

1.抛出检查异常导致事务不能正确回滚
原因:Spring 默认只会回滚非检查异常
解决方案:配置 rollbackFor 属性 (@Transactional(rollbackFor = Exception.class )
2.业务方法内自己 try-catch 异常导致事务不能正确回滚
原因:事务通知只有捉到了目标抛出的异常,才能进行后续的回滚处理,如果目标自己处理掉异常,事务通知无法知悉
解决方案: 1)异常原样抛出,即在 catch 块添加 throw new RuntimeException(e);2) 手动设置 TransactionStatus.setRollbackOnly() ,在 catch 块添加 TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
3.aop 切面顺序导致导致事务不能正确回滚
原因:事务切面优先级最低,但如果自定义的切面优先级和他一样,则还是自定义切面在内层,这时若自定义切面没有正确抛出异常
解决方案: 1) 和失效原因二一样
2) 调整切面顺序,在 MyAspect 上添加 @Order(Ordered.LOWEST_PRECEDENCE - 1) (不推荐)
4.非 public 方法导致的事务失效
原因:Spring 为方法创建代理、添加事务通知、前提条件都是该方法是 public 的
解决方案:1)使用public方法
5.父子容器导致的事务失效
原因:子容器扫描范围过大,把未加事务配置的 service 扫描进来
解决方案:1)各扫描各的,不要图简便
2)不要用父子容器,所有 bean 放在同一容器

事务的传播

在这里插入图片描述

特性(ACID)

原子性:一个事务要么全部成功,全部失败,不会停在某个阶段
一致性 :事务的前后处于一致状态
隔离性:多个事务同时操作相同数据库的同一个数据时,一个事务的执行不受另外一个事务的干扰
持久性:一个事务一旦提交,则数据将持久化到本地,除非其他事务对其进行修改

应用

1.注解作用域

事务常用注解

  1. @EnableTransactionMannagement
    表示spring开启注解事务配置的支持
    2.@Transactional
    spring注解配置事务的核心注解,可以出现在接口、类、方法上
    3.@TransactionEventListener
    用于配置事务的监听器,使我们在事务提交和回滚前后可以做一些额外的功能

2.分类

1.声明式事务

1)基于注解方式实现(常用)
2)基于xml配置文件方式实现
注意:在Spring中进行声明式事务管理,底层使用的是AOP编程式事务

2.编程式事务

复习Spring Security的概念和作用,包括身份验证、授权、安全过滤器链等,以及如何在Spring应用中添加安全性和权限控制。

复习Spring框架整合,spring与mybatis的整合以及RESTful Web Services

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值