有关springboot的一些理解
springboot
概念
spring:Spring是一个分层的轻量级java开源框架,是为了解决企业应用开发的复杂性而创建的。其分层架构允许使用者自由选择使用哪一个组件;独立于各种应用服务器;ICO机制降低了业务对象替换的复杂性,提高了组件之间的解耦;AOP支持允许将一些通用任务如安全、事务、日志等进行集中式管理,从而提供了更好的复用;ORM与第三方持久层框架的良好整合,并简化了底层的数据库访问。
springboot是spring项目的脚手架,其能够快速构建spring项目,不再需要一些对应用程序的xml文件配置,其自带许多硬件设备的驱动。其核心是约定大于配置理念,即减少人为配置,尽量采用默认的配置即可。springBoot专注于微服务方面的接口开发,和前端解耦。
spingboot和spring比较:
- SpringBoot遵循约定大于配置原则,通过自动化配置减少了Spring项目中的XML和Java配置。
- SpringBoot通过引入start依赖,可以自动化引入项目所需的依赖,避免手动添加依赖项,且可以快速启动应用
- SpringBoot通过提供各种默认配置和开箱即用的功能,极大简化了开发过程,减少了样板代码的编写
- springBoot专注于微服务方面的接口开发,和前端解耦。
spring boot默认的配置文件必须是,也只能是application.命名的yml文件或者properties文件,且唯一,默认只会去src-main-resources文件夹下去找application配置文件。
配置文件优先级 .properties > .yml >.yaml
spring boot注解代替 xml,是指使用 @Configuration 修饰配置类,在配置类中进行 bean 声明;注解 @ComponentScan 默认扫描当前修饰类的 package,将 @Component 修饰的类创建为 bean 放入容器中;注解 @PropertySource 用来引入 properties 资源文件,引入后应用中通过 @Value、@ConfigurationProperties 获取值;注解 @Import 用来引入 @Configuration,ImportSelector 或 ImportBeanDefinitionRegistrar 修饰的配置类;注解 @ImportResource 用来引入 xml 配置文件;
Spring的核心即为AOP和IOC
AOP
AOP (Aspect Orient Programming),直译过来就是 面向切面编程,AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向切面编程,实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术。
应用场景:
- 日志记录
- 事务管理
- 权限验证
- 性能监测
核心概念:
- Joinpoint(连接点):可以被拦截的点,spring中一般指被标注可拦截的方法。
- Pointcut(切入点):属于Joinpoint,指要被拦截的点,即符合某种规则从Joinpoint筛选出的特定的连接点。
- Advice(通知):拦截了Pointcut后在Pointcut上执行的增强处理,即需要额外执行的内容。
- Target(目标):目标类,被代理的对象,真正执行的业务逻辑。
- Weaving(织入):把切面应用到目标函数的过程。
- Proxy(代理):代理的对象,即Target的代理对象。(详见超链接)
- Aspect(切面):通常是一个类,定义了切入点和通知。
springAOP的通知有五种:
- @Before(前置通知):在执行目标方法之前运行
- @After(后置通知):在执行目标方法之后运行
- @AfterReturning(返回通知):在目标方法正常返回后运行
- @AfterThrowing(异常通知):在目标方法抛出异常后运行
- @Around(环绕通知):在目标方法执行前后运行,该方法核心参数ProceedingJoinPoint,需要手动执行joinPoint.procced()。详见下例
//切入点 @Pointcut("@annotation(net.keysweb.annotation.GlobalInterceptor)") public void permissionPointcut(){}; //通知 @Around("permissionPointcut()") public Object interceptorDo(ProceedingJoinPoint joinPoint){ try{ //获得目标类 Object target = joinPoint.getTarget(); //获得目标参数 Object[] args = joinPoint.getArgs(); //获得连接点方法名 String methodName = joinPoint.getSignature().getName(); //获得连接点参数类列表 Class<?>[] paramTypes = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes(); //获得连接点方法 Method method = target.getClass().getMethod(methodName,paramTypes); ... //放行 Object pointResult = joinPoint.proceed(); ... }catch(...){ ... } };
IOC
控制反转IoC(Inversion of Control),是一种设计原则,DI(依赖注入)是实现IoC的一种方法
没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,所谓控制反转就是:获得依赖对象的方式反转了。
好处:
- 将逻辑的执行与具体实现解耦。
- 将模块重点放在其功能设计上。
- 将模块从系统解耦出来,无需关心具体实现,取而代之的是依赖引用。
- 防止更换模块时产生影响。
IOC容器
SpringIOC的实现是用SpringIOC容器来管理实例化对象,SpringIOC容器是一个管理Bean的容器,在Spring的定义里,所有IoC容器都要实现接口BeanFactory
package org.springframework.beans.factory; import org.springframework.beans.BeansException; import org.springframework.core.ResolvableType; import org.springframework.lang.Nullable; public interface BeanFactory { //前缀 String FACTORY_BEAN_PREFIX = "&"; //多个getBean方法 Object getBean(String var1) throws BeansException; <T> T getBean(String var1, Class<T> var2) throws BeansException; Object getBean(String var1, Object... var2) throws BeansException; <T> T getBean(Class<T> var1) throws BeansException; <T> T getBean(Class<T> var1, Object... var2) throws BeansException; <T> ObjectProvider<T> getBeanProvider(Class<T> var1); <T> ObjectProvider<T> getBeanProvider(ResolvableType var1); //是否包含Bean boolean containsBean(String var1); //Bean是否为单例 boolean isSingleton(String var1) throws NoSuchBeanDefinitionException; //Bean是否为原型 boolean isPrototype(String var1) throws NoSuchBeanDefinitionException; //是否类型匹配 boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException; //获取Bean的类型 @Nullable Class<?> getType(String var1) throws NoSuchBeanDefinitionException; @Nullable Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException; //获取Bean的别名 String[] getAliases(String var1); }
源码里有多个getBean方法,有按类型获取Bean的,有按名称获取Bean的。需注意,Spring默认为单例Bean。
具体注入过程详见下文springboot的启动过程
使用@Autowired会根据属性找到对应的Bean并注入。但是当我们需要注入的是接口类,且该接口类有多个实现类时,就会产生歧义
@Primary告诉IoC容器,当有多个同类型的Bean时,优先使用我注入
@Primary可能修饰多个类,此时就不能单用@Primary来消除歧义,@Qualifier的配置项value需要一个字符串定义,这样Autowired就会通过类型和名称一起找到Bean
拦截器和过滤器
触发 | 实现 | 依赖 | 生命周期 | 作用范围 | 其他 | |
拦截器 Inteceptor | 进入Servlet后 | 基于反射(AOP) | 独立 | IOC容器管理 | 可具体到方法 | 由spring管理,可调用IOC容器依赖 |
过滤器 Filter | 进入Servlet前 | 基于回调函数 | Servlet | Servlet容器管理 | 请求前后 |
使用场景:
拦截器:登录验证、权限验证、日志记录、性能监控、cookie处理等等。
过滤器:过滤请求参数、设置字符编码、URL级别权限访问控制、压缩响应信息等等。
start依赖
在Spring Boot中,Starter是一种自包含的、可重用的依赖项集合,用于快速启动特定类型的应用程序。它们是预配置的依赖项,包含了您构建应用程序所需的所有必要组件和配置。
start通常包括:
- Spring Boot的自动配置
- 必需的依赖项
- 特定于功能的依赖项
例如最常见的spring-boot-starter-web,使用@SpringBootApplication注解就能快速启动spring应用(具体详见下面springboot启动过程)。
当您使用spring-boot-starter-web时,Spring Boot会自动配置Tomcat服务器和Spring MVC框架,无需手动添加配置文件。
spring-boot-starter-web有许多必须的依赖以启动SpringBoot项目,例如Spring框架、Spring Boot框架等,这些依赖项是构建应用程序的基础,没有它们就无法构建应用程序。
Starter中还包含了特定于功能的依赖项,例如spring-boot-starter-data-jpa用于在Spring Boot应用程序中使用JPA和Hibernate、spring-boot-starter-test用于在Spring Boot应用程序中进行单元测试等。这些依赖项是用于实现特定功能的,可以根据需要添加相应的依赖项。
作用:
使用Starter的好处在于可以显著简化应用程序的依赖管理,避免手动添加依赖项,同时也可以更快地启动应用程序。
此外,Starter还可以使应用程序更加可读和模块化,因为它们明确指定了应用程序中包含的功能。
SpringBoot启动过程
SpringBoot启动类如下:
@SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
注意,虽然启动类是DemoApplication,但是SpringApplication.run传入的配置类可以不是DemoApplication,run传入的配置类决定了springboot的默认扫描路径,即该配置类路径下的所有包。@SpringBootApplication注解的核心是 @Configuration、@EnableAutoConfiguration、@ComponentScan三个注解,
其中
- @Configuration:代表这是一个Java配置类
- @ComponentScan:扫描被@Component (@Service、@Controller、@Mapper等)注解的 Bean,该扫描路径即刚才提到的传入的配置类的路径,因此我们只需在项目中对应的类上加上 @Service、@Controller、@Mapper等即可将其交给IoC容器管理
- @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
@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 { //通过类型排除自动装配类 @AliasFor( annotation = EnableAutoConfiguration.class ) Class<?>[] exclude() default {}; //通过名称排除自动装配类 @AliasFor( annotation = EnableAutoConfiguration.class ) String[] excludeName() default {}; //定义扫描包 @AliasFor( annotation = ComponentScan.class, attribute = "basePackages" ) String[] scanBasePackages() default {}; //定义被扫描的类 @AliasFor( annotation = ComponentScan.class, attribute = "basePackageClasses" ) Class<?>[] scanBasePackageClasses() default {}; @AliasFor( annotation = ComponentScan.class, attribute = "nameGenerator" ) Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; @AliasFor( annotation = Configuration.class ) boolean proxyBeanMethods() default true; }
在run方法中springboot执行了许多操作,包括启动web服务器(默认为tomcat)并设置springmvc等操作。期间对于所有jar包中的自带配置类(AutoConfig),SpringBoot会去扫描引入的jar包中的META-INFO文件中的spring.factories文件(在该文件中,会以key-value的形式去标出配置类文件的引用路径)和spring-autoconfigure-metadata.properties文件(该文件以key-value的形式去标出核心配置类,以方便springboot快速判断这些类是否能被正确加载,从而去成功引入对应的配置类),springboot通过类加载器(classLoader)去将这些路径以map的方式储存并使用,从而达到自动配置的效果。
Spring缓存
对于spring bean还分一级缓存,二级缓存和三级缓存,在 Spring 容器中,每次请求获取一个 bean 时,Spring 首先检查一级缓存、二级缓存和三级缓存中是否已经存在该 bean,如果存在,则直接返回缓存中的实例对象,否则才进行 bean 的创建。
-
singletonObjects 缓存:一级缓存,也称为“单例池”,用于存储所有单例 bean 的实例对象。当第一次需要获取一个单例 bean 时,Spring 会先检查一级缓存中是否已经存在该 bean 实例,如果存在,则直接返回该实例,否则 Spring 会根据 bean 的定义信息创建一个新的实例,并将其放入一级缓存中。
-
earlySingletonObjects 缓存:二级缓存,也称为“早期单例对象池”,用于存储正在创建过程中的单例 bean 实例。在单例 bean 的创建过程中,如果发现该 bean 依赖于其他的 bean,则需要先创建该依赖的 bean 实例。此时,Spring 会将该 bean 提前实例化,并将其放入二级缓存中。当依赖的 bean 实例创建完成后,Spring 会将其注入到该 bean 实例中,并从二级缓存中移除。
-
singletonFactories 缓存:三级缓存,也称为“单例工厂池”,用于存储用于创建单例 bean 的 ObjectFactory。在创建单例 bean 时,如果发现该 bean 依赖于其他的 bean,则需要先创建该依赖的 bean 实例,此时 Spring 会将用于创建该依赖的 ObjectFactory 保存到三级缓存中。当依赖的 bean 实例创建完成后,Spring 会使用该 ObjectFactory 创建该 bean 实例,并从三级缓存中移除。
二级缓存和三级缓存的区别:
- 存储对象的方式不同:二级缓存中存储的是正在创建的 bean 实例,而三级缓存中存储的是用于创建 bean 实例的 ObjectFactory 对象;
- 使用时机不同:二级缓存主要用于处理循环依赖的情况,即当两个或多个 bean 互相依赖,且都是单例时,需要借助二级缓存来解决循环依赖问题;而三级缓存则主要用于处理单例 bean 中存在 prototype 类型依赖的情况,即当一个单例 bean 依赖于一个原型(prototype)bean 时,需要借助三级缓存来创建该依赖项的实例。
注:单例bean Spring bean默认单例,维护在springboot容器中重复使用
原型bean 每次使用到该bean,都是Spring去重新帮你去进行创建的(可使用@Scope(value = BeanDefinition.SCOPE_PROTOTYPE)注解去声明
)
注:此图中提前暴露的是一个单例工厂,二级缓存中存储的就是从这个工厂中获取到的对象
需注意:
- 从2.6版本开始,如果你的项目里还存在循环依赖,SpringBoot将拒绝启动!
- 构造器的循环依赖无法解决
springmvc
MVC
MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。
- 是将业务逻辑、数据、显示分离的方法来组织代码。
- MVC主要作用是降低了视图与业务逻辑间的双向偶合。
- MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。
概念
Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。SpringMVC , 简单 , 便捷 , 易学 , 天生和Spring无缝集成(使用SpringIoC和Aop) , 使用约定优于配置 . 能够进行简单的junit测试 . 支持Restful风格 .异常处理 , 本地化 , 国际化 , 数据验证 , 类型转换 , 拦截器 等等…
本文部分为个人理解,仅供参考
参考文章:https://blog.csdn.net/qq_38939822/article/details/124258258
https://blog.csdn.net/cyx_159/article/details/131516933