目录
BeanFactory 和 ApplicationContext
@EnableAutoConfiguration实现自动装配的核心注解
AutoConfigurationImportSelector加载自动装配类
Spring
什么是Spring框架?
Spring是一个轻量级的(核心包),非侵入式的一站式(数据持久层、web层、IoC、AOP)的框架,为了简化企业级开发,开箱即用
轻量级:指的是核心jar包小
非侵入式:框架代码不会侵入到业务代码,业务代码不会实现或继承框架中接口或类
核心:IoC(控制反转)、AOP(面向切面编程)
Spring IoC
IoC(Inversion of Control:控制反转)是一种设计思想,将原本在程序中手动创建对象的控制权交给Spring框架去管理
IoC解决了什么问题?
-
对象之间的依赖程度降低了
-
资源变得容易管理
例如:我们要在Service层使用Dao层,但是Dao接口下有多个实现类,如果没有IoC的话我们就要new多个对象才能实现我们的业务,而且要是如果只有一个类引用了Dao还好,如果是多个,那我们就要一个一个去改,增加了很多没必要的工作量
但是有了IoC,我们在使用的时候直接向容器要就行
IoC和DI有区别吗?
IoC最常见以及最合理的实现方式叫做依赖注入(Dependency Injection,简称 DI)
Spring AOP
什么是AOP?
AOP即面向切面编程,面向对象的延续,二者互补
AOP的目的是将横切关注点(如日志记录、事务管理、权限控制等)从核心业务逻辑中分离出来,通过动态代理等技术,实现代码的复用和解耦,提高代码可维护性和扩展性。
简单来说就是通过一个代理对象,在不修改原来代码的情况下对目标类增强
AOP为什么叫面向切面编程?
核心思想是从将横切关注点从核心业务中分离出来,形成一个个切面(Aspect)
-
横切关注点:多个类对象中的公共行为(如日志、事务、权限)
-
切面:对横切关注点封装的类
-
连接点:方法执行的某个特定时刻(如方法调用、异常抛出)
-
通知:切面在某个连接点要执行的操作,有五种类型
-
前置通知(Before)
-
后置通知(After)
-
返回通知(AfterReturning)
-
异常通知(AfterThrowing)
-
环绕通知(Around)
-
-
切点:一个切点是一个表达式,匹配哪些连接点需要被增强,比如比如
execution(* com.zl.service..*(..))
匹配com.zl.service
包及其子包下的类或接口。 -
织入:将通知应用到切点匹配的连接点上。一般分为编译期织入(AspectJ)和运行期织入(AspectJ)
AOP解决了什么问题?
如果没有AOP,我们在写例如日志管理、事务管理、权限控制等功能时,就要把一份一模一样的代码复制粘贴在每一个需要的业务模块,这样代码显得很冗余,也不好管理,改一处就要改很多处
但是有了AOP,我们将这种公共功能封装到一个类中,哪里需要直接用就行,修改的时候,只用修改封装的那个类的东西即可,大大减轻我们的工作量,我们的代码也更加优雅
多个切面的执行顺序如何控制?
@Order(3)注解可以解决,值越小优先级越高
Spring Bean的管理
什么是Spring Bean?
Bean指的就是IoC容器管理的对象
我们需要告诉IoC帮助我们管理哪些对象,可以用XM文件、注解来实现
<bean id="admin" class="com.zl.spring.model.Admin">
<constructor-arg name="id" value="100"></constructor-arg>
<constructor-arg name="account" value="admin"></constructor-arg>
</bean>
将一个类声明Bean的注解有哪些?
-
@Component
:通用注解,如果一个Bean不知道哪一层,可以使用此注解 -
@Repository
: 对应持久层(Dao层)注解,主要用于数据库操作 -
@Service
:对应服务层,主要设计一些复杂逻辑 -
@Service
: 对应SpringMVC控制层,用于接收用户请求并调用Service层数据返回给前端
@Component和@Bean的区别
-
@Component
注解作用于类,而@Bean
注解作用于方法。 -
@Component
通常是通过类路径扫描自动侦测以及自动装配到Spring容器中,而@Bean
告诉Spring这是某个类实例,当我需要的时候给我 -
@Bean
注解比@Component
注解的自定义性更强,
@Autowired和@Resource的区别
-
@Autowired
是 Spring 提供的注解,@Resource
是 JDK 提供的注解 -
Autowired
默认的注入方式为byType
(根据类型进行匹配),@Resource
默认注入方式为byName
(根据名称进行匹配)。 -
Autowired
可以通过@Qualifier
注解来显式指定名称,@Resource
可以通过name
属性来显式指定名称。 -
@Autowired
支持在构造函数、方法、字段和参数上使用。@Resource
主要用于字段和方法上的注入,不支持在构造函数或参数上使用。
Bean的作用域
-
singleton : IoC 容器中只有唯一的 bean 实例。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用。
-
prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续
getBean()
两次,得到的是不同的 Bean 实例。
Bean是线程安全的吗?
Bean是否是线程安全的,取决于其作用域和状态
-
prototype作用域下,每次都会创建一个新的bean实例,不存在资源竞争,所以不存在线程安全问题
-
singleton作用域下,IoC中只有唯一的bean实例,可能会存在资源竞争(有状态才会存在),不过这个取决于Bean是否有状态,大部分下是无状态的
-
无状态:不会存储数据,例如Dao、Service、Controller,这些只关注方法调用本身
-
有状态:是有数据存储功能(例如包含成员变量)
-
解决办法
-
在Bean中尽量避免可变的成员变量
-
利用
ThreadLocal
,将可变的成员变量保存在其中
Bean生命周期
生命周期
何时生
1. 实例化 Instantiation 通过反射机制以及工厂创建出来的原始对象 2. 属性赋值 Populate 3. 初始化 Initialization(完成对原始对象的各种功能增强AOP生成代理对象),完成后就把bean对象放入到容器中使用 4. 销毁 Destruction <bean id="" class="" scope="" destory-method="" init-method="" lazy-init="true"></bean>
何时销毁
BeanFactory 和 ApplicationContext
两者都是接口
-
BeanFactory
:延迟注入(使用到某个 bean 的时候才会注入),相比于ApplicationContext
来说会占用更少的内存,程序启动速度更快。 -
ApplicationContext
:容器启动的时候,不管你用没用到,一次性创建所有 bean 。BeanFactory
仅提供了最基本的依赖注入支持,ApplicationContext
扩展了BeanFactory
,除了有BeanFactory
的功能还有额外更多功能,所以一般开发人员使用ApplicationContext
会更多。
循环依赖
两个类之间相互关联(依赖)
A类中关联B类
B类中关联A类
这个在自己new对象时,没有任何问题,只需要给关联的对象赋值为null
但是在Spring中就有问题
在Spring管理的bean时,在自动注入时,如果两个类相互之间关联,那么会出现注入时,另一个对象还没有初始化完成
Spring中解决循环依赖问题
通过三级缓存(就是三个Map对象)
一级缓存(singletonObjects):主要存储初始化完成的对象
二级缓存(earlySingletonObjects):存储实例化完成的半成品bean对象,提前暴露给需要的地方
三级缓存(singletonFactories):放的是创建对象的工厂
当A需要B时,那么先从一级缓存中找B,没有,然后到二级缓存中找到B,
也没有,就去三级缓存中,找到B对应的工厂,创建出B对象(原始对象,半成品)
把B对象放到了二级缓存中
Spring事务
Spring事务管理,指的是spring框架提供了对事务进行提交,回滚功能,帮助我们进行事务管理
什么是事务?
事务是逻辑上一组操作,要么都执行,要么都不执行
事务的特性(ACID)
-
原子性(Atomicity):事务最小的执行单位,保证动作要么全部完成,要么都不完成
-
一致性(Consistency):执行任务前后,数据保持一致
-
隔离性(Isolation):并发访问数据库,一个用户的事务不被其他事务干扰
-
持久性(Durability):一个事务被提交后,对数据库数据的改变是持久的
Spring支持两种方式的事务管理
-
编程式事务管理:通过
TransactionTemplate
或者TransactionManager
手动管理事务,较少用到 -
声明式事务管理:使用
@Transactional
注解进行事务管理,实际是通过AOP实现的
Spring事务管理接口
-
PlatformTransactionManager
:(平台)事务管理器,Spring 事务策略的核心,Spring 并不直接管理事务,而是提供了多种事务管理器,通过这个接口,Spring为很多平台提供了对应的事务管理器,例如JDBC -
TransactionDefinition
:事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)。 -
TransactionStatus
:事务运行状态。例如是否是新的事务、是否为只回滚,设置为只回滚、是否已完成
事务传播行为
是为了解决业务层方法之间互相调用的事务问题
若是错误的配置以下3种传播行为,事务将不会回滚,使用的很少:
-
TransactionDefinition.PROPAGATION_SUPPORTS
-
TransactionDefinition.PROPAGATION_NOT_SUPPORTED
-
TransactionDefinition.PROPAGATION_NEVER
事务回滚规则
默认情况下,事务只有遇到运行期异常(RuntimeException
的子类)时才会回滚,Error
也会导致事务回滚,但是,在遇到检查型(Checked)异常时不会回滚。
@Transactional注解
可作用在方法、类中
常用参数
注意事项
-
@Transactional
注解只有作用到 public 方法上事务才生效,不推荐在接口上使用; -
被
@Transactional
注解的方法所在的类必须被 Spring 管理,否则不生效; -
底层数据库引擎必须支持事务,否则不生效
-
正确的设置
@Transactional
的rollbackFor
和propagation
属性,否则事务可能会回滚失败,例如rollbackFor = Exception.class
任何异常都不提交事务
Spring框架中用了哪些设计模式
-
工程设计模式:Spring使用工厂模式通过
BeanFactory
、ApplicationContext
创建 bean 对象。 -
代理设计模式:Spring AOP功能的实现
-
单例设计模式:Spring中的Bean默认是单例的
-
模板方法模式: Spring 中
jdbcTemplate
、hibernateTemplate
等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
SpringMVC
MVC 是模型(Model)、视图(View)、控制器(Controller)的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代码。
SpringMVC一般把后端项目分为Service 层(处理业务)、Dao 层(数据库操作)、Entity 层(实体类)、Controller 层(控制层,返回数据给前台页面)。
SpringMVC的核心组件
-
DispatcherServlet
:核心的中央处理器,负责接收请求、分发,并给予客户端响应。 -
HandlerMapping
:处理器映射器,根据 URL 去匹配查找能处理的Handler
,并会将请求涉及到的拦截器和Handler
一起封装。 -
HandlerAdapter
:处理器适配器,根据HandlerMapping
找到的Handler
,适配执行对应的Handler
; -
Handler
:请求处理器,处理实际请求的处理器。 -
ViewResolver
:视图解析器,根据Handler
返回的逻辑视图 / 视图,解析并渲染真正的视图,并传递给DispatcherServlet
响应客户端
工作原理
客户端发送请求,到达DispatcherServlet,根据请求信息调用HandlerMapping,根据URL去匹配查询能处理的Handler(也就是Controller),并将请求涉及到的拦截器和 Handler一起封装,DispatcherServlet调用HandlerAdapter适配器执行Handler,Handler完成用户请求处理后,会返回一个ModelAndView
SpringBoot
开发基于Spring,是在Spring的基础上简化配置文件,真正做到开箱即用,生态好,让程序员只用专注于业务代码上而不是各种配置
SpringBoot自动装配原理
什么是自动装配?
简单理解,就是通过注解或者一些简单的配置就能在SpringBoot的帮助下实现某些功能
SpringBoot是如何实现自动装配
我们先看下SpringBoot的核心注解@SpringBootApplication
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {}
-----------------------分割线-----------------------------------
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {}
由此源码可以看出@SpringBootApplication
是由@Configuration
、@EnableAutoConfiguration
、@ComponentScan
注解的集合
-
@EnableAutoConfiguration
:启用 SpringBoot 的自动配置机制 -
@Configuration
:允许在上下文中注册额外的 bean 或导入其他配置类 -
@ComponentScan
:扫描被@Component
(@Service
,@Controller
)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。
@EnableAutoConfiguration实现自动装配的核心注解
EnableAutoConfiguration
只是一个简单地注解,自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector
类。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage//将main包下的所有组件注册到容器中
@Import({AutoConfigurationImportSelector.class})// 加载自动装配类
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
AutoConfigurationImportSelector加载自动装配类
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {}
public interface DeferredImportSelector extends ImportSelector {}
public interface ImportSelector {
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
由以上源码可以看出,AutoConfigurationImportSelector实现了ImportSelector接口,这个接口中的selectImports方法主要用于获取所有符合条件的类的全限定类型,被加载到IoC容器中
private static final String[] NO_IMPORTS = new String[0];
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// <1>.判断自动装配开关是否打开
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
//<2>.获取所有需要装配的bean
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
这里的getAutoConfigurationEntry()
方法负责加载自动配置类
由此可见,自动装配是先进行判断是否开启自动装配,然后去获取需要自动装配的配置类,读取META-INF/spring.factories
,但是并不是里面所有的配置类都会加载,在这其中会进行过滤,我们pom.xml文件中有的依赖它会留下,没有的会过滤掉
Servlet的过滤器与 Spring 拦截器区别
-
过滤器通常在进入Servlet前后就会触发,而拦截器是在请求进入Controller前后可以触发
-
拦截器只对Controller层请求有作用,过滤器对所有请求都起作用,包括静态资源
-
拦截器基于Java反射机制实现,不依赖Servlet容器,可以在Java任何地方使用,过滤器基于函数回调机制,依赖Servlet容器的生命周期
-
由于拦截器能够更精细地控制业务流程,它通常用于登录验证、权限检查、日志记录等业务相关的增强处理。过滤器则更多用于通用的功能,如字符编码过滤、安全过滤、性能监控等。
Spring常用注解
声明 bean 的注解
@Component:泛指各种组件
@Controller、@Service、@Repository 都可以称为@Component
@Controller:控制层
@Service:业务层
@Repository:数据访问层
Bean 的生命周期属性
@Scope 设置类型包括:设置 Spring 容器如何新建 Bean 实例
singleton:单例,一个 Spring 容器中只有一个 bean 实例,默认模式
protetype:每次调用新建一个 bean
request:web 项目中,给每个 http request 新建一个 bean
session:web 项目中,给每个 http session 新建一个 bean
globalSession:给每一个 global http session 新建一个 Bean 实例
SpringMVC 常用注解
@RestController : 该 注 解 为 一 个 组 合 注 解 , 相 当 于 @Controller 和@ResponseBody 的组合,注解在类上,意味着,该 Controller 的所有方法都默认加上了@ResponseBody。
@RequestMapping:用于映射 web 请求,包括访问路径和参数
@ResponseBody:支持将返回值放到 response 内,而不是一个页面,通常用户返回 json 数据
@RequestBody:允许 request 的参数在 request 体中,而不是在直接连接的地址后面