• Swagger 介绍和使用
    使用 Swagger 你只需要按照它的规范去定义接口及接口相关的信息,就可以做到生成接口文档,以及在线接口调试页面官网: swagger.io/ Knife4j 是为 Java MVC 框架集成 Swagger 生成 Api 文档的增强解决方案  使用方式 1. 导入坐标 <dependency>     <groupId>com.github.xiaoymin</groupId>     <artifactId>knife4j-spring-boot-starter</artifactId> </dependency> 2. 在配置类中加入 knife4j 相关配置     /**      * 通过knife4j生成接口文档      * @return      */     @Bean     public Docket docket() {         ApiInfo apiInfo = new ApiInfoBuilder()                 .title("苍穹外卖项目接口文档")                 .version("2.0")                 .description("苍穹外卖项目接口文档")                 .build();         Docket docket = new Docket(DocumentationType.SWAGGER_2)                 .apiInfo(apiInfo)                 .select()                 .apis(RequestHandlerSelectors.basePackage("com.sky.controller"))                 .paths(PathSelectors.any())                 .build();         return docket;     } 3. 设置静态资源映射,否则接口文档页面无法访问     /**      * 设置静态资源映射      * @param registry      */     protected void addResourceHandlers(ResourceHandlerRegistry registry) {         registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");         registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");     } 常用注解  查看效果 启动项目后访问如下地址: localhost:8080/doc.html  成功 附完整配置类代码: package com.sky.config;import com.sky.interceptor.JwtTokenAdminInterceptor;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;/** * 配置类,注册web层相关组件 */@Configuration@Slf4jpublic class WebMvcConfiguration extends WebMvcConfigurationSupport { @Autowired private JwtTokenAdminInterceptor jwtTokenAdminInterceptor; /** * 注册自定义拦截器 * * @param registry */ protected void addInterceptors(InterceptorRegistry registry) { log.info("开始注册自定义拦截器..."); registry.addInterceptor(jwtTokenAdminInterceptor) .addPathPatterns("/admin/**") .excludePathPatterns("/admin/employee/login"); } /** * 通过knife4j生成接口文档 * @return */ @Bean public Docket docket() { log.info("准备生成接口文档..."); ApiInfo apiInfo = new ApiInfoBuilder() .title("苍穹外卖项目接口文档") .version("2.0") .description("苍穹外卖项目接口文档") .build(); Docket docket = new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo) .select() .apis(RequestHandlerSelectors.basePackage("com.sky.controller")) .paths(PathSelectors.any()) .build(); return docket; } /** * 设置静态资源映射 * @param registry */ protected void addResourceHandlers(ResourceHandlerRegistry registry) { log.info("开始设置静态资源映射..."); registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); }} 转载自https://learnku.com/articles/85427
  • [技术干货] Spring家族
    大家应该都知道,按照出现的顺序,spring全家桶大概包含了spring、springmvc、springboot以及springcloud,从开胃小菜spring到满汉全席springcloud,spring全家桶可谓Java工程师的必备大餐,那么,我们不妨先来看看,spring全家桶是如何从光杆司令spring发展到如今的庞大家族的。 想要精通Spring的你,不妨来翻一翻这份大神整理出来的367页PDF,我想这应该是对“Spring家族”最完美的诠释了。  Key1:攻克Spring5 ①Spring-手绘脑图 (基本概念+AOP+事务管理+IOC+MVC+Spring类等) ②Spring5高级编程 ③Spring源码解析 第一部分:核心实现(Spring整体架构和环境搭建+容器的基本实现+默认标签的解析+自定义标签的解析+bean的加载+容器的功能扩展+AOP) 第二部分:企业应用(数据库连接JDBC+整合MyBatis+事务+SpringMVC+远程服务+Spring消息) ④Spring源码笔记 (Spring概述+核心思想+手写实现IOC和AOP+SpringIOC应用+SpringIOC源码深度剖析+SpringAOP应用+SpringAOP源码深度剖析) ⑤Spring面试题(高级应用篇) 什么是Spring 框架?Spring 框架有哪些主要模块? 使用 Spring 框架能带来哪些好处? 什么是控制反转(IOC)?什么是依赖注入? 请解释下 Spring 框架中的 IoC? BeanFactory 和 ApplicationContext 有什么区别? Spring 有几种配置方式? 如何用基于 XML 配置的方式配置 Spring? 如何用基于 Java 配置的方式配置 Spring? 怎样用注解的方式配置 Spring? 请解释 Spring Bean 的生命周期? Spring Bean 的作用域之间有什么区别? 什么是 Spring inner beans? Spring 框架中的单例 Beans 是线程安全的么? 请举例说明如何在 Spring 中注入一个 Java Collection? 如何向 Spring Bean 中注入一个 Java.util.Properties? 请解释 Spring Bean 的自动装配? 请解释一下自动装配模式的区别? 如何开启基于注解的自动装配? 请举例解释@Required 注解? 请举例解释@Autowired 注解? 请举例说明@Qualifier 注解? 构造方法注入和设值注入有什么区别? Spring 框架中有哪些不同类型的事件? FileSystemResource 和 ClassPathResource 有何区别? Spring 框架中都用到了哪些设计模式? 开发中主要使用 Spring 的什么技术 ? 简述 AOP 和 IOC 概念 AOP 在 Spring 中如何配置 Bean ? IOC 容器对 Bean 的生命周期 答案: Key2:攻克Spring Boot ①Spring Boot-手绘脑图 ②Spring Boot实战 (入门+开发的第一个应用程序+自定义配置+测试+Groovy与Spring Boot CLI+在Spring Boot中使用Grails+深入Actuator+部署Spring Boot应用程序) ③Spring Boot 学习笔记-核心部分 (Spring Boot入门+配置文件+日志+Web开发+Docker+SpringBoot与数据访问+启动配置原理+自定义starter) ④Spring Boot面试题(高级应用篇) 什么是 Spring Boot? Spring Boot 有哪些优点? 什么是 JavaConfig? 如何重新加载 Spring Boot 上的更改,而无需重新启动服务器? Spring Boot 中的监视器是什么? 如何在 Spring Boot 中禁用 Actuator 端点安全性? 如何在自定义端口上运行 Spring Boot 应用程序? YAML 是一种人类可读的数据序列化语言。它通常用于配置文件。 如何实现 Spring Boot 应用程序的安全性? 如何集成 Spring Boot 和 ActiveMQ? 如何使用 Spring Boot 实现分页和排序? 什么是 Swagger?你用 Spring Boot 实现了它吗? 什么是 Spring Profiles? 什么是 Spring Batch? 什么是 FreeMarker 模板? 如何使用 Spring Boot 实现异常处理? 您使用了哪些 starter maven 依赖项? 什么是 CSRF 攻击? 什么是 WebSockets? 什么是 AOP? 什么是 Apache Kafka? 我们如何监视所有 Spring Boot 微服务? 答案: Key3:攻克Spring MVC ①Spring MVC-手绘脑图 ②Spring MVC源码分析与实践 (Spring框架+模型2和MVC模式+SpringMVC介绍+基于注解的控制器+数据绑定和表单标签库+转换器和格式化+验证器+表达式语言+JSTL+国际化+上传文件+下载文件+应用测试) ③Spring MVC学习笔记 ④Spring MVC面试题(高级应用篇) 什么是 SpringMVC? 说说Spring MVC 的优点 SpringMVC 工作原理 SpringMVC 流程 SpringMvc 的控制器是不是单例模式,如果是,有什么问题,怎么解决? 如果你也用过 struts2.简单介绍下 springMVC 和 struts2 的区别有哪些? SpingMVC 中的控制器的注解一般用哪个,有没有别的注解可以替代? @RequestMapping 注解用在类上面有什么作用? 怎么样把某个请求映射到特定的方法上面? 如果在拦截请求中,我想拦截 get 方式提交的方法,怎么配置? 怎么样在方法里面得到 Request,或者 Session? 我想在拦截的方法里面得到从前台传入的参数,怎么得到? 如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象? SpringMVC 中函数的返回值是什么? SpringMVC 怎么样设定重定向和转发的? SpringMVC 用什么对象从后台向前台传递数据的? SpringMVC 中有个类把视图和数据都合并的一起的,叫什么? 怎么样把 ModelMap 里面的数据放入 Session 里面? SpringMVC 怎么和 AJAX 相互调用的? 当一个方法向 AJAX 返回特殊对象,比如 Object,List 等,需要做什么处理? SpringMVC 里面拦截器是怎么写的? 讲下 SpringMVC 的执行流程  面试: Key4:攻克Spring Cloud ①Spring Cloud-手绘脑图 ②Spring Cloud参考指南 ③Spring Cloud学习笔记  第一篇:基础服务篇(微服务与SpringCloud+服务发现+配置中心+客户端负载均衡+熔断器+Zuul+网关新选择+调用链追踪+加密管理+公共子项目) 第二篇:任务与消息篇(消息驱动+消息总线+批处理) 第三篇:微服务实战篇(利用Docker进行编排与整合) ④Spring Cloud面试题(高级应用篇) 什么是 Spring Cloud? 使用 Spring Cloud 有什么优势? 服务注册和发现是什么意思?Spring Cloud 如何实现? 负载平衡的意义什么? 什么是 Hystrix?它如何实现容错? 什么是 Hystrix 断路器?我们需要它吗? 什么是 Netflix Feign?它的优点是什么? 什么是 Spring Cloud Bus?我们需要它吗? ———————————————— 原文链接:https://blog.csdn.net/weixin_66896902/article/details/126464926 
  • [技术干货] spring全家桶
    1、spring是一个容器、生态、框架 Spring框架为开发提供了一系列的解决方案,比如利用控制反转的核心特性,并通过依赖注入实现控制反转来实现管理对象生命周期容器化,利用面向切面编程进行声明式的事务管理,整合多种持久化技术管理数据访问,提供大量优秀的Web框架方便开发等等。Spring框架具有控制反转(IOC)特性,IOC旨在方便项目维护和测试,它提供了一种通过Java的反射机制对Java对象进行统一的配置和管理的方法。Spring框架利用容器管理对象的生命周期,容器可以通过扫描XML文件或类上特定Java注解来配置对象,开发者可以通过依赖查找或依赖注入来获得对象。Spring框架具有面向切面编程(AOP)框架,SpringAOP框架基于代理模式,同时运行时可配置;AOP框架主要针对模块之间的交叉关注点进行模块化。Spring框架下的事务管理、远程访问等功能均可以通过使用SpringAOP技术实现。  spring首先是一个框架,在我们整个开发流程中,所有的框架生产几乎全都依赖于spring,spring帮我们起到了一个IOC容器的作用,用来承载整体的bean对象,帮我们进行了对象的创建到销毁的整个生命周期的管理。在使用spring的时候可以使用配置文件也可以使用注解的方式来进行相关实现,在程序启动后,把配置文件或者注解定义好的那些bean对象转换成beanDefination,要完成整个beanDefination的解析到加载的过程,获得完整的对象之后,下一步要对beanDefination进行实例化操作,在进行实例化的时候最简单的方式是使用反射的方式来创建对象,当对象创建完成之后,之后要实现Aware、BeanPostProcessor接口的一些操作,初始化对象的一些操作  1.1IOC容器(存放bean对象) IOC(Inversion of Control): IOC容器控制管理bean对象,实现解耦。 控制翻转,其根本是依赖注入(Dependecy Injection),不会直接创建对象,只是把对象声明出来,在代码 中不直接与对象和服务进行连接,但是在配置文件中描述了哪一项组件需要哪一项服务,容器将他们组合起来。在一般的IOC场景中容器创建了所有的对象,并设置了必要的属性将他们联系在一起,等到需要使用的时候才把他们声明出来,使用注解就更方便了,容器会自动根据注 解把对象组合起来。  是我们在使用spring中最重要的一个方面,spring容器里面放的是一个一个的bean对象,spring在启动时通过BeanDefinitionReader读取XML配置文件或者注解(bean的定义信息)获取bean对象:  下图说明: BeanDefinitionReader将配置文件信息解析成BeanDefinition(有$占位符), BeanFactoryPostProcessor将此信息在解析成完整的BeanDefinition对象(将信息传入,去掉$占位符) 1 2 3  1.1.2 bean生命周期(复杂) 1)Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化,在堆开辟新空间,使用反射实现对象的实例化  2)Bean实例化后对将Bean的引入和值注入到Bean的属性中  3)如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法  4)如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入  5)如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。  6)如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。  7)如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用  8)如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。  9)此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。  10)如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。  参考文档:https://www.cnblogs.com/javazhiyin/p/10905294.html  1.1.3 bean生命周期(简单): 实例化 Instantiation 属性赋值 Populate 初始化 Initialization 销毁 Destruction 1)实例化(Instantiation) //实例化是指Bean 从Bean到Object Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);  2)属性赋值(Populate)  3)初始化(Initialization) 初始化前: org.springFrameWork.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization 初始化中: org.springFrameWork.bean.InitializingBean#afterPropertiesSet 初始化后:org.springFrameWork.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization  4)销毁  参考文档:https://www.jianshu.com/p/1dec08d290c1  1.2 AOP面向切面编程 AOP:面向切面编程,底层实现是动态代理(JDK、CGlib)  web层级设计中,web层->网关层->服务层->数据层,每一层之间也是一个切面。编程中,对象与对象之间,方法与方法之间,模块与模块之间都是一个个切面。 将方法注入到接口调用的某个地方(切点)。  1.2.1 相关概念: 1)Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。 2)Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。 3)Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。 4)Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。 5)Target(目标对象):织入 Advice 的目标对象.。 6)Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程  参考文档:https://blog.csdn.net/q982151756/article/details/80513340  1.3 JdbcTemplate JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用。JdbcTemplate是Spring的一部分。JdbcTemplate处理了资源的建立和释放。  在JdbcTemplate中执行SQL语句的方法大致分为3类: 1)execute:可以执行所有SQL语句,一般用于执行DDL语句。 2)update:用于执行INSERT、UPDATE、DELETE等DML语句。 3)queryXxx:用于DQL数据查询语句。  1.4 事物 1.4.1、事物的特性 1.4.1.1、原子性(Atomicity): 事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。  1.4.1.2、一致性(Consistency): 一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。  1.4.1.3、隔离性(Isolation): 可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。  1.4.1.4、持久性(Durability): 一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。  1.4.2、spring事物配置方式 1)编程式事物管理:是侵入性事务管理,使用TransactionTemplate或者直接使用PlatformTransactionManager,对于编程式事务管理,Spring推荐使用TransactionTemplate。 2)声明式事物管理:建立在AOP之上,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。  声明式事务管理要优于编程式事务管理:声明式事务属于无侵入式,不会影响业务逻辑的实现,只需要在配置文件中做相关的事务规则声明或者通过注解的方式,便可以将事务规则应用到业务逻辑中。  1.4.3、事物的隔离级别  参考文档:https://www.cnblogs.com/mseddl/p/11577846.html  1.5 循环依赖 循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。  Spring中循环依赖场景有: (1)构造器的循环依赖 (2)field属性的循环依赖。  1.5.1、检测是否存在循环依赖 Bean在创建的时候可以给该Bean打标,如果递归调用回来发现正在创建中的话,即说明了循环依赖了。  1.5.2、spring解决循环依赖 Spring为了解决单例的循环依赖问题,使用了三级缓存。  这三级缓存分别指: singletonFactories : 单例对象工厂的cache earlySingletonObjects :提前暴光的单例对象的Cache singletonObjects:单例对象的cache。  参考文档:https://blog.csdn.net/u010853261/article/details/77940767  2、SpringMVC 2.1、springMVC简介 M:model,模型层,模型就是数据 V:view,网页、jsp,显示数据 C:controller,控制层,控制器的作用就是把不同的数据(Model),显示在不同的视图(View)上,Servlet 扮演的就是这样的角色。  Spring MVC主要由DispatcherServlet、处理器映射、处理器(控制器)、视图解析器、视图组成。 他的两个核心是两个核心: 1)处理器映射:选择使用哪个控制器来处理请求 2)视图解析器:选择结果应该如何渲染  2.1.1、运行原理  (1) Http请求:客户端请求提交到DispatcherServlet。 (2) 寻找处理器:由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller。 (3) 调用处理器:DispatcherServlet将请求提交到Controller。 (4)调用业务处理和返回结果:Controller调用业务逻辑处理后,返回ModelAndView。 (5)处理视图映射并返回模型: DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图。 (6) Http响应:视图负责将结果显示到客户端。  2.1.2、SpringMVC接口解释 (1)DispatcherServlet接口: Spring提供的前端控制器,所有的请求都有经过它来统一分发。在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。  (2)HandlerMapping接口: 能够完成客户请求到Controller映射。  (3)Controller接口: 需要为并发用户处理上述请求,因此实现Controller接口时,必须保证线程安全并且可重用。 Controller将处理用户请求,这和Struts Action扮演的角色是一致的。一旦Controller处理完用户请求,则返回ModelAndView对象给DispatcherServlet前端控制器,ModelAndView中包含了模型(Model)和视图(View)。 从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观考虑,Controller是单个Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型(Model)和视图(View)。  (4)ViewResolver接口: Spring提供的视图解析器(ViewResolver)在Web应用中查找View对象,从而将相应结果渲染给客户。  2.1.3、DispatcherServlet: 是整个Spring MVC的核心。它负责接收HTTP请求组织协调Spring MVC的各个组成部分。其主要工作有以下三项: (1)截获符合特定格式的URL请求。 (2)初始化DispatcherServlet上下文对应WebApplicationContext,并将其与业务层、持久化层的WebApplicationContext建立关联。 (3)初始化Spring MVC的各个组成组件,并装配到DispatcherServlet中。  参考文档:https://blog.csdn.net/jianyuerensheng/article/details/51258942  3、springBoot 3.1springboot简介 用来简化spring初始搭建的过程,将配置文件转换成注解的形式,方便迅速。Spring Boot 提供了大量开箱即用(out-of-the-box)的依赖模块,例如 spring-boot-starter-redis、spring-boot-starter-data-mongodb 和 spring-boot-starter-data-elasticsearch 等。这些依赖模块为 Spring Boot 应用提供了大量的自动配置,使得 Spring Boot 应用只需要非常少量的配置甚至零配置,便可以运行起来。  3.2、特点 1)独立运行的 Spring 项目 Spring Boot 可以以 jar 包的形式独立运行,Spring Boot 项目只需通过命令“ java–jar xx.jar” 即可运行。 2) 内嵌 Servlet 容器 Spring Boot 使用嵌入式的 Servlet 容器(例如 Tomcat、Jetty 或者 Undertow 等),应用无需打成 WAR 包 。 3) 提供 starter 简化 Maven 配置 Spring Boot 提供了一系列的“starter”项目对象模型(POMS)来简化 Maven 配置。 4) 提供了大量的自动配置 Spring Boot 提供了大量的默认自动配置,来简化项目的开发,开发人员也通过配置文件修改默认配置。 5) 自带应用监控 Spring Boot 可以对正在运行的项目提供监控。 6) 无代码生成和 xml 配置 Spring Boot 不需要任何 xml 配置即可实现 Spring 的所有配置。 参考文档:http://c.biancheng.net/spring_boot/overview.html  4、springCloud Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的开发便利性简化了分布式系统的开发,比如服务发现、服务网关、服务路由、链路追踪等。Spring Cloud 并不重复造轮子,而是将市面上开发得比较好的模块集成进去,进行封装,从而减少了各模块的开发成本。换句话说:Spring Cloud 提供了构建分布式系统所需的“全家桶”。  4.1、优点: 1)集大成者,Spring Cloud 包含了微服务架构的方方面面。 2)约定优于配置,基于注解,没有配置文件。 3)轻量级组件,Spring Cloud 整合的组件大多比较轻量级,且都是各自领域的佼佼者。 4)开发简便,Spring Cloud 对各个组件进行了大量的封装,从而简化了开发。 5)开发灵活,Spring Cloud 的组件都是解耦的,开发人员可以灵活按需选择组件。  4.2、Spring Cloud 模块的相关介绍: Eureka:服务注册中心,用于服务管理。 Ribbon:基于客户端的负载均衡组件,默认的负载策略是轮询。 Hystrix:容错框架,能够防止服务的雪崩效应。 Feign:Web 服务客户端,能够简化 HTTP 接口的调用。 Zuul:核心是过滤器,API 网关,提供路由转发、请求过滤等功能,是一个基于 JVM 路由和服务端的负载均衡器。 Config:分布式配置管理。 Sleuth:服务跟踪。 Stream:构建消息驱动的微服务应用程序的框架。 Bus:消息代理的集群消息总线。  4.2.1、 服务治理 Eureka 和 Zookeeper 区别: Eureka 是基于 AP 原则构建的,而 ZooKeeper 是基于 CP 原则构建的。  注: 在分布式系统领域有个著名的 CAP 定理,即 C 为数据一致性;A 为服务可用性;P 为服务对网络分区故障的容错性。这三个特性在任何分布式系统中都不能同时满足,最多同时满足两个。  服务治理就是服务的自动化管理,其核心是服务的自动注册与发现 1)服务注册:服务实例将自身服务信息注册到注册中心 2)服务发现:服务实例通过注册中心,获取注册到其中的服务实例的信息,通过这些信息去请求题目提供的服务 3)服务剔除:服务注册中心将出问题的服务自动剔除可使用服务列表,使其不会被调用 参考文档:http://c.biancheng.net/spring_cloud/ 5、SSM Java 企业开发框架 SSM,即 Spring、SpringMVC、MyBatis 。 Spring框架:是一个轻量级 Java 开发框架,主要是为了解决企业应用开发的复杂性而创建的。 SpringMVC框架:SpringMVC 分离了 控制器、模型对象、分派器,让我们更容易进行开发定制 MyBatis框架:是一个 Java 持久层框架,用于操作数据库,消除了几乎所有的 JDBC 代码,使用简单的 XML 或 注解即可完成数据库操作。 ————————————————       原文链接:https://blog.csdn.net/weixin_47268011/article/details/118188608 
  • [技术干货] springcloud综述之springcloud全家桶
    1.1 系统架构演变随着互联网的发展,网站应用的规模也在不断的扩大,进而导致系统架构也在不断的进行变化。系统架构大体经历了下面几个过程: 单体应用架构—>垂直应用架构—>分布式架构—>SOA架构—>微服务架构,当然还有悄然兴起的Service Mesh(服务网格化)。接下来我们就来了解一下每种系统架构是什么样子的, 以及各有什么优缺点。1.1.1 单体应用架构web项目,然后部署到一台tomcat服务器上优点:项目架构简单,小型项目的话, 开发成本低项目部署在一个节点上, 维护方便缺点:全部功能集成在一个工程中,对于大型项目来讲不易开发和维护项目模块之间紧密耦合,单点容错率低无法针对不同模块进行针对性优化和水平扩展1.1.2 垂直应用架构所谓的垂直应用架构,就是将原来的一个应用拆成互不相干的几个应用,以提升效率。这样拆分完毕之后,一旦某个应用用户访问量变大,只需要增加对应应用节点就可以了,而无需增加其他节点。优点:系统拆分实现了流量分担,解决了并发问题,而且可以针对不同模块进行优化和水扩展一个系统的问题不会影响到其他系统,提高容错率缺点:系统之间相互独立, 无法进行相互调用系统之间相互独立, 会有重复的开发任务1.1.3 分布式架构分布式系统架构,它把工程拆分成表现层和服务层两个部分,服务层中包含业务逻辑。表现层只需要处理和页面的交互,业务逻辑都是调用服务层的服务来实现。优点:抽取公共的功能为服务层,提高代码复用性缺点:系统间耦合度变高,调用关系错综复杂,难以维护1.1.4 SOA架构增加一个调度中心对集群进行实时管理。此时,用于资源调度和治理中心(SOA Service OrientedArchitecture,面向服务的架构)是关键。优点:使用注册中心解决了服务间调用关系的自动调节缺点:服务间会有依赖关系,一旦某个环节出错会影响较大( 服务雪崩 )服务关心复杂,运维、测试部署困难1.1.5 微服务架构微服务架构在某种程度上是面向服务的架构SOA继续发展的下一步,它更加强调服务的"彻底拆分"。优点:服务原子化拆分,独立打包、部署和升级,保证每个微服务清晰的任务划分,利于扩展微服务之间采用Restful等轻量级http协议相互调用缺点:分布式系统开发的技术成本高(容错、分布式事务等)1.2 微服务架构介绍微服务架构, 简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目。1.2.1 微服务架构的常见问题一旦采用微服务系统架构,就势必会遇到这样几个问题:这么多小服务,如何管理他们?(服务治理 注册中心[服务注册 发现 剔除])这么多小服务,他们之间如何通讯?(restful rpc)这么多小服务,客户端怎么访问他们?(网关)这么多小服务,一旦出现问题了,应该如何自处理?(容错)这么多小服务,一旦出现问题了,应该如何排错? (链路追踪)对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。常见的微服务组件及发展趋势1.2.2 微服务架构的常见概念1.2.2.1 服务治理服务治理就是进行服务的自动化管理,其核心是服务的自动注册与发现。服务注册:服务实例将自身服务信息注册到注册中心。服务发现:服务实例通过注册中心,获取到注册到其中的服务实例的信息,通过这些信息去请求它们提供的服务。服务剔除:服务注册中心将出问题的服务自动剔除到可用列表之外,使其不会被调用到。1.2.2.2 服务调用在微服务架构中,通常存在多个服务之间的远程调用的需求。目前主流的远程调用技术有基于HTTP的RESTful接口以及基于TCP的RPC协议。(Representational State Transfer)这是一种HTTP调用的格式,更标准,更通用,无论哪种语言都支持http协议RPC(Remote Promote Call)一种进程间通信方式。允许像调用本地服务一样调用远程服务。RPC框架的主要目标就是让远程服务调用更简单、透明。RPC框架负责屏蔽底层的传输方式、序列化方式和通信细节。开发人员在使用的时候只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节和调用过程。区别与联系比较项 RESTful RPC通讯协议 HTTP 一般使用TCP性能 略低 较高灵活度 高 低应用 微服务架构 SOA架构1.2.2.3 服务网关随着微服务的不断增多,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信可能出现:客户端需要调用不同的url地址,增加难度在一定的场景下,存在跨域请求的问题每个微服务都需要进行单独的身份认证针对这些问题,API网关顺势而生。API网关直面意思是将所有API调用统一接入到API网关层,由网关层统一接入和输出。一个网关的基本功能有:统一接入、安全防护、协议适配、流量管控、长短链接支持、容错能力。有了网关之后,各个API服务提供团队可以专注于自己的的业务逻辑处理,而API网关更专注于安全、流量、路由等问题。1.2.2.4 服务容错在微服务当中,一个请求经常会涉及到调用几个服务,如果其中某个服务不可用,没有做服务容错的话,极有可能会造成一连串的服务不可用,这就是雪崩效应。我们没法预防雪崩效应的发生,只能尽可能去做好容错。服务容错的三个核心思想是:不被外界环境影响不被上游请求压垮不被下游响应拖垮1.2.2.5 链路追踪随着微服务架构的流行,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心。因此,就需要对一次请求涉及的多个服务链路进行日志记录,性能监控即链路追踪1.2.3 微服务架构的常见解决方案1.2.3.1 ServiceCombApache ServiceComb,前身是华为云的微服务引擎 CSE (Cloud Service Engine) 云服务,是全球首个Apache微服务顶级项目。它提供了一站式的微服务开源解决方案,致力于帮助企业、用户和开发者将企业应用轻松微服务化上云,并实现对微服务应用的高效运维管理。1.2.3.2 SpringCloudSpring Cloud是一系列框架的集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。SpringCloud提供的全生态的分布式组件支持,netflex系列服务注册发现:Eureka(其他选择: Consul,Zookeeper,Nacos,Etcd)负载均衡:Robbin(声明式调用:Fegin)断路器:Hystrix网关:Zuul2,Spring Cloud Gateway配置中心:Spring Cloud Config监控:Spring Boot Admin,Spring Boot Actuator链路跟踪:Spring Cloud Sleuth三、组件介绍1、Eureka(1)体系划分Eureka是SpringCloud官方推荐的服务注册发现组件。Eureka的角色和Dubbo中Zookeeper的角色类似,体系划分如下,业务上可以分为:服务注册中心、服务提供者、服务消费者。代码逻辑上分为:Eureka Server 和 Eureka Client。(2)结构原理两台Eureka服务注册中心构成的服务注册中心的主从复制集群;然后服务提供者向注册中心进行注册、续约、下线服务等;服务消费者向Eureka注册中心拉去服务列表并维护在本地;然后服务消费者根据从Eureka服务注册中心获取的服务列表选取一个服务提供者进行消费服务。(3)Eureka 集群(三节点,两两注册)从图中可以看出 Eureka Server 集群相互之间通过 Replicate 来同步数据,相互之间不区分主节点和从节点,所有的节点都是平等的。在这种架构中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点。如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点。当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会进行节点间复制,将请求复制到其它 Eureka Server 当前所知的所有节点中。Eureka Server 集群之间的状态是采用异步方式同步的,所以不保证节点间的状态一定是一致的,不过基本能保证最终状态是一致的(Eureka保证AP,Zookeeper强调CP)。2、Robbin(1)客户端的软负载Robbin是springcloud的LB调用组件,提供客户端的软件负载均衡。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。Robbin 提供的客户端软负载,是SpringCloud微服务的典型特征之一。(2)负载均衡策略轮询(RoundRobin),以轮询的方式依次将请求调度不同的服务器,即每次调度执行i = (i + 1) mod n,并选出第i台服务器。随机(Random),随机选择状态为UP的Server。加权响应时间(WeightedResponseTime),根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。区域感知轮询(ZoneAvoidanceRule),复合判断server所在区域的性能和server的可用性选择server。(3)核心组件Ribbon的核心组件(均为接口类型)有以下几个,ServerList,用于获取地址列表。它既可以是静态的(提供一组固定的地址),也可以是动态的(从注册中心中定期查询地址列表)。ServerListFilter,仅当使用动态ServerList时使用,用于在原始的服务列表中使用一定策略过虑掉一部分地址。IRule,选择一个最终的服务地址作为LB结果。选择策略有轮询、根据响应时间加权、断路器(当Hystrix可用时)等。Ribbon在工作时首选会通过ServerList来获取所有可用的服务列表,然后通过ServerListFilter过虑掉一部分地址,最后在剩下的地址中通过IRule选择出一台服务器作为最终结果。3、FeginFegin是一个声明式Http端调用,集成了Robbin的负载均衡功能,同时声明式调用更加方便(只需要简单的注解即可)。简单的可以理解为:Spring Cloud Feign 的出现使得Eureka和Ribbon的使用更加简单。(1)Fegin接口示例a、启动类 @EnableFeignClients 注解@SpringBootApplication@EnableEurekaClient@EnableFeignClients // 启用fegin声明式调用public class FeginComsumerApplication {public static void main(String[] args) {SpringApplication.run(FeginComsumerApplication.class, args);}}b、声明一个调用的Feign接口,@Service@FeignClient(name = "name-service")public interface NameService {@RequestMapping(value = "/getName", method = RequestMethod.GET)public String getName();}c、服务端提供接口实现@RequestMapping(value = "/getName", method = RequestMethod.GET) public String getName(){return "hello world";}d、fegin声明是调用@Autowiredprivate NameServiceClient feginNameServiceClient;@RequestMapping(value = "/getName", method= RequestMethod.GET)public String getName(){return feginNameServiceClient.getName();}(2)Fegin 的类加载流程通过主类上的EnableFeignClients 注解开启FeignClient;根据Feign 的规则实现接口,并加上FeignClient注解,供调用的地方注入调用;程序启动后,会扫描所有FeignClient 注解的类,并将这些信息注入到IOC 容器中;当b中接口被调用时,通过jdk代理,以及反射(Spring处理注解的方式),来生成具体的RequestTemplateRequestTemplate 生成ReqestRequest 交给httpclient处理,这里的httpclient 可以是OkHttp,也可以是HttpUrlConnection 或者HttpClient最后Client被封装到LoadBalanceClient类,这个类结合Ribbon 实现负载均衡。(3)Fegin的原理4、HystrixHystrix 是springcloud生态的断路器(隔离、限流、降级),主要是用来预防服务雪崩的现象,剔除掉分布式系统中某些挂掉或请求过慢的服务节点。Hystrix 是一个帮助解决分布式系统中超时处理和容错的类库, 拥有保护系统的能力。(1)隔离、限流、降级Hystrix断路器有两种隔离策略:信号量隔离(默认)和线程池隔离。信号量模式从始至终都只有请求线程自身,是同步调用模式,不支持超时调用,不支持直接熔断,由于没有线程的切换,开销非常小。线程池模式可以支持异步调用,支持超时调用,支持直接熔断,存在线程切换,开销大。信号量隔离:常用于获取共享资源的场景中,比如计算机连接了两个打印机,那么初始的信号量就是2,被某个进程或线程获取后减1,信号量为0后,需要获取的线程或进程进入资源等待状态。Hystrix的处理有些不同,其不等待,直接返回失败。线程池隔离:采用的就是jdk的线程池,其默认选用不使用阻塞队列的线程池,例如线程池大小为10,如果某时刻10个线程均被使用,那么新的请求将不会进入等待队列,而是直接返回失败,起到限流的作用。此外,其还引入了一个断路器机制,当断路器处于打开状态时,直接返回失败或进入降级流程。断路器打开和关闭的触发流程为:当总的请求数达到可阈值HystrixCommandProperties.circuitBreakerRequestVolumeThreshold(),或总的请求失败百分比达到了阈值HystrixCommandProperties.circuitBreakerErrorThresholdPercentage(),这时将断路器的状态由关闭设置为打开。当断路器打开时,所有的请求均被短路,在经过指定休眠时间窗口后,让下一个请求通过(断路器被认为是半开状态)。如果请求失败,断路器进入打开状态,并进入新的休眠窗口;否则进入关闭状态。(2)Hystrix 的整体处理流程流程如上图所示,Hystrix框架通过命令模式来实现方法粒度上的服务保障,主要涉及HystrixCommand和HystrixObservableCommand类,前者提供同步的execute和异步的queue方法,后者提供立即执行observe和延迟执行toObservable的回调方法。此外,实际项目中通常不会使用Hystrix集成的本地缓存。5、Spring Cloud GatewaySpring Cloud Gateway 是springcloud全新推出的第二代微服务网关,用来替代Zuul。gateway实现了服务转发、熔断、限流、权限校验等功能,有测评显示,性能比Zuul要好不少。(1)相关概念Route(路由):这是网关的基本构建块。它由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配。Predicate(断言):这是一个 Java 8 的 Predicate。输入类型是一个 ServerWebExchange。我们可以使用它来匹配来自 HTTP 请求的任何内容,例如 headers 或参数。Filter(过滤器):这是org.springframework.cloud.gateway.filter.GatewayFilter的实例,我们可以使用它修改请求和响应。(2)请求流程spring cloud gateway处理request请求的流程如下图,我们先看gateway的构成:一个netty server,一个netty client,Route(包含Predicate和Filter)。在gateway中最重要的应该是Route(Netty Server和Client已经封装好了),它由RouteLocatorBuilder构建,内部包含Predicate和Filter。流程:即在最前端,启动一个netty server(默认端口为8080)接受请求,然后通过Routes(每个Route由Predicate(等同于HandlerMapping)和Filter(等同于HandlerAdapter))处理后通过Netty Client发给响应的微服务。(3)yml配置server.port: 8082spring:application:name: gatewaycloud:gateway:routes:- id: path_routeuri: http://localhost:8000order: 0predicates:- Path=/foo/**filters:- StripPrefix=1上面给出了一个根据请求路径来匹配目标uri的例子,如果请求的路径为/foo/bar,则目标uri为 http://localhost:8000/bar。如果上面例子中没有加一个StripPrefix=1过滤器,则目标uri 为http://localhost:8000/foo/bar,StripPrefix过滤器是去掉一个路径。6、Spring Boot AdminSpring Boot Admin 是springcloud提供的监控组件,用于管理和监控SpringBoot各个微服务。Admin通过注册中心(如Eureka)来监控各个节点的状态。可以结合 Spring Boot Actuator 使用,常用的监控数据有,显示健康状况显示详细信息,例如JVM和内存指标micrometer.io指标数据源指标缓存指标查看jvm系统和环境属性监控 server端需要 @EnableAdminServer 注解,client端只需要配置好yaml文件就好了,admin会通过注册中心获取各个服务节点的状态。management:endpoints:web:exposure:include: '*'endpoint:health:show-details: ALWAYS7、Spring Cloud ConfigSpring Cloud Config 是springcloud的分布式配置中心组件。分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件Spring Cloud Config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。SpringCloudConfig分为服务端(Config Server)和客户端(Config Client),服务端负责将git(svn)中存储的配置文件发布成REST接口,客户端可以从服务端REST接口获取配置。但客户端并不能主动感知到配置的变化,从而主动去获取新的配置, 它需要每个客户端通过POST方法触发各自的/refresh,SpringCloudBus就通过一个轻量级消息代理连接分布式系统的节点。Config Server用于配置属性的存储,存储的位置可以为Git仓库、SVN仓库、本地文件等,Config Client用于服务属性的读取。spring cloud config是将配置保存在git/svn上,依赖git每次push后,触发webhook回调,最终触发spring cloud bus(消息总线),然后由消息总线通知相关的应用。1.2.3.3 SpringCloud AlibabaSpring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。SpringCloud Alibaba介绍Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式 应用服务。依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。1.3.1 主要功能服务限流降级:默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。服务注册与发现:适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。分布式配置管理:支持分布式系统中的外部化配置,配置更改时自动刷新。消息驱动能力:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。分布式事务:使用 @GlobalTransactional 注解, 高效并且对业务零侵入地解决分布式事务问题。阿里云对象存储:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。分布式任务调度:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有Worker(schedulerx-client)上执行。阿里云短信服务:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。组件Sentinel: 把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。Nacos: 一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。RocketMQ: 一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。Dubbo: Apache Dubbo™ 是一款高性能 Java RPC 框架。Seata: 阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。Alibaba Cloud ACM: 一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心产品。Alibaba Cloud OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。具体技术点(约定>配置>编码)maven:3.6.0这样做的好处就是: 如果有多个子项目都引用同一样的依赖,则可以避免在每个使用的子项目里都声明一个版本号,这样想升级或切换到另一个版本时,只需在顶层父容器里更新,而不需要一个一个子项目的修改l;另外如果某个子项目需要另外的一个版本,只需声明version版本数据库:MySQL 5.7持久层: SpingData Jpa其他: SpringCloud Alibaba 技术栈安全框架:Spring Security Spring Cloud Oauth2分布式任务调度:elastic-job持久层框架:MyBatis、通用Mapper4、Mybatis_PageHelper数据库连接池日志管理:Logback 前端框架:Vue全家桶以及相关组件三方服务: 邮件服务、阿里云短信服务、七牛云文件服务、钉钉机器人服务、高德地图API————————————————原文链接:https://blog.csdn.net/liuerchong/article/details/108374777
  • [技术干货] 一文读懂SpringCloud全家桶
    一、云原生应用 SpringCloud是对Springboot使用的分布式解决方案,适合分布式、中大型的项目架构开发,现在也逐渐成为Java服务端的主流框架。使用Spring Cloud开发的应用程序非常适合在Docker和PaaS(比如Pivotal Cloud Foundry)上部署,所以又叫做云原生应用(Cloud Native Application)。云原生可以简单地理解为面向云环境的软件架构。 springcloud 微服务架构, 1、优点 服务拆分粒度更细,有利于资源重复利用,有利于提高开发效率 可以更精准的制定优化服务方案,提高系统的可维护性 微服务架构采用去中心化思想,服务之间采用Restful等轻量级通讯,比ESB更轻量 适于互联网时代,产品迭代周期更短 2、缺点 微服务过多,治理成本高,不利于维护系统 分布式系统开发的成本高(容错,分布式事务等)对团队挑战大 二、全家桶 SpringCloud提供的全生态的分布式组件支持, 服务注册发现:Eureka(其他选择: Consul,Zookeeper,Nacos,Etcd) 负载均衡:Robbin(声明式调用:Fegin) 断路器:Hystrix 网关:Zuul2,Spring Cloud Gateway 配置中心:Spring Cloud Config 监控:Spring Boot Admin,Spring Boot Actuator 链路跟踪:Spring Cloud Sleuth 三、组件介绍 1、Eureka (1)体系划分 Eureka是SpringCloud官方推荐的服务注册发现组件。Eureka的角色和Dubbo中Zookeeper的角色类似,体系划分如下, 业务上可以分为:服务注册中心、服务提供者、服务消费者。 代码逻辑上分为:Eureka Server 和 Eureka Client。  (2)结构原理 看图说话, 两台Eureka服务注册中心构成的服务注册中心的主从复制集群; 然后服务提供者向注册中心进行注册、续约、下线服务等; 服务消费者向Eureka注册中心拉去服务列表并维护在本地; 然后服务消费者根据从Eureka服务注册中心获取的服务列表选取一个服务提供者进行消费服务。 (3)Eureka 集群(三节点,两两注册) 从图中可以看出 Eureka Server 集群相互之间通过 Replicate 来同步数据,相互之间不区分主节点和从节点,所有的节点都是平等的。在这种架构中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点。 如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点。当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会进行节点间复制,将请求复制到其它 Eureka Server 当前所知的所有节点中。 Eureka Server 集群之间的状态是采用异步方式同步的,所以不保证节点间的状态一定是一致的,不过基本能保证最终状态是一致的(Eureka保证AP,Zookeeper强调CP)。 2、Robbin (1)客户端的软负载 Robbin是springcloud的LB调用组件,提供客户端的软件负载均衡。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。 Robbin 提供的客户端软负载,是SpringCloud微服务的典型特征之一。 (2)负载均衡策略 轮询(RoundRobin),以轮询的方式依次将请求调度不同的服务器,即每次调度执行i = (i + 1) mod n,并选出第i台服务器。 随机(Random),随机选择状态为UP的Server。 加权响应时间(WeightedResponseTime),根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。 区域感知轮询(ZoneAvoidanceRule),复合判断server所在区域的性能和server的可用性选择server。 (3)核心组件 Ribbon的核心组件(均为接口类型)有以下几个, ServerList,用于获取地址列表。它既可以是静态的(提供一组固定的地址),也可以是动态的(从注册中心中定期查询地址列表)。 ServerListFilter,仅当使用动态ServerList时使用,用于在原始的服务列表中使用一定策略过虑掉一部分地址。 IRule,选择一个最终的服务地址作为LB结果。选择策略有轮询、根据响应时间加权、断路器(当Hystrix可用时)等。 Ribbon在工作时首选会通过ServerList来获取所有可用的服务列表,然后通过ServerListFilter过虑掉一部分地址,最后在剩下的地址中通过IRule选择出一台服务器作为最终结果。 3、Fegin Fegin是一个声明式Http端调用,集成了Robbin的负载均衡功能,同时声明式调用更加方便(只需要简单的注解即可)。简单的可以理解为:Spring Cloud Feign 的出现使得Eureka和Ribbon的使用更加简单。  (1)Fegin接口示例  a、启动类@EnableFeignClients 注解  @SpringBootApplication @EnableEurekaClient @EnableFeignClients // 启用fegin声明式调用 public class FeginComsumerApplication {      public static void main(String[] args) {         SpringApplication.run(FeginComsumerApplication.class, args);     }  } b、声明一个调用的Feign接口,  @Service @FeignClient(name = "name-service") public interface NameService {      @RequestMapping(value = "/getName", method = RequestMethod.GET)     public String getName();  } c、服务端提供接口实现  @RequestMapping(value = "/getName", method = RequestMethod.GET) public String getName(){     return "hello world"; } d、fegin声明是调用 @Autowired private NameServiceClient feginNameServiceClient; @RequestMapping(value = "/getName", method= RequestMethod.GET) public String getName(){     return feginNameServiceClient.getName(); } (2)Fegin 的类加载流程 通过主类上的EnableFeignClients 注解开启FeignClient; 根据Feign 的规则实现接口,并加上FeignClient注解,供调用的地方注入调用; 程序启动后,会扫描所有FeignClient 注解的类,并将这些信息注入到IOC 容器中; 当b中接口被调用时,通过jdk代理,以及反射(Spring处理注解的方式),来生成具体的RequestTemplate RequestTemplate 生成Reqest Request 交给httpclient处理,这里的httpclient 可以是OkHttp,也可以是HttpUrlConnection 或者HttpClient 最后Client被封装到LoadBalanceClient类,这个类结合Ribbon 实现负载均衡。 (3)Fegin的原理 4、Hystrix Hystrix 是springcloud生态的断路器(隔离、限流、降级),主要是用来预防服务雪崩的现象,剔除掉分布式系统中某些挂掉或请求过慢的服务节点。Hystrix是一个帮助解决分布式系统中超时处理和容错的类库, 拥有保护系统的能力。 (1)隔离、限流、降级 Hystrix断路器有两种隔离策略:信号量隔离(默认)和线程池隔离。 信号量模式从始至终都只有请求线程自身,是同步调用模式,不支持超时调用,不支持直接熔断,由于没有线程的切换,开销非常小。 线程池模式可以支持异步调用,支持超时调用,支持直接熔断,存在线程切换,开销大。 信号量隔离:常用于获取共享资源的场景中,比如计算机连接了两个打印机,那么初始的信号量就是2,被某个进程或线程获取后减1,信号量为0后,需要获取的线程或进程进入资源等待状态。Hystrix的处理有些不同,其不等待,直接返回失败。 线程池隔离:采用的就是jdk的线程池,其默认选用不使用阻塞队列的线程池,例如线程池大小为10,如果某时刻10个线程均被使用,那么新的请求将不会进入等待队列,而是直接返回失败,起到限流的作用。 此外,其还引入了一个断路器机制,当断路器处于打开状态时,直接返回失败或进入降级流程。断路器打开和关闭的触发流程为:当总的请求数达到可阈值HystrixCommandProperties.circuitBreakerRequestVolumeThreshold(),或总的请求失败百分比达到了阈值HystrixCommandProperties.circuitBreakerErrorThresholdPercentage(),这时将断路器的状态由关闭设置为打开。当断路器打开时,所有的请求均被短路,在经过指定休眠时间窗口后,让下一个请求通过(断路器被认为是半开状态)。如果请求失败,断路器进入打开状态,并进入新的休眠窗口;否则进入关闭状态。 (2)Hystrix 的整体处理流程 流程如上图所示,Hystrix框架通过命令模式来实现方法粒度上的服务保障,主要涉及HystrixCommand和HystrixObservableCommand类,前者提供同步的execute和异步的queue方法,后者提供立即执行observe和延迟执行toObservable的回调方法。此外,实际项目中通常不会使用Hystrix集成的本地缓存。 5、Spring Cloud Gateway Spring Cloud Gateway 是springcloud全新推出的第二代微服务网关,用来替代Zuul。gateway实现了服务转发、熔断、限流、权限校验等功能,有测评显示,性能比Zuul要好不少。 (1)相关概念 Route(路由):这是网关的基本构建块。它由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配。 Predicate(断言):这是一个 Java 8 的 Predicate。输入类型是一个 ServerWebExchange。我们可以使用它来匹配来自 HTTP 请求的任何内容,例如 headers 或参数。 Filter(过滤器):这是org.springframework.cloud.gateway.filter.GatewayFilter的实例,我们可以使用它修改请求和响应。 (2)请求流程 spring cloud gateway处理request请求的流程如下图, 我们先看gateway的构成:一个netty server,一个netty client,Route(包含Predicate和Filter)。在gateway中最重要的应该是Route(Netty Server和Client已经封装好了),它由RouteLocatorBuilder构建,内部包含Predicate和Filter。 **流程:**即在最前端,启动一个netty server(默认端口为8080)接受请求,然后通过Routes(每个Route由Predicate(等同于HandlerMapping)和Filter(等同于HandlerAdapter))处理后通过Netty Client发给响应的微服务。  (3)yml配置 server.port: 8082 spring:   application:     name: gateway   cloud:     gateway:       routes:         - id: path_route           uri: http://localhost:8000           order: 0           predicates:             - Path=/foo/**           filters:             - StripPrefix=1 上面给出了一个根据请求路径来匹配目标uri的例子,如果请求的路径为/foo/bar,则目标uri为http://localhost:8000/bar。如果上面例子中没有加一个StripPrefix=1过滤器,则目标uri 为http://localhost:8000/foo/bar,StripPrefix过滤器是去掉一个路径。  6、Spring Boot Admin Spring Boot Admin 是springcloud提供的监控组件,用于管理和监控SpringBoot各个微服务。Admin通过注册中心(如Eureka)来监控各个节点的状态。可以结合Spring Boot Actuator 使用,常用的监控数据有,  显示健康状况 显示详细信息,例如 JVM和内存指标 micrometer.io指标 数据源指标 缓存指标 查看jvm系统和环境属性 监控 server端需要 @EnableAdminServer 注解,client端只需要配置好yaml文件就好了,admin会通过注册中心获取各个服务节点的状态。  management:   endpoints:     web:       exposure:         include: '*'   endpoint:     health:       show-details: ALWAYS 7、Spring Cloud Config Spring Cloud Config 是springcloud的分布式配置中心组件。 分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件Spring Cloud Config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。 SpringCloudConfig分为服务端(Config Server)和客户端(Config Client),服务端负责将git(svn)中存储的配置文件发布成REST接口,客户端可以从服务端REST接口获取配置。但客户端并不能主动感知到配置的变化,从而主动去获取新的配置, 它需要每个客户端通过POST方法触发各自的/refresh,SpringCloudBus就通过一个轻量级消息代理连接分布式系统的节点。 Config Server用于配置属性的存储,存储的位置可以为Git仓库、SVN仓库、本地文件等,Config Client用于服务属性的读取。 spring cloud config是将配置保存在git/svn上,依赖git每次push后,触发webhook回调,最终触发spring cloud bus(消息总线),然后由消息总线通知相关的应用。 ————————————————  原文链接:https://blog.csdn.net/m0_67401660/article/details/124465286 
  • [技术干货] SpringBoot之容器
    容器功能 1.1 组件添加 法一: @Configuration  /**  * 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的  * 2、配置类本身也是组件  * 3、proxyBeanMethods:代理bean的方法        (这是SpringBoot2对SpringBoot很大的不同)  *      Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】  *      Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】  *      组件依赖必须使用Full模式默认。其他默认是否Lite模式  *  *  *  */ @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 public class MyConfig {      /**      * Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象      * @return      */     @Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例     public User user01(){         User zhangsan = new User("zhangsan", 18);         //user组件依赖了Pet组件         zhangsan.setPet(tomcatPet());         return zhangsan;     }      @Bean("tom")   //给容器中添加组件。以方法名作为组件的id。     public Pet tomcatPet(){         return new Pet("tomcat");     } } 法二:@Bean、@Component、@Controller、@Service、@Repository 法一的方法新一些,这个方法老一些,这个方法是将注解标于要添加到bean中的那些类的上面。而法一是统一在MyConfig类中添加组件。 将注解t注解在一个类上,表示将此类标记为Spring容器中的一个Bean。 Spring为Controller-Service-Dao的分层模型分别提供了@Controller、@Service、@Repository注解,除此之外的组件使用@Component注解 其他注解1: @ComponentScan、@Import @ComponentScan 的作用就是根据定义的扫描路径(否则扫描路径是主配置类的同级或下级目录),把符合扫描规则的类装配到spring容器中 @import的好处是可以引入外部类(非自己定义的类) * 4、@Import({User.class, DBHelper.class})  *      给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名  *  *  *  */  @Import({User.class, DBHelper.class}) @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 public class MyConfig { } 其他注解2: @Configuration (这个注解重要) 该注解放在配置类上表示,当容器中满足条件时,配置类中的组件才生效; 放在配置方法上的时候,表示的意思是当满足条件的时候配置方法才生效;  1.2 原生配置文件引入 @ImportResource 指以.xml结尾的配置文件,通过@ImportResource导入后SpringBoot进行解析,完成对应的组件注册 位置:在主配置类的上方。主要是为了兼容第三方,注入IOC。 @ImportResource("classpath:beans.xml") public class MyConfig {} 1.3 配置绑定 @ConfigurationProperties (常见) 场景例子:我们习惯将经常爱变化的东西写在.properties配置文件中,比如与数据库相关的信息(连接池、URL等)配置到配置文件中,为了方便我们会将配置文件中的内容解析到JavaBean中。 配置绑定:两种方式 @Component + @ConfigurationProperties(prefix=“mycar”)声明在要绑定的类的上方 @ConfigurationProperties(prefix=“mycar”)声明在要绑定的类的上方;在配置类的上方声明@EnableConfigurationProperties(Car.class),开启对应类的配置绑定功能,并把Car这个组件自动注入到容器中; /**  * 只有在容器中的组件,才会拥有SpringBoot提供的强大功能,所以先用@Component将Car绑定到容器中  */ @Component @ConfigurationProperties(prefix = "mycar") public class Car {      private String brand;     private Integer price;      public String getBrand() {         return brand;     }      public void setBrand(String brand) {         this.brand = brand;     }      public Integer getPrice() {         return price;     }      public void setPrice(Integer price) {         this.price = price;     }      @Override     public String toString() {         return "Car{" +                 "brand='" + brand + '\'' +                 ", price=" + price +                 '}';     } }` //一般使用这种方式 @EnableConfigurationProperties(Car.class) // 开启 Car 的属性配置并自动注入到容器中 public class MyConfiguration { @ConfigurationProperties(prefix = "mycar") ———————————————— 原文链接:https://blog.csdn.net/qq_44901346/article/details/119703806 
  • [技术干货] SpringBoot中的容器
    一、容器功能 1、组件添加 (1)主要注解 @Configuration 告诉SpringBoot这是一个配置类 == 配置文件 注意:spring5.2以后@Configuration多了一个属性proxyBeanMethods,默认为true  @Configuration(proxyBeanMethods = true) proxyBeanMethods:代理bean的方法  Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】 外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象  Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】  组件依赖必须使用Full模式默认。其他默认是否Lite模式 ● Full模式与Lite模式 ○ 最佳实战 ■ 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断 ■ 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式 @Bean 给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例 配置类里面使用@Bean标注在方法上给容器注册组件,默认是单实例的 配置类本身也是组件  (2) 基本使用 bean包: Pet类:  /**  * 宠物  */ public class Pet {     private String name;      public String getName() {         return name;     }      public void setName(String name) {         this.name = name;     }      public Pet(String name) {         this.name = name;     }      public Pet() {     }      @Override     public String toString() {         return "Pet{" +                 "name='" + name + '\'' +                 '}';     } }  User类:  /* 用户  */ public class User {     private String name;     private Integer age;      public User() {     }      public User(String name, Integer age) {         this.name = name;         this.age = age;     }      public String getName() {         return name;     }      public void setName(String name) {         this.name = name;     }      public Integer getAge() {         return age;     }      public void setAge(Integer age) {         this.age = age;     }      @Override     public String toString() {         return "User{" +                 "name='" + name + '\'' +                 ", age=" + age +                 '}';     } } config包: MyConfig类  @Configuration(proxyBeanMethods = false)//告诉Spring这是一个配置类 public class MyConfig {     @Bean//给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例     public User user01(){         return  new User("zhangsan",18);     }     @Bean("tom")     public Pet tomcatPet(){         return new Pet("tomcat");     } } controller包: MainApplication类  @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com") public class MainApplication {     public static void main(String[] args) {         //1、返回我们IOC容器         ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);          //2、查看容器里面的组件         String[] names = run.getBeanDefinitionNames();         for (String name : names) {             System.out.println(name);         }         //3、从容器中获取组件         MyConfig bean = run.getBean(MyConfig.class);         System.out.println(bean);         //如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。         //保持组件单实例         User user = bean.user01();         User user1 = bean.user01();         System.out.println("组件为:"+(user == user1));     }  } 结果 (3)补充 @Import 给容器导入一个组件 必须写在容器中的组件上   * @Import({User.class, DBHelper.class})  *      给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名  *  *  *  */  @Import({User.class, DBHelper.class}) @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 public class MyConfig { } @Configuration测试代码如下  @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com") public class MainApplication {     public static void main(String[] args) {         //1、返回我们IOC容器         ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);          //2、查看容器里面的组件         String[] names = run.getBeanDefinitionNames();         for (String name : names) {             System.out.println(name);         }         //3、从容器中获取组件         MyConfig bean = run.getBean(MyConfig.class);         System.out.println(bean);         //如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。         //保持组件单实例         User user = bean.user01();         User user1 = bean.user01();         System.out.println("组件为:"+(user == user1));          //5、获取组件         String[] beanNamesForType = run.getBeanNamesForType(User.class);         System.out.println("======");         for (String s : beanNamesForType) {             System.out.println(s);         }         DBHelper bean1 = run.getBean(DBHelper.class);         System.out.println(bean1);      }  } @Conditional 条件装配:满足Conditional指定的条件,则进行组件注入  ConditionalOnBean:当容器中存在指定的bean组件时才干某些事情 ConditionalOnMissingBean:当容器中不存在指定的bean组件时才干某些事情 ConditionalOnClass:当容器中有某个类时才干某些事情 ConditionalOnResource:当项目的类路径存在某个资源时,才干什么事  =====================测试条件装配========================== @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 //@ConditionalOnBean(name = "tom") @ConditionalOnMissingBean(name = "tom") public class MyConfig {     @Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例     public User user01(){         User zhangsan = new User("zhangsan", 18);         //user组件依赖了Pet组件         zhangsan.setPet(tomcatPet());         return zhangsan;     }      @Bean("tom22")     public Pet tomcatPet(){         return new Pet("tomcat");     } }  测试: public static void main(String[] args) {         //1、返回我们IOC容器         ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);          //2、查看容器里面的组件         String[] names = run.getBeanDefinitionNames();         for (String name : names) {             System.out.println(name);         }          boolean tom = run.containsBean("tom");         System.out.println("容器中Tom组件:"+tom);          boolean user01 = run.containsBean("user01");         System.out.println("容器中user01组件:"+user01);          boolean tom22 = run.containsBean("tom22");         System.out.println("容器中tom22组件:"+tom22);      }  2、原生配置文件引入(xml文件引入) @ImportResource 导入资源  @ImportResource("classpath:beans.xml")//导入spring的配置文件 @Import({User.class, DBHelper.class}) @Configuration(proxyBeanMethods = false)//告诉Spring这是一个配置类 @ConditionalOnMissingBean(name = "tom") public class MyConfig { ======================beans.xml========================= <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"        xmlns:context="http://www.springframework.org/schema/context"        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">      <bean id="haha" class="com.atguigu.boot.bean.User">         <property name="name" value="zhangsan"></property>         <property name="age" value="18"></property>     </bean>      <bean id="hehe" class="com.atguigu.boot.bean.Pet">         <property name="name" value="tomcat"></property>     </bean> </beans> 测试  ======================测试=================         boolean haha = run.containsBean("haha");         boolean hehe = run.containsBean("hehe");         System.out.println("haha:"+haha);//true         System.out.println("hehe:"+hehe);//true 3.配置绑定 如何使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用; (1)@Component + @ConfigurationProperties properties文件 /**  * 只有在容器中的组件,才会拥有SpringBoot提供的强大功能  */ @Component @ConfigurationProperties(prefix = "mycar") public class Car {      private String brand;     private Integer price;      public String getBrand() {         return brand;     }      public void setBrand(String brand) {         this.brand = brand;     }      public Integer getPrice() {         return price;     }      public void setPrice(Integer price) {         this.price = price;     }      @Override     public String toString() {         return "Car{" +                 "brand='" + brand + '\'' +                 ", price=" + price +                 '}';     } } (2)@EnableConfigurationProperties + @ConfigurationProperties @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件 @ConditionalOnMissingBean(name = "tom") @ImportResource("classpath:beans.xml") //@EnableConfigurationProperties(Car.class) //1、开启Car配置绑定功能 //2、把这个Car这个组件自动注册到容器中 ———————————————— 原文链接:https://blog.csdn.net/spade_Kwo/article/details/121778319 
  • [技术干货] Spring Boot之容器功能
    一.Spring 注入组件的注解 @Component、@Controller、 @Service、@Repository 说明: 这些在 Spring 中的传统注解仍然有效,通过这些注解可以给容器注入组件 二.@Configuration 在 SpringBoot, 通过 @Configuration 创建配置类来注入组件 1.代码演示 1.1JavaBean--》Monster.java ublic class Monster {       private Integer id;     private String name;     private Integer age;     private String skill;       public Monster(Integer id, String name, Integer age, String skill) {         this.id = id;         this.name = name;         this.age = age;         this.skill = skill;     }       public Monster() {     }       public Integer getId() {         return id;     }       public void setId(Integer id) {         this.id = id;     }       public String getName() {         return name;     }       public void setName(String name) {         this.name = name;     }       public Integer getAge() {         return age;     }       public void setAge(Integer age) {         this.age = age;     }       public String getSkill() {         return skill;     }       public void setSkill(String skill) {         this.skill = skill;     }       @Override     public String toString() {         return "Monster{" +                 "id=" + id +                 ", name='" + name + '\'' +                 ", age=" + age +                 ", skill='" + skill + '\'' +                 '}';     } }  1.2配置类 /**  * @author 海绵hong  * @version 1.0  * <p>  * 解读  * 1. @Configuration 标识这是一个配置类, 等价于配置文件  * 2. 程序员可以通过@Bean 注解注入bean对象到容器  * 3. 当一个类被 @Configuration 标识,该类-Bean 也会注入容器  */ @Configuration public class BeanConfig {       /**      * 解读      * 1. @Bean : 给容器添加组件, 就是Monster bean      * 2. monster01() : 默认 你的方法名monster01 作为Bean的名字/id      * 3. Monster : 注入类型, 注入bean的类型是Monster      * 4. new Monster(200,"牛魔王",500,"疯魔拳") 注入到容器中具体的Bean信息      * 5. @Bean(name = "monster_nmw") : 在配置、注入Bean指定名字/id monster_nmw      * 6. 默认是单例注入      * 7. 通过 @Scope("prototype")  可以每次返回新的对象,就多例.      */     //@Bean(name = "monster_nmw")     @Bean     //@Scope("prototype")     public Monster monster01() {         return new Monster(200, "牛魔王", 500, "疯魔拳");     }   }  1.3执行代码         //启动springboot应用程序/项目         ConfigurableApplicationContext ioc =                 SpringApplication.run(MainApp.class, args);     //  ===演示 @Configuration start ====                  Monster monster01 = ioc.getBean("monster01", Monster.class);         Monster monster02 = ioc.getBean("monster01", Monster.class);                  System.out.println("monster01--" + monster01 + " " + monster01.hashCode());         System.out.println("monster02--" + monster02 + " " + monster02.hashCode());           //===演示 @Configuration end ==== 2.@Configuration 注意事项和细节 1. 配置类本身也是组件, 因此也可以获取 , 测试 修改 MainApp.java     public static void main(String[] args) {         ConfigurableApplicationContext ioc =                 SpringApplication.run(MainApp.class, args); //解读 //1. ioc.getBean("monster01", Monster.class) 是从 BeanConfig 配置类/容器获取 bean 实例 //2. 默认是单列模式, 所以 monster01 == monster02 //获取 BeanConfig 配置类的组件/bean 实例         Monster monster01 = ioc.getBean("monster01", Monster.class);         System.out.println(monster01);         Monster monster02 = ioc.getBean("monster01", Monster.class);         System.out.println(monster01 == monster02); //解读 //配置类本身也是组件, 因此也可以获取         BeanConfig beanConfig = ioc.getBean(BeanConfig.class);         System.out.println("beanConfig= " + beanConfig);     }  2. SpringBoot2 新增特性: proxyBeanMethods 指定 Full 模式 (全模式)和 Lite 模式(简化模式) 1. proxyBeanMethods:代理bean的方法  (1) Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的, 是代理方式】  (2) Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的, 是非代理方式】  (3) 特别说明: proxyBeanMethods 是在 调用@Bean方法 才生效,因此,需要先获取BeanConfig 组件,再调用方法 而不是直接通过 SpringBoot 主程序得到的容器来获取bean, 注意观察直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效  (4) 如何选择: 组件依赖必须使用Full模式默认。如果不需要组件依赖使用 Lite模  (5) Lite模 也称为轻量级模式,因为不检测依赖关系,运行速度快 @Configuration(proxyBeanMethods = false) public class BeanConfig {         //===演示@Configuration(proxyBeanMethods = xxx) start           //1. 先得到BeanConfig组件         BeanConfig beanConfig = ioc.getBean(BeanConfig.class);         Monster monster_01 = beanConfig.monster01();         Monster monster_02 = beanConfig.monster01();           System.out.println("monster_01-" + monster_01 + " " + monster_01.hashCode());         System.out.println("monster_02-" + monster_02 + " " + monster_02.hashCode());           //特别说明: proxyBeanMethods 是在 调用@Bean方法 才生效,因此,需要先获取BeanConfig 组件,再调用方法         //1. 而不是直接通过 SpringBoot 主程序得到的容器来获取bean, 注意观察直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效           Monster monster01 = ioc.getBean("monster01", Monster.class);         Monster monster02 = ioc.getBean("monster01", Monster.class);         System.out.println("monster01-" + monster01 + " " + monster01.hashCode());         System.out.println("monster02-" + monster02 + " " + monster02.hashCode());           //===演示@Configuration(proxyBeanMethods = xxx) end  3. 配置类可以有多个 , 就和 Spring 可以有多个 ioc 配置文件是一个道理 三.@Import 在 SpringBoot, 通过 @Import 来注入组件(和@Configuration一样都是注入bean) 1.创建两个JavaBean类 Cat+Dog 2.注入类 /**  * 解读  * 1. @Import 代码 可以看到,可以指定 class的数组, 可以注入指定类型的Bean  * public @interface Import {  *  *          Class<?>[] value()}  *  * 2. 通过@Import 方式注入了组件, 默认组件名字/id就是对应类型的全类名  */   @Import({Dog.class, Cat.class}) 3.测试注解的使用   //启动springboot应用程序/项目         ConfigurableApplicationContext ioc =                 SpringApplication.run(MainApp.class, args);    //===测试@Import 使用 start           Dog dogBean = ioc.getBean(Dog.class);         Cat catBean = ioc.getBean(Cat.class);         System.out.println("dogBean--" + dogBean);         System.out.println("catBean--" + catBean);           //===测试@Import 使用 end 四.@Conditional 1.@Conditional 介绍 1. 条件装配:满足 Conditional 指定的条件,则进行组件注入 2. @Conditional 是一个根注解,下面有很多扩展注解 2.应用实例   1. 要求 : 演示在 SpringBoot, 如何通过 @ConditionalOnBean 来注入组件 2. 只有在容器中有 name = monster_nmw 组件时,才注入 dog01, 代码如图     @Bean     /**      * 解读      * 1. @ConditionalOnBean(name = "monster_nmw") 表示      * 2. 当容器中有一个Bean , 名字是monster_nmw (类型不做约束), 就注入dog01这个Dog bean      * 3. 如果没有 名字是monster_nmw Bean 就不注入dog01这个Dog bean      * 4. 还有很多其它的条件约束注解,小伙伴可以自己测试      *      * 5. @ConditionalOnMissingBean(name = "monster_nmw") 表示在容器中,      * 没有 名字/id 为 monster_nmw 才注入dog01这个Bean      *      * 6. @ConditionalOnBean(name = "monster_nmw") 也可以放在配置类      * 表示对该配置类的所有要注入的组件,都进行条件约束.      *      */     @ConditionalOnBean(name = "monster_nmw")     //@ConditionalOnMissingBean(name = "monster_nmw")     public Dog dog01() {         return new Dog();     }  五.@ImportResource 1.作用: 原生配置文件引入 , 也就是可以直接导入 Spring 传统的 beans.xml ,可以认 为是 SpringBoot 对 Spring 容器文件的兼容 .(原来依靠借口或者类来导入,现在可以使用该注解进行判断) 2.@ImportResource 应用实例  @Configuration //导入beans.xml - 就可以获取到beans.xml 中配置bean @ImportResource(locations = {"classpath:beans.xml","classpath:beans02.xml"})//配置两个bean文件 public class BeanConfig3 { }         //===测试@Import 使用 start           Dog dogBean = ioc.getBean(Dog.class);         Cat catBean = ioc.getBean(Cat.class);         System.out.println("dogBean--" + dogBean);         System.out.println("catBean--" + catBean);           //===测试@Import 使用 end 六.配置绑定 一句话:使用 Java 读取到 SpringBoot 核心配置文件 application.properties 的内容, 并且把它封装到 JavaBean 中 1.代码演示 #设置Furn的属性k-v #前面的 furn01 是用于指定/区别不同的绑定对象, 这样可以再绑定Furn bean属性值时 #通过furn01 前缀进行区分 #furn01.id 中的id 就是你要绑定的 Furn bean的属性名 furn01.id=100 furn01.name=TV furn01.price=1000.9 @Component @ConfigurationProperties(prefix = "furn01") public class Furn {     private Integer id;     private String name;     private Double price;     } 会读取核心配置文件的信息,然后放入容器 2.配置绑定还有第 2 种方式 注意 : 注销 @Component 需 要 在 BeanConfig.java( 说 明 : 也 可 以 是 其 它 配 置 类 ) 配 置 @EnableConfigurationProperties ( Furn . class ), 否则会提示错误 //@EnableConfigurationProperties(Furn.class)解读 //1、开启 Furn 配置绑定功能 //2、把 Furn 组件自动注册到容器中 @EnableConfigurationProperties(Furn.class) public class BeanConfig { } 海绵的思路(可能错误): 将@Component注解标识掉之后,就不会去读取到容器中,但是在控制器中@EnableConfigurationProperties(Furn.class)被添加,那么底层应该就是这样一个思路:将这个启用配置属性明确配置那个类的信息,然后在那个对应的JavaBean类中有@ConfigurationProperties(prefix = "furn01")这个配置就可以读取到,并且直接将这个信息发送到了控制器中,所有在之后添加了那个注解之后便没有报错  3.注意事项和细节 1. 如果 application.properties 有中文 , 需要转成 unicode 编码写入 , 否则出现乱码 #设置属性 k-v furn01.id=100 furn01.name=soft_chair\u6c99\u53d1!! furn01.price=45678.9 2. 使用 @ConfigurationProperties (prefix = "furn01" ) 会提示如下信息 , 但是不会影响使用 3. 解决 @ConfigurationProperties(prefix = "furn01") 提示信息, 在 pom.xml 增加依赖, 即可  <dependency>     <groupId>org.springframework.boot</groupId>     <artifactId>spring-boot-configuration-processor</artifactId>     <optional>true</optional> </dependency> ———————————————— 原文链接:https://blog.csdn.net/weixin_54107527/article/details/127870247 
  • [技术干货] Spring容器详细介绍
    一、Spring容器是什么,有什么作用? Spring容器是Spring核心部分,Spring容器的主要作用是帮java程序员处理大量繁琐的任务。使得程序员只需要用代码实现自己所关注的事情。 程序员是不用创建对象的,也不用创建对象的关联。只需要从配置的信息中告诉Spring容器。 而且他还能管理对象的全生命周期。 例如: 我们知道权限和用户服务是有关联的。我们只需要提供给Spring容器这四个类的代码,用注解或配置文件告诉Spring这四个服务之间的关联,关系。 Spring在启动时就会创建好这些对象,并且建立他们之间的关联,我们可以从Spring中拿到这些对象,很方便的使用他。 二 、写配置信息的方法 xml    缺点:无法检查错误。 Java代码 注解 使用java代码 和 注解 的优点:我们可以使用很多工具来测试发现错误。 但是 还是会有很多配置要我们去写 这时候可以用Springboot Springboot优点:大量采用默认配置,帮助开发者高效的构建Spring应用。 如何用注释告诉Spring容器? 1.注解(这四个注解功能都一样,知识帮助开发者区分用途) @component{"boss_setter"}普通对象 @controller{""}处理http的response,request对象 表示是一个控制器对象 @Service{" "}服务层的对象 @Repository数据存储层的对象 三、Spring容器 BeanFactory ApplicationContext 两者区别:  ApplicationContext是BeanFactory的派生容器。 Application在BeanFactory原有功能的基础上还有面向实际的 高级功能 国际化接口 ,MessageSource,ResourceLoader(可以去加载外面资源的接口),ApplicationEvent的publish这样一些 应用事件发布接口。  最大的区别是 ApplicationContext在启动时就把所有的对象都创建对象。 ———————————————— 原文链接:https://blog.csdn.net/Victor_e/article/details/126528788 
  • [技术干货] 理解Spring容器、BeanFactory和ApplicationContext
    理解Spring容器、BeanFactory和ApplicationContext初学Spring时一定会对它的容器概念有所困惑,对context应用上下文感到无法理解,我这里参考他人的博客以及自己的理解做了一些总结,主要给自己的Java学习之路做一些总结性工作,另外希望给需要帮助的人提供一些指南。下面图中【实线】为继承extends,【虚线】为实现implements。一. spring容器理解spring容器可以理解为生产对象(OBJECT)的地方,在这里容器不只是帮我们创建了对象那么简单,它负责了对象的整个生命周期--创建、装配、销毁。而这里对象的创建管理的控制权都交给了Spring容器,所以这是一种控制权的反转,称为IOC容器,而这里IOC容器不只是Spring才有,很多框架也都有该技术。二. BeanFactory和ApplicationContext之间的关系BeanFactory和ApplicationContext是Spring的两大核心接口,而其中ApplicationContext是BeanFactory的子接口。它们都可以当做Spring的容器,Spring容器是生成Bean实例的工厂,并管理容器中的Bean。在基于Spring的Java EE应用中,所有的组件都被当成Bean处理,包括数据源,Hibernate的SessionFactory、事务管理器等。生活中我们一般会把生产产品的地方称为工厂,而在这里bean对象的地方官方取名为BeanFactory,直译Bean工厂(com.springframework.beans.factory.BeanFactory),我们一般称BeanFactory为IoC容器,而称ApplicationContext为应用上下文。Spring的核心是容器,而容器并不唯一,框架本身就提供了很多个容器的实现,大概分为两种类型:一种是不常用的BeanFactory,这是最简单的容器,只能提供基本的DI功能;一种就是继承了BeanFactory后派生而来的ApplicationContext(应用上下文),它能提供更多企业级的服务,例如解析配置文本信息等等,这也是ApplicationContext实例对象最常见的应用场景。三. BeanFactory详情介绍Spring容器最基本的接口就是BeanFactory。BeanFactory负责配置、创建、管理Bean,它有一个子接口ApplicationContext,也被称为Spring上下文,容器同时还管理着Bean和Bean之间的依赖关系。spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说,DefaultListableBeanFactory 是整个spring ioc的始祖。BeanFactory结构.png接口介绍:1.BeanFactory接口: 是Spring bean容器的根接口,提供获取bean,是否包含bean,是否单例与原型,获取bean类型,bean 别名的方法 。它最主要的方法就是getBean(String beanName)。2.BeanFactory的三个子接口: * HierarchicalBeanFactory:提供父容器的访问功能 * ListableBeanFactory:提供了批量获取Bean的方法 * AutowireCapableBeanFactory:在BeanFactory基础上实现对已存在实例的管理3.ConfigurableBeanFactory:主要单例bean的注册,生成实例,以及统计单例bean4.ConfigurableListableBeanFactory:继承了上述的所有接口,增加了其他功能:比如类加载器,类型转化,属性编辑器,BeanPostProcessor,作用域,bean定义,处理bean依赖关系, bean如何销毁…5.实现类DefaultListableBeanFactory详细介绍:实现了ConfigurableListableBeanFactory,实现上述BeanFactory所有功能。它还可以注册BeanDefinition接口详细介绍请参考:揭秘BeanFactory四. ApplicationContext介绍如果说BeanFactory是Sping的心脏,那么ApplicationContext就是完整的身躯了。ApplicationContext结构图.pngApplicationContext类结构树.pngApplicationContext常用实现类作用AnnotationConfigApplicationContext从一个或多个基于java的配置类中加载上下文定义,适用于java注解的方式。ClassPathXmlApplicationContext从类路径下的一个或多个xml配置文件中加载上下文定义,适用于xml配置的方式。FileSystemXmlApplicationContext从文件系统下的一个或多个xml配置文件中加载上下文定义,也就是说系统盘符中加载xml配置文件。AnnotationConfigWebApplicationContext专门为web应用准备的,适用于注解方式。XmlWebApplicationContext从web应用下的一个或多个xml配置文件加载上下文定义,适用于xml配置方式。Spring具有非常大的灵活性,它提供了三种主要的装配机制:在XMl中进行显示配置在Java中进行显示配置隐式的bean发现机制和自动装配*组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。*自动装配(autowiring):Spring自动满足bean之间的依赖。(使用的优先性: 3>2>1)尽可能地使用自动配置的机制,显示配置越少越好。当必须使用显示配置bean的时候(如:有些源码不是由你来维护的,而当你需要为这些代码配置bean的时候),推荐使用类型安全比XML更加强大的JavaConfig。最后只有当你想要使用便利的XML命名空间,并且在JavaConfig中没有同样的实现时,才使用XML。代码示例:通过xml文件将配置加载到IOC容器中<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--若没写id,则默认为com.test.Man#0,#0为一个计数形式--><bean id="man" class="com.test.Man"></bean></beans>public class Test {public static void main(String[] args) {//加载项目中的spring配置文件到容器//ApplicationContext context = new ClassPathXmlApplicationContext("resouces/applicationContext.xml");//加载系统盘中的配置文件到容器ApplicationContext context = new FileSystemXmlApplicationContext("E:/Spring/applicationContext.xml");//从容器中获取对象实例Man man = context.getBean(Man.class);man.driveCar();}}通过java注解的方式将配置加载到IOC容器//同xml一样描述bean以及bean之间的依赖关系@Configurationpublic class ManConfig {@Beanpublic Man man() {return new Man(car());}@Beanpublic Car car() {return new QQCar();}}public class Test {public static void main(String[] args) {//从java注解的配置中加载配置到容器ApplicationContext context = new AnnotationConfigApplicationContext(ManConfig.class);//从容器中获取对象实例Man man = context.getBean(Man.class);man.driveCar();}}隐式的bean发现机制和自动装配/*** 这是一个游戏光盘的实现*///这个简单的注解表明该类回作为组件类,并告知Spring要为这个创建bean。@Componentpublic class GameDisc implements Disc{@Overridepublic void play() {System.out.println("我是马里奥游戏光盘。");}}不过,组件扫描默认是不启用的。我们还需要显示配置一下Spring,从而命令它去寻找@Component注解的类,并为其创建bean。@Configuration@ComponentScanpublic class DiscConfig {}我们在DiscConfig上加了一个@ComponentScan注解表示在Spring中开启了组件扫描,默认扫描与配置类相同的包,就可以扫描到这个GameDisc的Bean了。这就是Spring的自动装配机制。除了提供BeanFactory所支持的所有功能外ApplicationContext还有额外的功能默认初始化所有的Singleton,也可以通过配置取消预初始化。继承MessageSource,因此支持国际化。资源访问,比如访问URL和文件。事件机制。同时加载多个配置文件。以声明式方式启动并创建Spring容器。注:由于ApplicationContext会预先初始化所有的Singleton Bean,于是在系统创建前期会有较大的系统开销,但一旦ApplicationContext初始化完成,程序后面获取Singleton Bean实例时候将有较好的性能。也可以为bean设置lazy-init属性为true,即Spring容器将不会预先初始化该bean。参考文章(一部分在上述链接中,这里就不加了):BeanFactory和ApplicationContextSpring容器BeanFactory和ApplicationContext对比Spring基础篇——Spring容器和应用上下文理解ApplicationContext探究Spring 装配bean的三种方式(注解,xml,自动装配)
  • [技术干货] spring容器与对象
    一. spring容器理解spring容器可以理解为生产对象(OBJECT)的地方,在这里容器不只是帮我们创建了对象那么简单,它负责了对象的整个生命周期--创建、装配、销毁。而这里对象的创建管理的控制权都交给了Spring容器,所以这是一种控制权的反转,称为IOC容器,而这里IOC容器不只是Spring才有,很多框架也都有该技术。二. BeanFactory和ApplicationContext之间的关系BeanFactory和ApplicationContext是Spring的两大核心接口,而其中ApplicationContext是BeanFactory的子接口。它们都可以当做Spring的容器,Spring容器是生成Bean实例的工厂,并管理容器中的Bean。在基于Spring的Java EE应用中,所有的组件都被当成Bean处理,包括数据源,Hibernate的SessionFactory、事务管理器等。生活中我们一般会把生产产品的地方称为工厂,而在这里bean对象的地方官方取名为BeanFactory,直译Bean工厂(com.springframework.beans.factory.BeanFactory),我们一般称BeanFactory为IoC容器,而称ApplicationContext为应用上下文。Spring的核心是容器,而容器并不唯一,框架本身就提供了很多个容器的实现,大概分为两种类型:一种是不常用的BeanFactory,这是最简单的容器,只能提供基本的DI功能;一种就是继承了BeanFactory后派生而来的ApplicationContext(应用上下文),它能提供更多企业级的服务,例如解析配置文本信息等等,这也是ApplicationContext实例对象最常见的应用场景。三. BeanFactory详情介绍Spring容器最基本的接口就是BeanFactory。BeanFactory负责配置、创建、管理Bean,它有一个子接口ApplicationContext,也被称为Spring上下文,容器同时还管理着Bean和Bean之间的依赖关系。spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说,DefaultListableBeanFactory 是整个spring ioc的始祖。BeanFactory结构.png接口介绍:1.BeanFactory接口: 是Spring bean容器的根接口,提供获取bean,是否包含bean,是否单例与原型,获取bean类型,bean 别名的方法 。它最主要的方法就是getBean(String beanName)。2.BeanFactory的三个子接口: * HierarchicalBeanFactory:提供父容器的访问功能 * ListableBeanFactory:提供了批量获取Bean的方法 * AutowireCapableBeanFactory:在BeanFactory基础上实现对已存在实例的管理3.ConfigurableBeanFactory:主要单例bean的注册,生成实例,以及统计单例bean4.ConfigurableListableBeanFactory:继承了上述的所有接口,增加了其他功能:比如类加载器,类型转化,属性编辑器,BeanPostProcessor,作用域,bean定义,处理bean依赖关系, bean如何销毁…5.实现类DefaultListableBeanFactory详细介绍:实现了ConfigurableListableBeanFactory,实现上述BeanFactory所有功能。它还可以注册BeanDefinition接口详细介绍请参考:揭秘BeanFactory四. ApplicationContext介绍如果说BeanFactory是Sping的心脏,那么ApplicationContext就是完整的身躯了。ApplicationContext结构图.pngApplicationContext类结构树.pngApplicationContext常用实现类作用AnnotationConfigApplicationContext从一个或多个基于java的配置类中加载上下文定义,适用于java注解的方式。ClassPathXmlApplicationContext从类路径下的一个或多个xml配置文件中加载上下文定义,适用于xml配置的方式。FileSystemXmlApplicationContext从文件系统下的一个或多个xml配置文件中加载上下文定义,也就是说系统盘符中加载xml配置文件。AnnotationConfigWebApplicationContext专门为web应用准备的,适用于注解方式。XmlWebApplicationContext从web应用下的一个或多个xml配置文件加载上下文定义,适用于xml配置方式。Spring具有非常大的灵活性,它提供了三种主要的装配机制:在XMl中进行显示配置在Java中进行显示配置隐式的bean发现机制和自动装配*组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。*自动装配(autowiring):Spring自动满足bean之间的依赖。(使用的优先性: 3>2>1)尽可能地使用自动配置的机制,显示配置越少越好。当必须使用显示配置bean的时候(如:有些源码不是由你来维护的,而当你需要为这些代码配置bean的时候),推荐使用类型安全比XML更加强大的JavaConfig。最后只有当你想要使用便利的XML命名空间,并且在JavaConfig中没有同样的实现时,才使用XML。代码示例:通过xml文件将配置加载到IOC容器中<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--若没写id,则默认为com.test.Man#0,#0为一个计数形式--><bean id="man" class="com.test.Man"></bean></beans>public class Test {public static void main(String[] args) {//加载项目中的spring配置文件到容器//ApplicationContext context = new ClassPathXmlApplicationContext("resouces/applicationContext.xml");//加载系统盘中的配置文件到容器ApplicationContext context = new FileSystemXmlApplicationContext("E:/Spring/applicationContext.xml");//从容器中获取对象实例Man man = context.getBean(Man.class);man.driveCar();}}通过java注解的方式将配置加载到IOC容器//同xml一样描述bean以及bean之间的依赖关系@Configurationpublic class ManConfig {@Beanpublic Man man() {return new Man(car());}@Beanpublic Car car() {return new QQCar();}}public class Test {public static void main(String[] args) {//从java注解的配置中加载配置到容器ApplicationContext context = new AnnotationConfigApplicationContext(ManConfig.class);//从容器中获取对象实例Man man = context.getBean(Man.class);man.driveCar();}}隐式的bean发现机制和自动装配/*** 这是一个游戏光盘的实现*///这个简单的注解表明该类回作为组件类,并告知Spring要为这个创建bean。@Componentpublic class GameDisc implements Disc{@Overridepublic void play() {System.out.println("我是马里奥游戏光盘。");}}不过,组件扫描默认是不启用的。我们还需要显示配置一下Spring,从而命令它去寻找@Component注解的类,并为其创建bean。@Configuration@ComponentScanpublic class DiscConfig {}我们在DiscConfig上加了一个@ComponentScan注解表示在Spring中开启了组件扫描,默认扫描与配置类相同的包,就可以扫描到这个GameDisc的Bean了。这就是Spring的自动装配机制。除了提供BeanFactory所支持的所有功能外ApplicationContext还有额外的功能默认初始化所有的Singleton,也可以通过配置取消预初始化。继承MessageSource,因此支持国际化。资源访问,比如访问URL和文件。事件机制。同时加载多个配置文件。以声明式方式启动并创建Spring容器。注:由于ApplicationContext会预先初始化所有的Singleton Bean,于是在系统创建前期会有较大的系统开销,但一旦ApplicationContext初始化完成,程序后面获取Singleton Bean实例时候将有较好的性能。也可以为bean设置lazy-init属性为true,即Spring容器将不会预先初始化该bean。原文链接:https://blog.csdn.net/s573626822/article/details/109599329
  • [技术干货] Spring详解 容器及实例化
    1. Spring容器1.1 容器的定义我们先看官网中的一句话:The org.springframework.context.ApplicationContext interface represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans.翻译下来大概就是:Spring IOC容器就是一个org.springframework.context.ApplicationContext的实例化对象容器负责了实例化,配置以及装配一个bean那么我们可以说:从代码层次来看:Spring容器就是一个实现了ApplicationContext接口的对象,从功能上来看: Spring 容器是 Spring 框架的核心,是用来管理对象的。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。1.2 容器工作方式我们直接看官网上的一张图片,如下:Spring容器通过我们提交的pojo类以及配置元数据产生一个充分配置的可以使用的系统这里说的配置元数据,实际上我们就是我们提供的XML配置文件,或者通过注解方式提供的一些配置信息2. Spring Bean2.1 Spring Bean实例化从官网上来看,主要有以下三种方法构造方法通过静态工厂方法通过实例工厂方法这三种例子,官网都有具体的演示,这里就不再贴了,我们通过自己查阅部分源码,来验证我们在官网得到的结论,然后通过debug等方式进行验证。我们再从代码的角度进行一波分析,这里我们直接定位到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance这个方法中,具体定位步骤不再演示了,大家可以通过形如下面这段代码:ClassPathXmlApplicationContext cc =// 这里我们通过xml配置实例化一个容器new ClassPathXmlApplicationContext("classpath:application.xml");MyServiceImpl luBan = (MyServiceImpl) cc.getBean("myServiceImpl");直接main方法运行,然后在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance这个方法的入口打一个断点,如图:接下来我们对这个方法进行分析,代码如下:protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// 1.获取这个bean的class属性,确保beanDefinition中beanClass属性已经完成解析// 我们通过xml从<bean>标签中解析出来的class属性在刚刚开始的时候必定是个字符串Class<?> beanClass = resolveBeanClass(mbd, beanName);// 省略异常判断代码.....// 2.通过beanDefinition中的supplier实例化这个beanSupplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}// 3.通过FactoryMethod实例化这个beanif (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}// 4.下面这段代码都是在通过构造函数实例化这个Bean,分两种情况,一种是通过默认的无参构造,一种 是通过推断出来的构造函数boolean resolved = false;boolean autowireNecessary = false;if (args == null) {synchronized (mbd.constructorArgumentLock) {if (mbd.resolvedConstructorOrFactoryMethod != null) {resolved = true;autowireNecessary = mbd.constructorArgumentsResolved;}}}if (resolved) {if (autowireNecessary) {return autowireConstructor(beanName, mbd, null, null);}else {return instantiateBean(beanName, mbd);}}// Candidate constructors for autowiring?Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {return autowireConstructor(beanName, mbd, ctors, args);}// Preferred constructors for default construction?ctors = mbd.getPreferredConstructors();if (ctors != null) {return autowireConstructor(beanName, mbd, ctors, null);}// No special handling: simply use no-arg constructor.return instantiateBean(beanName, mbd);}我们主要关注进行实例化的几个方法:通过BeanDefinition中的instanceSupplier直接获取一个实例化的对象。这个instanceSupplier属性我本身不是特别理解,在xml中的标签以及注解的方式都没有找到方式配置这个属性。后来在org.springframework.context.support.GenericApplicationContext这个类中找到了以下两个方法经过断点测试,发现这种情况下,在实例化对象时会进入上面的supplier方法。下面是测试代码:public static void main(String[] args) {// AnnotationConfigApplicationContext是GenericApplicationContext的一个子类AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();ac.registerBean("service", Service.class,Service::new);ac.refresh();System.out.println(ac.getBean("service"));}这个方法一般不常用,平常我们也使用不到,就不做过多探究,笔者认为,这应该是Spring提供的一种方便外部扩展的手段,让开发者能够更加灵活的实例化一个bean。接下来我们通过不同的创建bean的手段,来分别验证对象的实例化方法通过@compent,@Service等注解的方式测试代码:public class Main {public static void main(String[] args) {// 通过配置类扫描AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);System.out.println(ac.getBean(Service.class));}}@Componentpublic class Service {}可以发现,代码执行到最后一行,同时我们看代码上面的注释可以知道,当没有进行特殊的处理的时候,默认会使用无参构造函数进行对象的实例化通过普通XML的方式(同@compent注解,这里就不赘诉了)通过@Configuration注解的方式测试代码:public class Main {public static void main(String[] args) {// 通过配置类扫描AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);// 这里将测试对象换为config即可,同时记得将条件断点更改为beanName.equlas("config")System.out.println(ac.getBean(config.class));}}同样,断点也进入最后一行通过@Bean的方式测试代码:@Configuration@ComponentScan("com.dmz.official")public class Config {@Beanpublic Service service(){return new Service();}}public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext ac =new AnnotationConfigApplicationContext(Config.class);System.out.println(ac.getBean("service"));}}可以发现,通过@Bean方法创建对象时,Spring底层是通过factoryMethod的方法进行实例化对象的。Spring会在我们需要实例化的这个对象对应的BeanDefinition中记录factoryBeanName是什么(在上面的例子中factoryBeanName就是config),同时会记录这个factoryBean中创建对象的factoryMethodName是什么,最后通过factoryBeanName获取一个Bean然后反射调用factoryMethod实例化一个对象。这里我们需要注意几个概念:这里所说的通过静态工厂方式通过factoryBeanName获取一个Bean,注意,这个Bean,不是一个FactoryBean。也就是说不是一个实现了org.springframework.beans.factory.FactoryBean接口的Bean。至于什么是FactoryBean我们在后面的文章会认真分析提到了一个概念BeanDefinition,它就是Spring对自己所管理的Bean的一个抽象。不懂可以暂且跳过,后面有文章会讲到。通过静态工厂方法的方式测试代码:public static void main(String[] args) {ClassPathXmlApplicationContext cc =new ClassPathXmlApplicationContext("application.xml");System.out.println(cc.getBean("service"));}<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!-- <bean id="myServiceImpl" class="com.dmz.official.service.Service"/>--><!-- the factory bean, which contains a method called get() --><bean id="myFactoryBean" class="com.dmz.official.service.MyFactoryBean"><!-- inject any dependencies required by this locator bean --></bean><!-- 测试实例工厂方法创建对象--><bean id="clientService"factory-bean="myFactoryBean"factory-method="get"/><!--测试静态工厂方法创建对象--><bean id="service"class="com.dmz.official.service.MyFactoryBean"factory-method="staticGet"/></beans>可以发现,这种情况也进入了instantiateUsingFactoryMethod方法中。通过静态工厂方法这种方式特殊之处在于,包含这个静态方法的类,不需要实例化,不需要被Spring管理。Spring的调用逻辑大概是:通过<bean>标签中的class属性得到一个Class对象通过Class对象获取到对应的方法名称的Method对象最后反射调用Method.invoke(null,args)因为是静态方法,方法在执行时,不需要一个对象。通过实例工厂方法的方式测试代码(配置文件不变):public static void main(String[] args) {ClassPathXmlApplicationContext cc =new ClassPathXmlApplicationContext("application.xml");System.out.println(cc.getBean("clientService"));}还是执行的这个方法。这个方法的执行过程我断点跟踪了以后,发现跟@Bean方式执行的流程是一样的。这里也不再赘述了。到这里,这段代码我们算结合官网大致过了一遍。其实还遗留了以下几个问题:Spring是如何推断构造函数的?我们在上面验证的都是无参的构造函数,并且只提供了一个构造函数Spring是如何推断方法的?不管是静态工厂方法,还是实例工厂方法的方式,我们都只在类中提供了一个跟配置匹配的方法名,假设我们对方法进行了重载呢?要说清楚这两个问题需要比较深入的研究代码,同时进行测试。我们在官网学习过程中,暂时不去强求这类问题。这里提出来是为了在源码学习过程中,我们可以带一定目的性去阅读。实例化总结:对象实例化,只是得到一个对象,还不是一个完全的Spring中的Bean,我们实例化后的这个对象还没有完成依赖注入,没有走完一系列的声明周期,这里需要大家注意Spring官网上指明了,在Spring中实例化一个对象有三种方式:构造函数实例工厂方法静态工厂方法我自己总结如下结论:Spring通过解析我们的配置元数据,以及我们提供的类对象得到一个Beanfinition对象。通过这个对象可以实例化出一个java bean对象。主要流程如图:这篇文章到这里就结束了,主要学习了Spring官网中的1.2,1.3两小节。下篇文章,我们开始学习1.4中的知识。主要涉及到依赖注入的一些内容,也是我们Spring中非常重要的一块内容哦原文链接:https://blog.csdn.net/fedorafrog/article/details/112785956
  • [技术干货] 什么是Spring?Spring容器介绍
    一、什么是spring? spring是2003年兴起的一个轻量级的java开发框架,它是为了解决企业应用开发的复杂性而创建的。 spring是一个容器,用于降低代码间的耦合度,根据不同情况(不同代码),采用IoC(用于主业务逻辑解耦合)和AOP(用于系统级服务与主业务逻辑解耦合)两种技术进行解耦合。 上面是spring架构图,每一块代表一个jar包,例如第一块由5个jar包组成。 二、spring的特点 1.非侵入式 spring框架的API不会在业务逻辑上出现,即业务逻辑是POJO(java原生类,不需要依赖任何额外引入的jar)。由于业务逻辑中没有spring的API,所以业务逻辑可以从spring框架迅速移植到其他框架。  2.容器 spring作为一个容器,可以管理对象的生命周期、对象与对象之间的依赖关系。可以通过配置文件,来定义对象,以及设置其与其他对象的依赖关系。 3.IoC 控制反转,即实例的创建不是由调用者完成,而是由spring容器完成,并注入调用者。容器在对象初始化时不等对象请求就主动将依赖传递给它。 4.AOP 面向切面编程,是一种编程思想,是面对对象编程OOP的补充。很多框架都实现了对AOP编程思想的实现。spring也提供了面向切面编程的丰富支持,允许分离应用的业务逻辑与系统级服务(如日志和事务管理)进行开发。 我们可以把日志、安全和事务管理等服务理解成一个“切面”,以前都是直接把这些服务写到业务逻辑代码当中,这样有两点不好:(1)业务逻辑代码不纯净,不便于阅读理解。(2)这些服务是会被业务逻辑反复使用的,完全可以剥离出来做到复用。AOP就是解决这个问题的,它可以把这些服务剥离出来形成一个“切面”,然后将“切面”动态的织入到业务逻辑中,让业务逻辑能够享受到此“切面”的服务。 三、spring与IoC IoC是一种思想,指将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,将程序代码本身反转到了外部容器。 IoC是一个概念,是一种思想,其实现方式多种多样。当前比较流行的实现方式有两种: (1)依赖查找(DL):容器提供调用接口,程序代码则需提供查找的路径。 (2)依赖注入(DI):不做定位查询,所有工作由容器自动完成。(但是对象不能重名)。 3.1 spring的第一个程序 首先准备好spring的jar包和spring的依赖包,下面需要的jar包都是从这里来的。 必须:spring的4个基础jar包 如果需要测试,导入junit 如果需要记录日志,导入log4j和apache-commons中的logging  jar包。logging是一个适配器,它使得框架可以使用任何日志技术,而不局限于log4j等。 到这里需要的jar包就准备好了。 1)创建一个java project 2)建立服务类及其实现类  public interface SomeService {     void doSome(); } import com.hnu.service.SomeService;   public class SomeServiceImpl implements SomeService {       @Override     public void doSome() {         System.out.println("执行doSome方法!");     }   }  3)在src目录下建立applicationContext.xml(取什么名字都行,官方推荐这个名字)。xml文件需要约束,可以从spring官方jar包中的spring-framework-4.2.1.RELEASE\docs\spring-framework-reference\html这个文件夹下找到xsd-configuration.html这个文件,里面有spring的约束文件格式。 建立xml文件: <?xml version="1.0" encoding="UTF-8"?> <xml-body>   </xml-body> 添加约束:  <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:schemaLocation="         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">       <!-- bean definitions here -->   </beans> 添加自动提示(补充):拷贝http://www.springframework.org/schema/beans/spring-beans.xsd,点击window->preferences->XML Catalog 点击添加,弹出如下窗口,Key type选择URI,Key填上面复制的spring-bean的约束地址http://www.springframework.org/schema/beans/spring-beans.xsd,Location选择spring官方jar包中的spring-bean约束spring-framework-4.2.1.RELEASE\schema\beans\spring-beans-4.2.xsd ,选择4.2版本的,因为我们用的spring也是4.2的。 点击确定,然后关掉xml再打开,就有自动提示了。 4)注册bean <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:schemaLocation="         http://www.springframework.org/schema/beans          http://www.springframework.org/schema/beans/spring-beans.xsd">       <!-- bean definitions here -->     <!--注册Service -->     <bean id="myService" class="com.hnu.service.implSomeServiceImpl" />   </beans>   5)获取容器对象,实现注入: import org.junit.Test; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; import org.springframework.core.io.ClassPathResource; import com.hnu.service.SomeService; import com.hnu.service.impl.SomeServiceImpl; public class MyTest {          @Test     public void test01(){         SomeService service = new SomeServiceImpl();         service.doSome();     }          @Test     public void test02(){         //1.从类路径下找配置文件         ApplicationContext ac =new ClassPathXmlApplicationContext("applicationContext.xml");                  //2.从项目路径下找配置文件         //ApplicationContext ac =new FileSystemXmlApplicationContext("applicationContext.xml");                  //3.从指定盘符下找配置文件         //ApplicationContext ac =new FileSystemXmlApplicationContext("d:/applicationContext.xml");         SomeService service = (SomeService) ac.getBean("myService");         service.doSome();     }               @Test     public void test05(){         //另外一中容器BeanFactory         BeanFactory bf =new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));       //BeanFactory bf =new XmlBeanFactory(new FileSystemResource("applicationContext.xml"));         SomeService service = (SomeService) bf.getBean("myService");         service.doSome();     }     } ApplicationContext的getBean()方法是继承的BeanFactory的。 ApplicationContext和BeanFactory容器的区别: 1)ApplicationContext容器在进行初始化时,会将其中的所有的Bean(对象)进行创建          缺点:占用系统资源          优点:响应速度快 2)BeanFactory容器中的对象,在容器初始化时并不会被创建,而是在真正获取该对象时才被创建          缺点:相对来说响应速度慢          优点:不多占用系统资源 目前计算机资源越来约廉价,我们一般都习惯用空间换时间,所以一般第一种方式用的较多一点。 连接spring源码操作(补充): alt+鼠标左键点击ApplicationContext类,弹出如下窗口: 选择External location ,Encoding选择UTF-8,根据上面的提示找到spring-context-4.2.1的源码,一般在spring-framework-4.2.1.RELEASE\libs里面。点击ok即可连上源码。 Ctrl+T可以查看类或接口的继承关系,如下: Ctrl+O可以查看类或接口的结构 ————————————————             原文链接:https://blog.csdn.net/cqf949544506/article/details/80894673 
  • [技术干货] Spring介绍
    1. Spring是什么? Spring是一个开放源代码的设计层面框架,解决业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。  Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。  2. Spring框架特点 Spring是一个轻量级且非侵入式的开源框架 。 Spring是包含并管理应用对象的配置和生命周期的一种容器。 Spring是可以将简单的组件配置、组合成为复杂的应用的框架。 Spring通过控制反转(IoC) 促进了低耦合。 Spring提供了面向切面编程(AOP) 的丰富支持,允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发。 3. Spring框架组成 Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式。  组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:  Spring Core(核心容器):核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC)模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。  Spring Context(上下文):Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。  Spring AOP(面向切片):通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。  Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。  Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。  Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。  Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。  重要拓展:Spring Boot与Spring Cloud Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务。 Spring Cloud是基于Spring Boot实现的。 Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架。 Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置 , Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。 SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。 4. 控制反转(IOC) 控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转(IOC)后将对象的创建转移给第三方调用者,控制反转可认为是获得依赖对象的方式反转。  通俗来讲,以前所有东西都是由程序去进行控制创建(代码写死,直接实例化对象), 而现在是由调用者自行控制创建对象(由调用者按需求传入对象),把主动权交给了调用者,程序不用去管怎么创建,怎么实现了,它只负责提供一个接口。 4.1 Spring IOC容器 官方解释: The org.springframework.context.ApplicationContext interface represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans. 翻译:Spring IOC容器就是一个org.springframework.context.ApplicationContext的实例化对象,容器负责了实例化,配置以及装配一个bean 从代码层次来看:Spring IOC容器就是一个实现了ApplicationContext接口的对象, 从功能上来看: Spring 容器是 Spring 框架的核心,是用来管理对象的。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。 4.1.1 Spring IOC容器如何工作 IoC是Spring框架的核心内容,可以通过使用XML配置,也可以使用注解来实现了IoC,新版本的Spring也可以零配置实现IoC。 Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离开的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。  4.2 如何实例化Bean 构造方法 通过静态工厂方法 通过实例工厂方法  简单分析下创建bean实例的方法  protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {         // 1.获取这个bean的class属性,确保beanDefinition中beanClass属性已经完成解析         // 我们通过xml从<bean>标签中解析出来的class属性在刚刚开始的时候必定是个字符串         Class<?> beanClass = resolveBeanClass(mbd, beanName);           // 省略异常判断代码.....                  // 2.通过beanDefinition中的supplier实例化这个bean         Supplier<?> instanceSupplier = mbd.getInstanceSupplier();         if (instanceSupplier != null) {             return obtainFromSupplier(instanceSupplier, beanName);         }                  // 3.通过FactoryMethod实例化这个bean         if (mbd.getFactoryMethodName() != null) {             return instantiateUsingFactoryMethod(beanName, mbd, args);         }           // 4.下面这段代码都是在通过构造函数实例化这个Bean,分两种情况,一种是通过默认的无参构造,一种是通过推断出来的构造函数         boolean resolved = false;         boolean autowireNecessary = false;         if (args == null) {             synchronized (mbd.constructorArgumentLock) {                 if (mbd.resolvedConstructorOrFactoryMethod != null) {                     resolved = true;                     autowireNecessary = mbd.constructorArgumentsResolved;                 }             }         }                   if (resolved) {             if (autowireNecessary) {                 return autowireConstructor(beanName, mbd, null, null);             }             else {                 return instantiateBean(beanName, mbd);             }         }           // Candidate constructors for autowiring?         Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);         if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||                 mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {             return autowireConstructor(beanName, mbd, ctors, args);         }           // Preferred constructors for default construction?         ctors = mbd.getPreferredConstructors();         if (ctors != null) {             return autowireConstructor(beanName, mbd, ctors, null);         }           // No special handling: simply use no-arg constructor.         return instantiateBean(beanName, mbd);     }  通过上述代码可以发现实例化bean的方法主要分为三类:  1. 通过instanceSupplier获取,这个方法一般不常用,平常我们也使用不到,就不做过多探究,笔者认为,这应该是Spring提供的一种方便外部扩展的手段,让开发者能够更加灵活的实例化一个bean。 2. FactoryMethod,通过断点调试可以发现@compent、@Service、普通XML的方式(同@compent注解)、@Configuration等方式创建bean都是走instantiateUsingFactoryMethod(beanName, mbd, args)方法,即通过工厂方法实例化bean(包括静态工厂方法和实例工厂方法)。  public static void main(String[] args) {     ClassPathXmlApplicationContext cc =         new ClassPathXmlApplicationContext("application.xml");     System.out.println(cc.getBean("service")); } <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--    <bean id="myServiceImpl" class="com.dmz.official.service.Service"/>-->       <!-- the factory bean, which contains a method called get() -->     <bean id="myFactoryBean" class="com.dmz.official.service.MyFactoryBean">         <!-- inject any dependencies required by this locator bean -->     </bean>       <!-- 测试实例工厂方法创建对象-->     <bean id="clientService"           factory-bean="myFactoryBean"           factory-method="get"/>       <!--测试静态工厂方法创建对象-->     <bean id="service"           class="com.dmz.official.service.MyFactoryBean"           factory-method="staticGet"/> </beans>  通过静态工厂方法这种方式特殊之处在于,包含这个静态方法的类,不需要实例化,不需要被Spring管理。Spring的调用逻辑大概是: 通过<bean>标签中的class属性得到一个Class对象 通过Class对象获取到对应的方法名称的Method对象 最后反射调用Method.invoke(null,args)获取bean 3. 构造方法。 4.3 实例化总结 1. 对象实例化,只是得到一个对象,还不是一个完全的Spring中的Bean,我们实例化后的这个对象还没有完成依赖注入,没有走完一系列的声明周期,这里需要大家注意。 2. Spring官网上指明了,在Spring中实例化一个对象有三种方式: 构造函数 实例工厂方法 静态工厂方法 5. 依赖注入(DI) 5.1 依赖注入概念 依赖注入(Dependency Injection,DI):  依赖 : 指Bean对象的创建依赖于容器。 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配。 5.2 依赖注入方式 依赖注入主要分为两种方式:  构造函数注入 Setter方法注入 5.3 代码测试 public class Main02 {     public static void main(String[] args) {         AnnotationConfigApplicationContext ac = new              // config类主要完成对类的扫描             AnnotationConfigApplicationContext(Config.class);         Service service = (Service) ac.getBean("service");         service.test();     } }   // setter方法注入 @Component public class Service {       private LuBanService luBanService;       public Service() {         System.out.println("service create");     }       public void test(){         System.out.println(luBanService);     }       // 通过autowired指定使用set方法完成注入     @Autowired     public void setLuBanService(LuBanService luBanService) {         System.out.println("注入luBanService by setter");         this.luBanService = luBanService;     } }   // 构造方法注入 @Component public class Service {       private LuBanService luBanService;          public Service() {         System.out.println("service create by no args constructor");     }          // 通过Autowired指定使用这个构造函数,否则默认会使用无参     @Autowired     public Service(LuBanService luBanService) {         System.out.println("注入luBanService by constructor with arg");         this.luBanService = luBanService;         System.out.println("service create by constructor with arg");     }       public void test(){         System.out.println(luBanService);     } }   @Component public class LuBanService {     LuBanService(){         System.out.println("luBan create ");     } }  上述代码中,@Autowired 注解加在setter 方法和属性字段上的区别: 1. 直接添加@Autowired注解到字段上,不需要提供setter方法也能完成注入。以上面的例子来说,Spring会通过反射获取到Service中luBanService这个字段,然后通过反射包的方法,Filed.set(Service,luBanService)这种方式来完成注入。 2. 将@Autowired添加到setter方法时,我们可以通过断点看一下方法的调用栈,如下: 对于这种方式来说,最终是通过Method.invoke(object,args)的方式来完成注入的,这里的method对象就是我们的setter方法。 同时采用构造注入加属性注入会怎么样呢? Spring虽然能在构造函数里完成属性注入,但是这属于实例化对象阶段做的事情,那么在后面真正进行属性注入的时候,属性注入会将构造函数注入的属性覆盖。 总结:构造函数注入和属性注入使用官方推荐: 1. 构造函数注入跟setter方法注入可以混用,对于一些强制的依赖,我们最好使用构造函数注入,对于一些可选依赖我们可以采用setter方法注入。 2. Spring团队推荐使用构造函数的方式完成注入。但是对于一些参数过长的构造函数,Spring是不推荐的。 5.3 方法注入 5.3.1 Bean的作用域 类别    说明 Singleton 在Spring IoC容器中仅存在一个Bean实例,Bean以单例方式存在,Spring IoC容器中所有对象默认是单例的 Prototype 原型模式,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行new XxxBean() Request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 Session 同一个Http Session 共享一个Bean,不同的Session 使用不用Bean,仅适用于WebApplicationContext环境 5.3.2 方法注入作用 有了上面Bean的作用域基础知识之后,就能理解方法注入的作用。  @Component public class MyService {       @Autowired     private LuBanService luBanService;       public void test(int a){         luBanService.addAndPrint(a);     }   }   @Component // 原型对象 @Scope("prototype") public class LuBanService {     int i;       LuBanService() {         System.out.println("luBan create ");     }     // 每次将当前对象的属性i+a然后打印     public void addAndPrint(int a) {         i+=a;         System.out.println(i);     } }   public class Main02 {     public static void main(String[] args) {         AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);         MyService service = (MyService) ac.getBean("myService");         service.test(1);         service.test(2);         service.test(3);     } }  如上述代码,我们目的是每次都获取到不同的 LuBanService 对象,然而实际是每次调用到的LuBanService是同一个对象。当然,这也很好理解,因为在依赖注入阶段我们就完成了LuBanService的注入,之后我们在调用测试方法时,不会再去进行注入,所以我们一直使用的是同一个对象。 方法注入的作用就是解决此问题,每次使用Bean时都重新去获取。 实现方式: 1. 通过注入上下文(applicationContext对象)获取Bean  // 实现org.springframework.context.ApplicationContextAware接口 @Component public class MyService implements ApplicationContextAware {       private ApplicationContext applicationContext;       public void test(int a) {         LuBanService luBanService = ((LuBanService) applicationContext.getBean("luBanService"));         luBanService.addAndPrint(a);     }       @Override     public void setApplicationContext(@Nullable ApplicationContext applicationContext) throws BeansException {         this.applicationContext = applicationContext;     } }   // 直接注入上下文 @Component public class MyService{     @Autowired     private ApplicationContext applicationContext;       public void test(int a) {         LuBanService luBanService = ((LuBanService) applicationContext.getBean("luBanService"));         luBanService.addAndPrint(a);     } } 2. 通过@LookUp的方式(也分为注解跟XML两种方式,这里只演示注解的)  @Component public class MyService{     public void test(int a) {         LuBanService luBanService = lookUp();         luBanService.addAndPrint(a);     }       @Lookup     public LuBanService lookUp(){         return null;     } } 3. 方法注入 之 replace-method(使用很少) 5.4 依赖注入总结 Spring中的依赖注入就是属性注入。 我们知道一个对象由两部分组成:属性+行为(方法),可以说Spring通过属性注入+方法注入的方式掌控的整个bean。 属性注入跟方法注入都是Spring提供给我们用来处理Bean之间协作关系的手段。 属性注入有两种方式:构造函数,Setter方法。 方法注入(LookUp Method跟Replace Method)需要依赖动态代理完成。 方法注入对属性注入进行了一定程度上的补充,因为属性注入的情况下,原型对象可能会失去原型的意义。 6. 自动注入 Spring可以自动注入互相协作的bean之间的依赖。自动注入有以下两个好处: 自动注入能显著的减少我们指定属性或构造参数的必要,即可以不用依赖注入的方式为类注入相关依赖对象。 自动装配可以随着对象的演化更新配置。例如,如果需要向类添加依赖项,则可以自动满足该依赖项,而不需要修改配置。因此,自动装配在开发过程中特别有用,但是当我们的代码库变的稳定时,自动装配也不会影响我们将装配方式切换到精确注入。 自动注入四种模型: 模型    解释 no     这是目前Spring默认的注入模型,也可以说默认情况下Spring是关闭自动注入,必须要我们通过setter方法或者构造函数完成依赖注入,并且Spring也不推荐修改默认配置。建议我们使用精确的方式注入依赖。 byName     这种方式,我们为了让Spring完成自动注入需要提供两个条件: 提供setter方法 如果需要注入的属性为xxx,那么setter方法命名必须是setXxx,也就是说,命名必须规范 在找不到对应名称的bean的情况下,Spring也不会报错,只是不会给我们完成注入。 byType     测试代码跟之前唯一不同的就是修改配置autowire="byType",这里我们测试以下三种异常情况: 找不到合适类型的bean,发现不报异常,同时不进行注入 找到了多个合适类型的bean,Spring会直接报错Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.dmz.official.service.DmzService' available: expected single matching bean but found 2: dmzService,dmzService2 set方法中有两个参数,切两个参数都能找到唯一一个类型符合的bean,不报异常,也不进行注入 另外需要说明的是,我在测试的过程,将set方法仅仅命名为set,像这样public void set(DmzService dmzService),这种情况下Spring也不会进行注入。 我们可以发现,对于这两种注入模型都是依赖setter方法完成注入的,并且对setter方法命名有一定要求(只要我们平常遵从代码书写规范,一般也不会踩到这些坑)。第一,不能有多个参数;第二,不能仅仅命名为set constructor    当我们使用这种注入模型时,Spring会根据构造函数查找有没有对应参数名称的bean,有的话完成注入(跟前文的byName差不多),如果根据名称没找到,那么它会再根据类型进行查找,如果根据类型还是没找到,就会报错。 自动注入的缺陷: 1. 精确注入会覆盖自动注入。并且我们不能注入基本数据类型,字符串,Class类型(这些数据的数组也不行)。而且这是Spring故意这样设计的; 2. 自动注入不如精确注入准确。而且我们在使用自动注入时,对象之间的依赖关系不明确; 3. 对于一些为Spring容器生成文档的工具,无法获取依赖关系; 4. 容器中的多个bean定义可能会与自动注入的setter方法或构造函数参数指定的类型匹配。对于数组、集合或映射实例,这可能不会产生什么问题。但是,对于期望单个值的依赖项,我们无法随意确定到底有谁进行注入。如果没有唯一的bean定义可用,则会抛出异常。 补充一些注解的知识: @Autowired 与 @Qualifier  1. @Autowired(required=false) 说明:false,对象可以为null;true,对象必须存对象,不能为null。 2. @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配。 3. @Qualifier不能单独使用。 @Resource 1. @Resource如有指定的name属性,先按该属性指定的name进行byName方式查找装配;其次再进行默认的byName方式进行装配。 2. 如果以上都不成功,则按byType的方式自动装配。 3. 都不成功,则报异常。 @Autowired与@Resource异同: 1. @Autowired与@Resource都可以用来装配bean。都可以写在属性上,或写在setter方法上。 2. @Autowired 默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用。 3. @Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。 4. 它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。 ———————————————— 原文链接:https://blog.csdn.net/m0_38033199/article/details/126949283 
  • [技术干货] Spring Boot和Spring的区别
    一、SpringBoot的介绍 Spring是一个开放源代码的设计层面框架,解决业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。 Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。  简而言之,Spring框架为开发Java应用程序提供了全面的基础架构支持。它包含一些很好的功能,列如依赖注入和开箱即用的等模块。 Spring框架优点: Spring是一个轻量级的、非入侵式的框架。 控制反转(IOC),面向切面编程(AOP)。 支持事务的处理,对框架整合的支持。 总结:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。 这些模块可以大大缩短应用程序的开发时间。例如,在Java Web开发的早期阶段,我们需要编写大量的重复代码来将记录插入到数据源中。但是通过使用Spring JDBC模块的JDBCTemplate,我们可以将它简化为只需几个简单配置或者几行代码。 二、SpringBoot的介绍 拓展 1、Spring Boot框架基本上是Spring框架的扩展,它消除了设置Spring应用程序所需的复杂例行配置 2、学习SpringBoot需要掌握Spring与SpringMVC 它的目标和Spring的目标是一致的,为更快,更高效的开发生态系统铺平了道路。以下是Spring Boot中的一些功能: 通过starter这一个依赖,以简化构建和复杂的应用程序配置。 可以直接main函数启动,嵌入式web服务器,避免了应用程序部署的复杂性,Metrics度量,Helth check健康检查和外部化配置。 尽可能的自动化配置Spring功能。 三、Spring与SpringBoot的比较 Maven依赖     首先,让我们看一下使用Spring创建Web应用程序所需的最小依赖项: 与Spring不同,Spring Boot只需要一个依赖项来启动和运行Web应用程序:  在构建期间,所有其他依赖项将自动添加到最终归档中,如果构建项目时没有勾选该依 赖的功能在构建期间不会有该依赖需要在配置中手动添加。 Spring Boot为不同的Spring模块提供许多依赖项,比喻我们常用的:  spring-boot-starter-data-jpa spring-boot-starter-security spring-boot-starter-test spring-boot-starter-web spring-boot-starter-thymeleaf ———————————————— 原文链接:https://blog.csdn.net/weixin_49983304/article/details/124643580 
总条数:739 到第
上滑加载中