Spring
2023-11-06 16:13:09 0 举报
AI智能生成
Spring详解
作者其他创作
大纲/内容
体系结构
Core Container(核心容器)
Beans
管理 Beans
Core
Spring 的核心,提供IOC容器的对象的创建并处理依赖对象关系
ExpressionLanguage
Context
配置文件 就是Bean的关系的集合,也叫做IOC容器,调用了大部分spring-core中的方法
ExpressionLanguage
SpEL 表达式
AOP
切面编程 使 Spring框架管理对象支持AOP,同时这个模块也提供了事务管理
ORM
提供了对现有的ORM框架的支持,例如Hibernate,JDO,Mybatis等
DAO
提供了对数据访问对象(Data Access Object,DAO)模式和JDBC的支持,把实现业务逻辑和数据库访问的代码实现分离等。
Data Access(数据库整合)
JDBC
ORM
OXM
JMS
Transaction
springWeb(MVC Web 开发)
springWeb 和 spring 无需通过中间整合层进行整合, 是一个基于 mvc 的 web 框架,方便前后端数据的传输,
拥有控制器,接收外部求,解析参数传给服务层
拥有控制器,接收外部求,解析参数传给服务层
bean的管理
基于 xml 配置方式依赖注入
get, set 方式注入
构造方法注入
注解方式实现依赖注入
注解需要的 jar 包, 注解功能封装在 AOP 包中,需要导入spring-aspects包
在spring中开启注解扫描
<context:component-scan base-package="包名"> </context:component-scan>
创建对象注解方式
@Component(value=“admin”)
相当于 <bean id=“admin” class=“”></bean>
@Service
@Repository
注意:只是为了后续扩展功能,在不同的层使用不同的注解标记
@Scope(value=“prototype”) 原型 @Scope(value=“ singleton ”) 单例
@Scope(value=“prototype”) 原型 @Scope(value=“ singleton ”) 单例
注解方式注入属性
@Autowired
byType 自动注入
该注解默认使用按类型自动装配 Bean 的方式
byName 自动注入
结合@Qualifier 注解一起使用,按照名称(byName)来装配
@Qualifier 的value 属性用于指定要匹配的 Bean 的 id 值
@Qualifier 的value 属性用于指定要匹配的 Bean 的 id 值
@Resource
Spring 提供了对 jdk 中@Resource 注解的支持
既可以按名称匹配 Bean,也可以按类型匹配 Bean。默认按照 ByType 自动注入
注解与 XML 的对比
注解
优点:方便,直观,高效
缺点:以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的
XML
优点:配置和代码是分离的,在 xml 中做修改,无需编译代码,只需重启服务器即可将新的配置加载
缺点:编写麻烦,效率低,大型项目过于复杂
Bean 的作用域
singleton
在Spring容器仅存在一个Bean实例,Bean以单实例的方式存在,是Bean默认的作用域
prototype
每次从容器重调用Bean时,都会返回一个新的实例
request
每一次HTTP请求都会产生一个新的Bean,该Bean仅在当前HTTP Request内有效
session
同一个HTTP Session共享一个Bean,不同的HTTP Session使用不同的Bean
globalSession
同一个全局Session共享一个Bean,只用于基于Protlet的Web应用,Spring5中已经不存在了。
事务管理
事物可以看做是由对数据库若干操作组成的一个单元。
事务的作用就是为了保证用户的每一个操作都是可靠的,事务中的每一步操作都必须成功执行,
只要有发生异常就回退到事务开始未进行操作的状态,这些操作要么都完成,要么都取消,从而保证数据满足一致性的要求
事务的作用就是为了保证用户的每一个操作都是可靠的,事务中的每一步操作都必须成功执行,
只要有发生异常就回退到事务开始未进行操作的状态,这些操作要么都完成,要么都取消,从而保证数据满足一致性的要求
事务形式
编程式事务
需 要 注 入 一 个 事 务 管 理 TransactionTemplate ,然后在我们代码中需要提交事务或回滚事务时自己写代码实现,少用
声明式事务
管理建立在 AOP 基础上,本质是对方法前后进行拦截,所以声明式事务是方法级别的
管理方式
基于 xml 配置
基于注解实现
配置事物管理器
开启注解事务管理
< tx :annotation-driven transaction-manager ="transactionManager" />
@Transactional
用法
一般把 @Transactional标签添加在service中
@Transactional可以添加在service层的类上,类中所有的方法都会添加事务管理功能
@Transactional如果只添加在某个方法上,那么表示此方法在事务管理中进行
失效情况
修饰一个非public的方法,底层权限只针对public修饰的方法
方法中的异常被catch捕获处理了
默认情况下出现编译期异常,事务不生效
@Transactional事务传播行为设置错误
数据库引擎不支持事务, 数据库引擎是mysql底层具体的一种数据处理实现的机制,
innodb(支持事务功能),myisam(不支持事务)
innodb(支持事务功能),myisam(不支持事务)
在一个非事务方法中使用this(原始的对象==自己new出来的对象)
java创建对象的方式
构造方法:new student()
反射
序列化
动态代理
容器:tomcat容器、ioc容器
相关面试问题
说说Spring AOP 和 AspectJ AOP 区别
Spring AOP
Spring AOP 属于运行时增强
特点
基于动态代理来实现,默认如果使用接口的,用 JDK 提供的动态代理实现,如果是方法则使用 CGLIB 实现
Spring AOP 需要依赖 IOC 容器来管理,并且只能作用于 Spring 容器,使用纯 Java 代码实现
在性能上,由于 Spring AOP 是基于动态代理来实现的,在容器启动时需要生成代理实例,
在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ 的那么好
在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ 的那么好
AspectJ AOP
AspectJ 是一个易用的功能强大的 AOP 框架,属于编译时增强, 可以单独使用,也可以整合到其它框架中,
是 AOP 编程的完全解决方案。AspectJ 需要用到单独的编译器 ajc
是 AOP 编程的完全解决方案。AspectJ 需要用到单独的编译器 ajc
AspectJ 属于静态织入,通过修改代码来实现,在实际运行之前就完成了织入,所以说它生成的类是没有额外运行时开销的
织入的时机
编译期织入(Compile-time weaving)
如类 A 使用 AspectJ 添加了一个属性,类 B 引用了它,这个场景就需要编译期的时候就进行织入,否则没法编译类 B。
编译后织入(Post-compile weaving)
也就是已经生成了 .class 文件,或已经打成 jar 包了,这种情况我们需要增强处理的话,就要用到编译后织入。
类加载后织入(Load-time weaving)
指的是在加载类的时候进行织入,要实现这个时期的织入
设计模式
工厂设计模式
Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象
代理设计模式
Spring AOP 功能的实现。
单例设计模式
Spring 中的 Bean 默认都是单例的。
模板方法模式
Spring 中jdbcTemplate、hibernateemplate 等以Template 结尾的对数据库操作的类,它们就使用到了模板模式
包装器设计模
我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库,
这种模式让我们可以根据客户的需求能够动态切换不同的数据源
这种模式让我们可以根据客户的需求能够动态切换不同的数据源
观察者模式
Spring 事件驱动模型就是观察者模式很经典的一个应用。
适配器模式
Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller
1、bean的注入方式
1、@Configuration注解去标记了该类,这样标明该类是一个Spring的一个配置类,在加载配置的时候会去加载它,
@Bean的注解,标明这是一个注入Bean的方法,会将下面的返回的Bean注入IOC
@Bean的注解,标明这是一个注入Bean的方法,会将下面的返回的Bean注入IOC
2、通过构造方法注入Bean
IOC(控制反转)
它是一种 设计思想 ,就是 将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理
IOC 容器是具有依赖注入功能的容器,负责对象的实例化、对象的初始化,对象和对象之间依赖关系配置、
对象的销毁、对外提供对象的查找等操作,对象的整个生命周期都是由容器来控制
对象的销毁、对外提供对象的查找等操作,对象的整个生命周期都是由容器来控制
正控
若要使用某个对象,需要 自己去负责对象的创建
反控
若要使用某个对象,只需要 从 Spring 容器中获取需要使用的对象,不关心对象的创建过程,也就是把 创建对象的控制权反转给了 Spring 框架.
底层实现方式
解析 xml/扫描注解标签 + 工厂模式 + 反射机制
Spring 通过 IoC 容器来管理对象的实例化和初始化,以及对象从创建到销毁的整个生命周期
两种类型容器
BeanFactory
Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能;
BeanFactory在启动的时候不会去实例化Bean,当有从容器中拿Bean的时候才会去实例化;
BeanFactory在启动的时候不会去实例化Bean,当有从容器中拿Bean的时候才会去实例化;
ApplicationContext
应用上下文,继承BeanFactory接口,它是Spring的一个更高级的容器,提供了更多的有用的功能
ApplicationContext在启动的时候就把所有的Bean全部实例化了。
它还可以为Bean配置lazy-init=true来让Bean延迟实例化;
ApplicationContext在启动的时候就把所有的Bean全部实例化了。
它还可以为Bean配置lazy-init=true来让Bean延迟实例化;
实现类
ClassPathXmlApplicationContext
该类从类路径 ClassPath 中寻找指定的 XML 配置文件,并完成 ApplicationContext 的实例化工作
FileSystemXmlApplicationContext
该类从指定的文件系统路径中寻找指定的 XML 配置文件,并完成 ApplicationContext 的实例化工作
AOP(面向切面编程)
可以对业务逻辑和非业务逻辑进行隔离,从而使得各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
应用场景
验证权限
打印日志
提交事务
统一异常处理
核心原理
使用动态代理的方式在执行方法前后或者出现异常的时候做加入相关的逻辑.
基本概念
连接点(Joinpoint)
类中可以被增强的方法,这个方法就被称为连接点
切入点(pointcut)
类中有很多方法可以被增强,但实际中只有 add 和 update被增强了,那么 add 和 update 方法就被称为切入点
通知(Advice)
通知是指一个切面在特定的连接点要做的事情(增强的功能)。
通知分为方法执行前通知,方法执行后通知,环绕通知等.
通知分为方法执行前通知,方法执行后通知,环绕通知等.
切面(Aspect)
把通知添加到切入点的整个过程称为切面
目标(Target)
代理的目标对象(连接点,切入点所在类)
代理(Proxy)
向目标对象应用通知时创建的代理对象
AspectJ
基于 aspectj 的 xml 配置方式实现
基于注解方式的实现
启动 AspectJ 支持:<aop:aspectj-autoproxy /> <!--自动代理-->
通知类型
前置通知
@Before
后置通知
@After
环绕通知
@Around
多个切面的情况下,可以通过 @Order 指定先后顺序,数字越小,优先级越高
异常通知
@AfterThrowing
返回通知
@AfterReturning
动态代理
jdk动态代理
基于接口,Java的Proxy类和InvocationHandler接口是JDK动态代理的核心,代理对象实现了目标接口,
通过InvocationHandler来拦截对目标方法的调用。
通过InvocationHandler来拦截对目标方法的调用。
Interface
对于 JDK 动态代理,目标类需要至少需要实现一个Interface(接口)
InvocationHandler
InvocationHandler是一个接口,可以通过实现这个接口,定义横切逻辑,再通过反射机制(invoke)调用目标类的代码,
在次过程,可能包装逻辑,对目标方法进行前置后置处理
在次过程,可能包装逻辑,对目标方法进行前置后置处理
Proxy
Proxy利用InvocationHandler动态创建一个符合目标类实现的接口的实例,生成目标类的代理对象
Proxy.newProxyInstance
优缺点
优点
无需引用第三方库,在JRE运行环境中就可以运行,生成代理对象更加简单、快捷
缺点
仅支持基于接口进行代理,无法对类进行代理,所以它的作用有限
cglib动态代理
基于继承,CgLib 动态代理是使用字节码处理框架 ASM,其原理是通过字节码技术为一个类创建子类,
并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
实现MethodInterceptor接口重写intercept
利用第三方Enhancer工具类创建目标子类代理对象
利用第三方Enhancer工具类创建目标子类代理对象
CGLib 由于是采用动态创建子类的方法,对于 final 方法,无法进行代理。
优缺点
优点
Cglib支持对类进行代理,即使没有接口,也可通过设置回调接口间接地实现。
性能比JDK动态代理更高,能够代理那些没有实现任何接口的目标对象
性能比JDK动态代理更高,能够代理那些没有实现任何接口的目标对象
缺点
对比
实现方式
JDK 动态代理是通过反射实现的,而CGLIB动态代理是通过继承目标类来实现的
目标类限制
JDK 动态代理要求目标类必须要实现接口,而CGLIB动态代理则没有这个限制
性能
JDK 动态代理相对于 CGLIB 动态代理来说,因为实现方式不同,生成的代理类的效率会低一些
对象类型
JDK 动态代理只能代理实现了接口的类,CGLIB 通过继承实现,不能代理 final 类
依赖库
JDK 动态代理是 Java 自带的库,不需要额外的依赖,而 CGLIB 动态代理需要依赖 cglib 库
事务传播行为
事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。
事务传播行为是 Spring 框架独有的事务增强特性,他不属于的事务实际提供方数据库行为
事务传播行为是 Spring 框架独有的事务增强特性,他不属于的事务实际提供方数据库行为
七种传播行为
PROPAGATION_REQUIRED
默认的,如果当前没有事务,就新建一个事务,如果已经存在一个事务中, 加入到这个事务中
PROPAGATION_SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行
PROPAGATION_MANDATORY
使用当前的事务,如果当前没有事务,就抛出异常
PROPAGATION_REQUIRES_NEW
新建事务,如果当前存在事务,把当前事务挂起
PROPAGATION_NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
PROPAGATION_NEVER
以非事务方式执行,如果当前存在事务,则抛出异常
PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行。
如果当前没有事务, 则执行与 PROPAGATION_REQUIRED 类似的操作。
如果当前没有事务, 则执行与 PROPAGATION_REQUIRED 类似的操作。
Spring Bean生命周期
实例化(Instantiation)
通过反射调用构造方法实例化对象
属性赋值(Populate)
为 Bean 设置相关属性和依赖
初始化(Initialization)
初始化前回调
初始化后回调
Bean可用
销毁(Destruction)
销毁前回调
生命周期图
主要步骤
实例化 Bean
通过反射调用构造方法实例化对象
依赖注入
装配 Bean 的属性
实现了 Aware接口的 Bean,执行接口方法
如顺序执行 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware、ApplicationContextAware的接口方法。
Bean 对象初始化前
循环调用实现了 BeanPostProcessor 接口的预初始化方法(postProcessBeforeInitialization)
Bean 对象初始化
顺序执行 @PostConstruct 注解方法、InitializingBean 接口方法、init-method 方法
Bean 对象初始化后
循环调用实现了 BeanPostProcessor 接口的后初始化方法(postProcessAfterInitialization)
容器关闭时
执行 Bean 对象的销毁方法,顺序是:@PreDestroy 注解方法、DisposableBean 接口方法、destroy-method
自动装配类型
byName
根据名称进行自动匹配,假设Boss又一个名为car的属性,如果容器中刚好有一个名为car的bean,Spring就会自动将其装配给Boss的car属性
byType
根据类型进行自动匹配,假设Boss有一个Car类型的属性,如果容器中刚好有一个Car类型的Bean,Spring就会自动将其装配给Boss这个属性
constructor
与 byType类似, 只不过它是针对构造函数注入而言的。如果Boss有一个构造函数,构造函数包含一个Car类型的入参,
如果容器中有一个Car类型的Bean,则Spring将自动把这个Bean作为Boss构造函数的入参;
如果容器中没有找到和构造函数入参匹配类型的Bean,则Spring将抛出异常。
如果容器中有一个Car类型的Bean,则Spring将自动把这个Bean作为Boss构造函数的入参;
如果容器中没有找到和构造函数入参匹配类型的Bean,则Spring将抛出异常。
autodetect
根据Bean的自省机制决定采用byType还是constructor进行自动装配,如果Bean提供了默认的构造函数,则采用byType,否则采用constructor。
0 条评论
下一页