springBoot 与 springCloud 运行与说明

使用步骤:SpringBoot
SpringBoot准备步骤
1:添加依赖操作:
	//	继承SpringBoot父依赖,导入springCloud,通用Mapper启动器,mysql驱动,添加web启动器,tk.mybatis 减少数据库的配置
	1:添加父工程依赖:
		// springBoot 父坐标 统一依赖管理
		<parent>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-parent</artifactId>
			<version>2.0.4.RELEASE</version>
		</parent>
		<!-- springCloud -->
		<!-- 通用Mapper启动器 -->
	    <!-- mysql驱动 -->
			
	2:添加子工程依赖:
		<!-- 添加web启动器-->
		<!-- mysql驱动 -->
		<!-- tk.mybatis 减少数据库的配置-->

2:全局配置:	
	//	配置端口,数据库配置,mybatis别名
	通过 application.properties 或 application.yml(application.yaml) 来覆盖默认属性值,如有重叠属性,默认以Properties优先,形成自定义配置,
		端口
		数据库配置
		mybatis 别名

	
3:启动类:
	//	添加注解 @SpringBootApplication , @MapperScan("com.itcast.user.mapper")映射器扫描 添加了 tk.mybatis 依赖才需要
	@SpringBootApplication
	@MapperScan("com.itcast.user.mapper")	//	<- 映射器扫描 添加了 tk.mybatis 依赖才需要
	public class Application {
		public static void main(String[] args) {
			SpringApplication.run(Application.class, args);
		}
	}

	
4:编写controller:
	//	加注解 @RestController , @RequestMapping("/user")
	@RestController
	@RequestMapping("/user")
	public class UserController {

		@Autowired
		private UserService userService;
		
		@GetMapping("/{id}")
		public User queryById(@PathVariable("id")Long id){
			return userService.queryById(id);
		}
	}

	
5:编写Service:	//	加注解 @Service
	@Service
	public class UserService {

		@Autowired
		private UserMapper userMapper;

		public User queryById(Long id){
			return userMapper.selectByPrimaryKey(id);
		}
	}

	
6:编写Mapper:	
	//	继承 Mapper<User>  <-	Mapper 导入 tk.mybatis.mapper 的包
	public interface UserMapper extends Mapper<User> {	// <-	Mapper 添加的是 tk.mybatis.mapper 的包
	}


7:编写pojo:	
	//	加注解 @Table(name = "tb_user"), @Data,@Id,@KeySql(useGeneratedKeys = true)
	@Table(name = "tb_user")
	@Data
	public class User {

		@Id
		@KeySql(useGeneratedKeys = true)
		private Long id;

		private String userName; // 用户名

		private String password; // 密码

		private String name;// 姓名

		private Integer age;// 年龄

		private Integer sex;// 性别,1男性,2女性

		private Date birthday;// 出生日期

		private Date created;// 创建时间

		private Date updated;// 更新时间

		private String note;// 备注
	}	


使用步骤: 拦截器
定义一个拦截器
	public class LoginInterceptor implements HandlerInterceptor {

		private Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
		@Override
		public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
			logger.debug("preHandle method is now running!");
			return true;
		}

		@Override
		public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
			logger.debug("postHandle method is now running!");
		}

		@Override
		public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
			logger.debug("afterCompletion method is now running!");
		}
	}

注册拦截器
	@Configuration
	public class MvcConfig implements WebMvcConfigurer{
		/**
		 * 通过@Bean注解,将我们定义的拦截器注册到Spring容器
		 * @return
		 */
		@Bean
		public LoginInterceptor loginInterceptor(){
			return new LoginInterceptor();
		}

		/**
		 * 重写接口中的addInterceptors方法,添加自定义拦截器
		 * @param registry
		 */
		@Override
		public void addInterceptors(InterceptorRegistry registry) {
			// 通过registry来注册拦截器,通过addPathPatterns来添加拦截路径
			registry.addInterceptor(this.loginInterceptor()).addPathPatterns("/**");
		}
	}

静态资源的默认存放路径:
	//	常用 classpath:/static/路径
	//	ResourceProperties	类中定义了默认静态资源路径:
	- classpath:/static/	//	常用
	- classpath:/META-INF/resources/
	- classpath:/resources/
	- classpath:/public
创建返回结果实体类:
概念了解:  VO , DTO , PO
	- VO:(Value object 值对象 / View object 表现层对象):
		主要是和表现层\页面打交道用
	- DTO:(Data Transfer Object 数据传输(转换)对象):
		主要用来封装和传输数据用。
	- PO:(Persistent Object 持久化对象):
		主要数据库表的映射

依赖:

```
<parent> 				//  父类
<properties>			//  依赖管理
<dependencyManagement>	//	统一依赖管理,不继承,子类pom文件加入后才继承
<dependencies>			//	该父类下的所有子类都继承该些依赖
<build>					//	插件
```
自动配置原理:
springBoot的自动配置:	//	例如: SpringMVC 查看mvc 的自动配置类
	@Configuration	//	声明这个类是一个配置类
	
	//	此处就是满足项目的类是是Type.SERVLET类型,也就是一个普通web工程
	@ConditionalOnWebApplication(type = Type.SERVLET)	

	//	Servlet只要引入了tomcat依赖自然会有,后两个需要引入SpringMVC才会有。
	//	这里是判断是否引入了相关依赖,引入依赖后该条件成立,当前类的配置才会生效!
	@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })

	//	如果自己配置了一个WebMVCConfigurationSupport的类,那么这个默认配置就会失效!
	@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)

总结:通过实现WebMvcConfigurer并添加@Configuration 注解来实现自定义部分SpringMvc配置。

SpringCloud主要框架:
	- 服务发现	—— Netflix Eureka
	- 服务调用	—— Netflix Feign
	- 负载均衡	—— Netflix Ribbon	
	- 熔断器	—— Netflix Hystrix
	- 服务网关	—— Netflix Zuul
	- 分布式配置—— Spring Cloud Config
	- 消息总线 	—— Spring Cloud Bus
微服务的特点: 软件单一,松耦合,自包含,独立运行和部署的架构思想
	微服务和分布式有什么区别?
		微服务可以是分布式,分布式就是把业务进行拆分,把前台分开、service逻辑层以及common通用层分开,可认为是层级分离。
		微服务侧重于功能的分离,
		对于微服务来说,前台、后台、数据库等是完整的一套。


	- 单一职责:	微服务中每一个服务都对应唯一的业务能力,做到单一职责
	- 微:		微服务的服务拆分粒度很小,例如一个用户管理就可以作为一个服务。每个服务虽小,但“五脏俱全”。
	- 面向服务:	面向服务是说每个服务都要对外暴露Rest风格服务接口API。并不关心服务的技术实现,做到与平台和语言无关,也不限定用什么技术实现,只要提供Rest的接口即可。
	- 自治:		自治是说服务间互相独立,互不干扰
	  - 团队独立:每个服务都是一个独立的开发团队,人数不能过多。
	  - 技术独立:因为是面向服务,提供Rest接口,使用什么技术没有别人干涉
	  - 前后端分离:采用前后端分离开发,提供统一Rest接口,后端不用再为PC、移动段开发不同接口
	  - 数据库分离:每个服务都使用自己的数据源
	  - 部署独立,服务间虽然有调用,但要做到服务重启不影响其它服务。有利于持续集成和持续交付。每个服务都是独立的组件,可复用,可替换,降低耦合,易维护

	微服务优点
		1. 项目分解,拆分多个服务,解决了复杂性问题
		3. 每个微服务独立的开发,部署
		2. 各个服务只用提供API,让开发者可以自由选择开发技术
		4. 让开发者只关注于一个业务功能,使得每个服务都很简单
		5. 易于规模化开发,多个开发团队可以并行开发,每个团队负责一项服务
		6. 改善故障隔离。一个服务宕机不会影响其他的服务

	微服务缺点:
		1. 测试工作更加困难
		2. 部署复杂
		3. 内存占用量更高
服务调用方式: RPC 和 HTTP
常见的远程调用方式有以下2种:
	- RPC:Remote Produce Call 远程过程调用,类似的还有RMI(remote method invoke)。
		自定义数据格式,基于原生TCP通信,速度快,效率高。
		早期的webservice,现在热门的dubbo,都是RPC的典型代表.

	- Http:http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。
		现在客户端浏览器与服务端通信基本都是采用Http协议,也可以用来进行远程服务调用。
		缺点是消息封装臃肿,优势是对服务的提供和调用方没有任何技术限定,自由灵活,更符合微服务理念。
		//	现在热门的Rest风格,就可以通过http协议来实现。

如果公司全部采用Java技术栈,那么使用Dubbo作为微服务架构是一个不错的选择。
如果公司的技术栈多样化,那么SpringCloud搭建微服务是不二之选。 因此使用Http方式来实现服务间调用
SpringCloud: 微服务是一种架构方式,最终肯定需要技术架构去实施。
微服务的实现方式很多,但是最火的莫过于Spring Cloud了。为什么?
	- 后台硬:作为Spring家族的一员,有整个Spring全家桶靠山,背景十分强大。
	- 技术强:Spring作为Java领域的前辈,可以说是功力深厚。有强力的技术团队支撑,一般人还真比不了
	- 群众基础好:可以说大多数程序员的成长都伴随着Spring框架,试问:现在有几家公司开发不用Spring?SpringCloud与Spring的各个框架无缝整合,对大家来说一切都是熟悉的配方,熟悉的味道。
	- 使用方便:相信大家都体会到了SpringBoot给我们开发带来的便利,而SpringCloud完全支持SpringBoot的开发,用很少的配置就能完成微服务框架的搭建

Spring最擅长的就是集成,把世界上最好的框架拿过来,集成到自己的项目中。
SpringCloud也是一样,它将现在非常流行的一些技术整合到一起,实现了诸如:
	配置管理,服务发现,智能路由,负载均衡,熔断器,控制总线,集群状态等等功能。
其主要涉及的组件包括
	Netflix:
		- Eureka:	注册中心 --> consul , zookeeper 
		- Feign:	服务调用
		- Ribbon:	负载均衡
		- Hystix:	熔断器
		- Zuul:		服务网关 

Eureka 注册中心: // 心跳机制 注册服务
Eureka详解:
	- 心跳(续约):提供者定期通过http方式向Eureka刷新自己的状态
	- Eureka-Server:就是服务注册中心(可以是一个集群),
		提供服务注册和发现功能,对外暴露自己的地址。
	- 提供者:启动后向Eureka注册自己信息(地址,服务名称等),
		提供服务的应用,
	- 消费者:服务调用方,会定期去Eureka拉取服务列表,
		消费应用从注册中心获取服务列表,然后使用负载均衡算法选出一个服务进行调用。
Eureka注册中心 使用步骤:
1.引依赖:
	//	服务端
	<dependency>	
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
	</dependency>
	//	客户端
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>

2.配置文件:
	spring.application.name	//	属性来指定应用名称,将来会作为服务的id使用。
	//	服务端
	eureka:
	  client:
		register-with-eureka: false # 不注册自己
		fetch-registry: false #不拉取服务
		service-url: # EurekaServer的地址,现在是自己的地址,如果是集群,需要写其它Server的地址。
		  defaultZone: http://127.0.0.1:10086/eureka
	//	客户端
	eureka:
	  client:
		service-url:
		  defaultZone: http://127.0.0.1:10086/eureka
		  
	启动类的注解:
	//	服务端	// 声明这个应用是一个EurekaServer
	@EnableEurekaServer 
	//	客户端	// 开启Eureka客户端
	@EnableDiscoveryClient  //	推荐使用! 支持多种
	@EnableEurekaClient		//	不推荐! 只支持Enable


3.高可用的Eureka:
	Eureka Server: 搭建 EurekaServer 的集群,形成高可用的Eureka中心

	Eureka客户端:
		客户端注册服务到集群:	//	因为EurekaServer不止一个,因此注册服务的时候,service-url参数需要变化:
			eureka:
			  client:
				service-url: # EurekaServer地址,多个地址以','隔开
				  defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka
			
		服务提供者在启动时,会检测配置属性中的:eureka.client.register-with-erueka=true
			默认 true。如果为true,则会向EurekaServer发起一个Rest请求,并携带自己的元数据信息,
			Eureka Server会把这些信息保存到一个双层Map结构中。
				- 第一层Map的Key就是服务id,一般是配置中的spring.application.name属性
				- 第二层Map的key是服务的实例id。一般host+ serviceId + port,例如:locahost:user-service:8081
				- 值则是服务的实例对象,也就是说一个服务,可以同时启动多个不同实例,形成集群
			默认注册时使用的是主机名,如果我们想用ip进行注册,可以添加配置:
				eureka:
					instance:
						ip-address: 127.0.0.1 # ip地址
						prefer-ip-address: true # 更倾向于使用ip,而不是host名
	
	服务续约:	//	需要最迟3分钟才能剔除挂掉的服务端,90秒检测并标记,60秒统一删除标记的服务端				
		在注册服务完成以后,服务提供者会维持一个心跳(定时向EurekaServer发起Rest请求),告诉EurekaServer:“我还活着”。这个我们称为

4.服务的续约(renewal);	
	eureka:
	  instance:
		lease-renewal-interval-in-seconds: 30	//	服务续约(renew)的间隔,默认为30秒
		lease-expiration-duration-in-seconds: 90	//	服务失效时间,默认值90秒

5.获取服务列表:
		当服务消费者启动是,会检测eureka.client.fetch-registry=true参数的值,
		如果为true,则会从Eureka Server服务的列表只读备份,然后缓存在本地。
		并且每隔30秒会重新获取并更新数据。我们可以通过下面的参数来修改:
			eureka:
			  client:
				registry-fetch-interval-seconds: 30

6.服务下线、失效剔除和自我保护
	服务下线:当服务进行正常关闭操作时,
		触发一个服务下线的REST请求给Eureka Server,告诉服务注册中心:“我要下线了”。

	失效剔除:当服务非正常关闭时,
		默认每隔一段时间(默认为60秒)将当前清单中超时(默认为90秒)没有续约的服务剔除,这个操作被称为失效剔除。
		可以通过eureka.server.eviction-interval-timer-in-ms参数对其进行修改,单位是毫秒。

	自我保护:Eureka会统计服务实例最近15分钟心跳续约的比例 低于了85%
		Eureka在这段时间内不会剔除任何服务实例,直到网络恢复正常。生产环境下这很有效,
		保证了大多数服务依然可用,不过也有可能获取到失败的服务实例,
		因此服务调用者必须做好服务的失败容错。
		eureka:
		  server:
			enable-self-preservation: false # 关闭自我保护模式(缺省为打开)

7.总结:
	- Eureka 注册中心 负责管理、记录提供者的信息。
	- 服务调用者把需求发送到Eureka,Eureka会调用相应的服务。实现了服务的自动注册、发现、状态监控。
		- 服务的注册和发现都是可控制的,可以关闭也可以开启。默认都是开启
	- 注册后需要心跳,心跳周期默认30秒一次,超过90秒没法认为宕机
		- Eureka会有自我保护,当心跳失败比例超过阈值,那么开启自我保护,不再剔除服务。
		- 服务拉取默认30秒拉取一次
		- Eureka每个60秒会剔除标记为宕机的服务
	- Eureka高可用就是多台Eureka互相注册在对方上,客服端通过相互复制完成数据同步

Feign 服务调用:
	将rest请求进行隐藏,伪装成SpringMVC的Controller一样。Feign通过动态代理生成实现类。与mapper.xml类似
	@FeignClient: 声明这是一个feign的客户端,类似于@mapper
	在启动类@EnableFeignClients 	//	开启feign功能
		Feign集成了robbon负载均衡,不需要自己定义RestTemplate了

快速入门

	导入依赖:
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>
	
	开启Feign功能:
		在启动类上,添加注解,开启Feign功能
		@EnableFeignClients // 开启Feign功能

	Feign的客户端:	
		- 首先这是一个接口,Feign会通过动态代理,帮我们生成实现类。这点跟mybatis的mapper很像
		- @FeignClient,声明这是一个Feign客户端,同时通过value属性指定服务名称
		- 接口中的定义方法,完全采用SpringMVC的注解,Feign会根据注解帮我们生成URL,并访问获取结果
		@FeignClient("user-service")
		public interface UserClient {
			@GetMapping("/user/{id}")
			User queryById(@PathVariable("id") Long id);
		}
	
	改造原来的调用逻辑,使用UserClient访问:
		@RestController
		@RequestMapping("consumer")
		@Slf4j
		public class ConsumerController {

			@Autowired
			private UserClient userClient;

			@GetMapping("{id}")
			public User queryById(@PathVariable("id") Long id){
				return userClient.queryById(id);
			}
		}

负载均衡:

	RestTemplate的注册被删除了。Feign中已经自动集成了Ribbon负载均衡,因此我们不需要自己定义RestTemplate了	
	Fegin内置的ribbon默认设置了请求超时时长,默认是1000,我们可以通过手动配置来修改这个超时时长:	
		ribbon:
		  ReadTimeout: 2000 # 读取超时时长
		  ConnectTimeout: 1000 # 建立链接的超时时长
	因为ribbon内部有重试机制,一旦超时,会自动重新发起请求。如果不希望重试,可以添加配置:	
		ribbon:
		  ConnectTimeout: 1000 # 连接超时时长
		  ReadTimeout: 2000 # 数据通信超时时长
		  MaxAutoRetries: 0 # 当前服务器的重试次数
		  MaxAutoRetriesNextServer: 0 # 重试多少次服务
		  OkToRetryOnAllOperations: false # 是否对所有的请求方式都重试

Hystix 熔断器:

Hystix 熔断器:	//	Feign默认也有对Hystix的集成:	
		默认情况下是关闭的。需要通过下面的参数来开启:
			feign:
			  hystrix:
				enabled: true # 开启Feign的熔断功能	 但是,Feign中的Fallback配置不像Ribbon中那样简单了。
		(1)首先,我们要定义一个类,实现刚才编写的UserFeignClient,作为fallback的处理类
			@Component
			public class UserClientFallback implements UserClient {
				@Override
				public User queryById(Long id) {
					User user = new User();
					user.setId(id);
					user.setName("用户查询出现异常!");
					return user; 
				}
			}
			
		(2)然后在UserFeignClient中,指定刚才编写的实现类
			@FeignClient(value = "user-service", fallback = UserFeignClientFallback.class)
			public interface UserClient {
				@GetMapping("/user/{id}")
				User queryById(@PathVariable("id") Long id);
			}
			
		(3)重启测试:
			我们关闭user-service服务,然后在页面访问:

请求压缩:

	Spring Cloud Feign 支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。
	通过下面的参数即可开启请求与响应的压缩功能:
		feign:
		  compression:
			request:
			  enabled: true # 开启请求压缩
			response:
			  enabled: true # 开启响应压缩
	
	同时,我们也可以对请求的数据类型,以及触发压缩的大小下限进行设置:
		feign:
		  compression:
			request:
			  enabled: true # 开启请求压缩
			  mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
			  min-request-size: 2048 # 设置触发压缩的大小下限
	
	注:上面的数据类型、压缩大小下限均为默认值。

日志级别:

	前面讲过,通过logging.level.xx=debug来设置日志级别。然而这个对Fegin客户端而言不会产生效果。
	因为@FeignClient注解修改的客户端在被代理时,都会创建一个新的Fegin.Logger实例。
	我们需要额外指定这个日志的级别才可以。

		(1)设置cn.itcast包下的日志级别都为debug
			logging:
			  level:
				cn.itcast: debug

		(2)编写配置类,定义日志级别
			@Configuration
			public class FeignConfig {
				@Bean
				Logger.Level feignLoggerLevel(){
					return Logger.Level.FULL;
				}
			}

	这里指定的Level级别是FULL,Feign支持4种级别:
		- NONE:不记录任何日志信息,这是默认值。
		- BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
		- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
		- FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。

		(3)在FeignClient中指定配置类:
			@FeignClient(value = "user-service", fallback = UserClientFallback.class, configuration = FeignConfig.class)
			public interface UserClient {
				@GetMapping("/user/{id}")
				User queryById(@PathVariable("id") Long id);
			}

		(4)重启项目,即可看到每次访问的日志:
Zuul网关: // 网关的核心功能是:过滤和路由
	Zuul上实现限流: https://www.jianshu.com/p/d165e12df1da
	
	不管是来自于客户端(PC或移动端)的请求,还是服务内部调用。
	一切对服务的请求都会经过Zuul这个网关,然后再由网关来实现 鉴权、动态路由等等操作。
	Zuul就是我们服务的统一入口。保证服务的安全性,需要进行权限控制,开放服务会破坏rest api的无状态特点。

操作步骤:

	添加依赖:
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
			</dependency>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
			</dependency>
		</dependencies>
				
	加注解:
		@EnableZuulProxy:	// 开启Zuul的网关功能  添加在启动类
		@SpringCouldApplication
		
	配置文件:
		server:
		  port: 10010 #服务端口
		spring: 
		  application:  
			name: api-gateway #指定服务名
		eureka:
		  client:
			service-url:
			  defaultZone: http://127.0.0.1:10086/eureka
		  instance: 
			prefer-ip-address: true
			ip-address: 127.0.0.1zuul: #映射规则
		zuul:	 
		  routes:
		  	//	路由前缀	
			prefix: /api   # 指定了路由的前缀,这样在发起请求时,路径就要以/api开头。
							//	路径/api/user-service/user/1将会被代理到/user-service/user/1
			user-service: /user-service/**  # 指定服务名称: 这里是映射路径
			//	因为有默认的路由规则,如果想要禁用某个路由规则,可以这样:
			ignored-service:  #忽略路由
			  - user-service 	#服务端的ID名
			  - consumer
			  ...

过滤器: // 身份认证和安全 , 审查与监控 , 动态路由 , 压力测试 , 负载分配 , 静态响应处理 , 多区域弹性

1.ZuulFilter 是过滤器的顶级父类,其中定义的4个最重要的方法:
		public abstract ZuulFilter implements IZuulFilter{

			abstract public String filterType();

			abstract public int filterOrder();
			
			boolean shouldFilter();// 来自IZuulFilter

			Object run() throws ZuulException;// IZuulFilter
		}
		
		- shouldFilter:返回一个Boolean值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
		- run:过滤器的具体业务逻辑。
		- filterType:返回字符串,代表过滤器的类型。包含以下4种:
		  - pre:请求在被路由之前执行
		  - route:在路由请求时调用
		  - post:在routing和errror过滤器之后调用
		  - error:处理请求时发生错误调用
		- filterOrder:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。
			
2.过滤器执行生命周期:
	- 正常流程:
		- 请求到达首先会经过pre类型过滤器,而后到达routing类型,进行路由,请求就到达真正的服务提供者,执行请求,返回结果后,会到达post过滤器。而后返回响应。
	- 异常流程:
		- 整个过程中,pre或者routing过滤器出现异常,都会直接进入error过滤器,再error处理完毕后,会将请求交给POST过滤器,最后返回给用户。
	 	- 如果是error过滤器自己出现异常,最终也会进入POST过滤器,而后返回。
	  	- 如果是POST过滤器出现异常,会跳转到error过滤器,但是与pre和routing不同的时,请求不会再到达POST过滤器了。

	使用场景:
		- 请求鉴权:一般放在pre类型,如果发现没有访问权限,直接就拦截了
		- 异常处理:一般会在error类型和post类型过滤器中结合来处理。
		- 服务调用时长统计:pre和post结合使用。

3.自定义过滤器:	//	基本逻辑:如果请求中有access-token参数,则认为请求有效,放行。

4.负载均衡和熔断:
	Zuul中默认 集成了 Ribbon负载均衡 和Hystix熔断机制
	但是所有的超时策略都是走的默认值,比如熔断超时时间只有1S,很容易就触发了。
	因此建议我们手动进行配置:
		hystrix:
		  command:
			default:
			  execution:
				isolation:
				  thread:
					timeoutInMilliseconds: 6000
		ribbon:
		  ConnectTimeout: 1000
		  ReadTimeout: 2000
		  MaxAutoRetries: 0
		  MaxAutoRetriesNextServer: 0

	
5.Zuul的高可用:
		启动多个Zuul服务,自动注册到Eureka,形成集群。
		内部访问:自动负载均衡
		外部访问:使用其他的服务网关, 比如:Nginx
Ribbon 负载均衡 :
启动了多个server后,导致消费者不知道调用哪一个服务,这时使用Eureka所集成的Ribbon
	
负载均衡策略:轮询
	如果要修改策略(随机),则要修改消费者中的yml文件,由SpringBoot提供,
User-service:
	Ribbon:
		NFLoadBalancerRuleClassName: com.netflix.loadbalance.RandomRule
			

使用步骤:

引依赖:
	不需要,在Eureka中包含了该依赖
启动类的注解:
	//	客户端 的启动类 restTemplate方法上
	@LoadBalanced
客户端的表现层代码:
	//	修改调用方式,不再手动获取ip和端口,而是直接通过服务名称调用:
	@GetMapping("{id}")
	public User queryById(@PathVariable("id") Long id){
		String url = "http://user-service/user/" + id;	//	直接通过服务名称调用
		User user = restTemplate.getForObject(url, User.class);
		return user;
	}

负载均衡策略		
	SpringBoot也帮我们提供了修改负载均衡规则的配置入口:	
		user-service:	//	服务名称
		  ribbon:
			NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule	//	值就是IRule的实现类

附加:
	Ribbon默认是采用懒加载,即第一次访问时才会去创建负载均衡客户端。
	往往会出现超时。如果需要采用饥饿加载,即项目启动即创建,可以这样配置
		ribbon:
		  eager-load:
			enabled: true
Hystrix 熔断器: // 一种保护机制 雪崩问题
Hystix解决雪崩问题的手段主要是服务降级,包括:
	- 线程隔离
	- 服务熔断

服务降级: 	触发Hystix服务降级的情况:
	- 线程池已满
	- 请求超时

	Hystrix为每个依赖服务调用分配一个小的线程池,
	如果线程池已满调用将被立即拒绝,默认不采用排队.加速失败判定时间。

	用户的请求将不再直接访问服务,而是通过线程池中的空闲线程来访问服务,
	如果线程池已满,或者请求超时,则会进行降级处理

	用户的请求故障时,不会被阻塞,至少可以看到一个执行结果(例如返回友好的提示信息).

操作步骤:

1.引入依赖:	//	在所需要的服务端添加
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
	</dependency>
	
2.开启熔断:	
		@EnableCircuitBreaker	在启动类上添加注解
		
		@SpringCloudApplication 组合注解等同于
			@SpringBootApplication
			@EnableDiscoveryClient	
			@EnableCircuitBreaker	在启动类上添加注解
		
3.编写降级逻辑:	//	要使用HystixCommond来完成:
		@GetMapping("{id}")
			@HystrixCommand(fallbackMethod = "queryByIdFallBack")	
			public String queryById(@PathVariable("id") Long id){
				String url = "http://user-service/user/" + id;
				String user = restTemplate.getForObject(url, String.class);
				return user;
			}

			public String queryByIdFallBack(Long id){	//	用来声明一个降级逻辑的方法
				log.error("查询用户信息失败,id:{}", id);
				return "对不起,网络太拥挤了!";
			}
						
		
4.默认的Fallback:	
		把Fallback配置加在类上,实现默认fallback:
			@RestController
			@RequestMapping("consumer")
			@DefaultProperties(defaultFallback = "defaultFallBack")	//	在类上指明统一的失败降级方法
			public class ConsumerController {

				@Autowired
				private RestTemplate restTemplate;

				@GetMapping("{id}")
				@HystrixCommand
				public String queryById(@PathVariable("id") Long id){
					String url = "http://user-service/user/" + id;
					String user = restTemplate.getForObject(url, String.class);
					return user;
				}

				public String defaultFallBack(){
					return "默认提示:对不起,网络太拥挤了!";
				}
			}
		
5.超时设置:	
		请求在超过1秒后都会返回错误信息,这是因为Hystix的默认超时时长为1通过配置修改这个值:
			hystrix:
			  command:
				default:
				  execution:
					isolation:
					  thread:
						timeoutInMilliseconds: 2000
						
		这个配置会作用于全局所有方法。				



6.服务熔断:
	状态机有3个状态:
		- Closed:关闭状态(断路器关闭),所有请求都正常访问。
		- Open:打开状态(断路器打开),所有请求都会被降级。Hystix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全关闭。默认失败比例的阈值是50%,请求次数最少不低于20次。
		- Half Open:半开状态,open状态不是永久的,打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放1次请求通过,若这个请求是健康的,则会关闭断路器,否则继续保持打开,再次进行5秒休眠计时。

7.熔断器的默认触发阈值是20次请求,不好触发。休眠时间时5秒,时间太短,不易观察,
	为了测试方便,我们可以通过配置修改熔断策略:
	circuitBreaker.requestVolumeThreshold=10	//	触发熔断的最小请求次数,默认20
	circuitBreaker.sleepWindowInMilliseconds=10000	//	触发熔断的失败请求最小占比,默认50%
	circuitBreaker.errorThresholdPercentage=50	//	休眠时长,默认是5000毫秒
Spring Cloud Config 分布式配置 :
	服务配置文件的统一管理	
		配置服务器: 可横向扩展、集中式的配置服务器
		配置客户端: 操作服务器的配置内容

	spring-cloud-bus:消息总线	//	及时接收新的配置信息
	
	Spring-cloud-stream:消息通信
	
	spring-cloud-hystrix-dashboard:容错统计,形成图形化界面
	
	spring-cloud-sleuth:链路追踪 结合Zipkin
微服务搭建:

创建父工程项目:

1. 导入依赖:
	<packaging>pom</packaging>

	<parent>	//	继承父类 springBoot
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.6.RELEASE</version>
		<relativePath/>
	</parent>

	<properties>	//	统一依赖版本管理
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<spring-cloud.version>Finchley.SR2</spring-cloud.version>
		<mapper.starter.version>2.1.4</mapper.starter.version>
		<mysql.version>5.1.46</mysql.version>
		<pageHelper.starter.version>1.2.5</pageHelper.starter.version>
		<leyou.latest.version>1.0.0-SNAPSHOT</leyou.latest.version>
		<fastDFS.client.version>1.26.5</fastDFS.client.version>
	</properties>

	<dependencyManagement>	//	统一依赖管理,子工程不添加,不继承
		<dependencies>
			<!-- springCloud -->
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<!-- 通用Mapper启动器 -->
			<dependency>
				<groupId>tk.mybatis</groupId>
				<artifactId>mapper-spring-boot-starter</artifactId>
				<version>${mapper.starter.version}</version>
			</dependency>
			<!-- 分页助手启动器 -->
			<dependency>
				<groupId>com.github.pagehelper</groupId>
				<artifactId>pagehelper-spring-boot-starter</artifactId>
				<version>${pageHelper.starter.version}</version>
			</dependency>
			<!-- mysql驱动 -->
			<dependency>
				<groupId>mysql</groupId>
				<artifactId>mysql-connector-java</artifactId>
				<version>${mysql.version}</version>
			</dependency>
			<!--FastDFS客户端-->
			<dependency>
				<groupId>com.github.tobato</groupId>
				<artifactId>fastdfs-client</artifactId>
				<version>${fastDFS.client.version}</version>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<dependencies>		//	统一依赖管理 直接继承给所有的子工程
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.4</version>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
	</dependencies>
	<build>			//	插件	
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

创建子工程项目:

1. 创建服务的注册中心(EurekaServer):{
	导入依赖:
		<groupId>com.leyou.common</groupId>
		<artifactId>ly-registry</artifactId>
		<version>1.0.0-SNAPSHOT</version>

		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
			</dependency>
		</dependencies>

		<build>
			<plugins>
				<plugin>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-maven-plugin</artifactId>
				</plugin>
			</plugins>
		</build>
	
2.创建启动类:
	注解: 
		@SpringBootApplication	//	当前类是一个配置类
		@EnableEurekaServer		//	Eureka 注册中心 服务端 -> 声明这个应用是一个EurekaServer
	
	配置文件:
		server:	
		  port: 10086	//	端口
		spring:
		  application:
			name: ly-registry	// 服务名
		eureka:
		  client:
			fetch-registry: false	#是否检索服务 #不拉取服务 
			register-with-eureka: false		#是否向服务注册中心注册自己 # 不注册自己
			service-url:
			  defaultZone: http://127.0.0.1:10086/eureka	


3. 创建服务网关(Zuul):{	
	导入依赖:
		<groupId>com.leyou.common</groupId>
		<artifactId>ly-gateway</artifactId>
		<version>1.0.0-SNAPSHOT</version>

		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
			</dependency>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
			</dependency>
		</dependencies>
		<build>
			<plugins>
				<plugin>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-maven-plugin</artifactId>
				</plugin>
			</plugins>
		</build>

	创建启动类:
		注解: 
			@SpringBootApplication	//	当前类是一个配置类
			@EnableZuulProxy		//	开启Zuul的网关功能  添加在启动类
	
	配置文件:
		server:
		  port: 10010
		spring:
		  application:
			name: api-gateway
		eureka:
		  client:
			service-url:
			  defaultZone: http://127.0.0.1:10086/eureka
		zuul:
		  prefix: /api # 添加路由前缀
		  routes:
			工程名-service: /工程名/** # 将商品微服务映射到/工程名/** 		  消除注释*/
		hystrix:
		  command:
			default:
			  execution:
				isolation:
				  thread:
					timeoutInMilliseconds: 5000 # 熔断超时时长:5000ms
		ribbon:
		  ConnectTimeout: 1000 # ribbon链接超时时长
		  ReadTimeout: 3500 # ribbon读取超时时长
		  MaxAutoRetries: 0  # 当前服务重试次数
		  MaxAutoRetriesNextServer: 0 # 切换服务重试次数	

->	基础服务搭建完毕,为了便于开发,统一配置中心(ConfigServer)以后添加

创建商品微服务

1.创建子工程:
		pom文件,打包方式设置为pom
	
2.在该工程下创建两个子工程:
	- ly-子工程-pojo:	主要是相关实体类
	- ly-子工程-service:所有业务逻辑及内部使用接口
		添加依赖:{
			 <dependencies>
				<dependency>	//	- web启动器
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-web</artifactId>
				</dependency>
				<dependency>	//	- Eureka客户端
					<groupId>org.springframework.cloud</groupId>
					<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
				</dependency>
				<dependency>	//	- 通用mapper启动器
					<groupId>tk.mybatis</groupId>
					<artifactId>mapper-spring-boot-starter</artifactId>
				</dependency>
				<dependency>	//	- mysql驱动
					<groupId>mysql</groupId>
					<artifactId>mysql-connector-java</artifactId>
				</dependency>
				<dependency>	//	- 连接池,我们用默认的Hykira,引入jdbc启动器
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-test</artifactId>
				</dependency>
				<dependency>	//	- 分页助手启动器
					<groupId>com.github.pagehelper</groupId>
					<artifactId>pagehelper-spring-boot-starter</artifactId>
				</dependency>
				<dependency>	//	- ly-item-pojo中的实体类
					<groupId>com.leyou.service</groupId>
					<artifactId>ly-item-pojo</artifactId>
					<version>1.0.0-SNAPSHOT</version>
				</dependency>
			</dependencies>
			<build>
				<plugins>
					<plugin>
						<groupId>org.springframework.boot</groupId>
						<artifactId>spring-boot-maven-plugin</artifactId>
					</plugin>
				</plugins>
			</build>


	配置文件:{
		server:
		  port: 8081
		spring:
		  application:
			name: item-service
		  datasource:
			url: jdbc:mysql://localhost:3306/heima54
			username: root
			password: 123456
		eureka:
		  client:
			service-url:
			  defaultZone: http://127.0.0.1:10086/eureka
		  instance:
			prefer-ip-address: true
			ip-address: 127.0.0.1
			hostname: localhost

			}
	}
	
3. 通用工具模块:
	创建common工程:
	引入依赖:
		<groupId>com.leyou.common</groupId>
			<artifactId>ly-common</artifactId>
			<version>1.0.0-SNAPSHOT</version>

			<dependencies>
				<dependency>
					<groupId>org.apache.tomcat.embed</groupId>
					<artifactId>tomcat-embed-core</artifactId>
					<scope>provided</scope>
				</dependency>
				<dependency>	<!--日志启动器-->
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</dependency>
				<dependency>
					<groupId>com.fasterxml.jackson.core</groupId>
					<artifactId>jackson-databind</artifactId>
					<version>2.9.7</version>
					<scope>compile</scope>
				</dependency>
			</dependencies>		
		
	引入工具类:
		
	
4. 日志配置:
		SpringBoot默认采用的日志框架是:slf4j + logback的组合
		
		在工具模块中 添加配置文件 logback-spring.xml :{
			<?xml version="1.0" encoding="UTF-8"?>
			<configuration>
				<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
					<encoder>
						<pattern>
							%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
						</pattern>
					</encoder>
				</appender>
				<appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
					<filter class="ch.qos.logback.classic.filter.LevelFilter">
						<level>ERROR</level>
						<onMatch>DENY</onMatch>
						<onMismatch>ACCEPT</onMismatch>
					</filter>
					<encoder>
						<pattern>
							%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
						</pattern>
					</encoder>
					<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
						<fileNamePattern>D:/heima/log/info.%d.log</fileNamePattern>
					</rollingPolicy>
					<!--日志文件最大的大小-->
					<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
						<MaxFileSize>20MB</MaxFileSize>
					</triggeringPolicy>
				</appender>
				<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
					<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
						<level>ERROR</level>
					</filter>
					<encoder>
						<pattern>
							%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
						</pattern>
					</encoder>
					<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
						<fileNamePattern>D:/heima/log/error.%d.log</fileNamePattern>
					</rollingPolicy>
					<!--日志文件最大的大小-->
					<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
						<MaxFileSize>20MB</MaxFileSize>
					</triggeringPolicy>
				</appender>
				<root level="info">
					<appender-ref ref="consoleLog" />
					<!--<appender-ref ref="fileErrorLog" />
					<appender-ref ref="fileInfoLog" />-->
				</root>
			</configuration>		
		
	
5. 通用异常处理:
	场景预设:	假如我们做新增商品,需要接收下面的参数:price:价格  name:名称
		然后对数据做简单校验:- 价格不能为空
		新增时,自动形成ID,然后随商品对象一起返回

	在ly-item-pojo中编写实体类:
		package com.leyou.item.pojo;

		import lombok.Data;

		@Data
		public class Item {
			private Integer id;
			private String name;
			private Long price;
		}

	
	在ly-item-service中编写业务:
		package com.leyou.item.service;

		import com.leyou.item.pojo.Item;
		import org.springframework.stereotype.Service;

		import java.util.Random;

		@Service
		public class ItemService {
			
			public Item saveItem(Item item){
				//	这里临时使用随机生成id,然后直接返回,没有做数据库操作
				int id = new Random().nextInt(100);
				item.setId(id);
				return item;
			}

	在ly-item-controller中编写:
		package com.leyou.item.controller;

		import com.leyou.item.pojo.Item;
		import com.leyou.item.service.ItemService;
		import org.springframework.beans.factory.annotation.Autowired;
		import org.springframework.http.HttpStatus;
		import org.springframework.http.ResponseEntity;
		import org.springframework.web.bind.annotation.PostMapping;
		import org.springframework.web.bind.annotation.RestController;

		@RestController
		public class ItemController<RestController> {

			@Autowired
			private ItemService itemService;

			@PostMapping("item")
			public ResponseEntity<Item> saveItem(Item item){
				// 如果价格为空,则抛出异常,返回400状态码,请求参数有误
				if(item.getPrice() == null){
					return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
				}
				Item result = itemService.saveItem(item);
				return ResponseEntity.status(HttpStatus.CREATED).body(result);
			}
		}

	统一异常处理: //	rest客户端:https://insomnia.rest/

		返回错误信息时,没有任何有效提示,不友好.
		修改controller的代码,把异常抛出:
			@PostMapping("item")
			public ResponseEntity<Item> saveItem(Item item){
				if(item.getPrice() == null){
					throw new RuntimeException("价格不能为空");
				}
				Item result = itemService.saveItem(item);
				return ResponseEntity.ok(result);
			}

6.使用SpringMVC提供的统一异常拦截器,因为是统一处理,我们放到ly-common项目中:{
			package com.leyou.common.advice;
			
			@ControllerAdvice	//	默认情况下,会拦截所有加了@Controller的类
			@Slf4j
			public class BasicExceptionHandler {

				//	声明要处理的异常类型,可以有多个; 
				@ExceptionHandler(RuntimeException.class){	
						//	被声明的方法可以看做是一个SpringMVC的Handler:
						//	- 参数是要处理的异常,类型必须要匹配
						//	- 返回结果可以是ModelAndView、ResponseEntity等,基本与handler类似
				}
				public ResponseEntity<String> handleException(RuntimeException e) {
					//	这里等于从新定义了返回结果,我们可以随意指定想要的返回类型。此处使用了String
					// 	我们暂定返回状态码为400, 然后从异常中获取友好提示信息
					return ResponseEntity.status(400).body(e.getMessage());
				}
			}
		}
		
		在ly-common中引入webmvc依赖:{
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-webmvc</artifactId>
			</dependency>
		}
		
		在ly-item-service中引入ly-common{
			<dependency>
				<groupId>com.leyou.common</groupId>
				<artifactId>ly-common</artifactId>
				<version>1.0.0-SNAPSHOT</version>
			</dependency>
		}
	
		
	自定义异常:{
		仅凭抛出的异常,无法判断到底该返回怎样的状态码,可能是参数有误、数据库异常、没有权限,等等各种情况。
		因此抛出异常时,就必须传递两个内容:
			- 异常信息
			- 异常状态码
			
		//	定义一个枚举,用于封装这些信息:	
		在com.leyou.common.enums 中编写:{
			@NoArgsConstructor
			@AllArgsConstructor
			public enum ExceptionEnum {
				PRICE_CANNOT_BE_NULL(400, "价格不能为空!");

				private int status;
				private String msg;

				public int status() {	//	status:响应状态码
					return this.value;
				}

				public String msg() {
					return this.msg;
				}
			}
		}
		
		//	自定义异常,来获取和传递枚举对象。
		在com.leyou.common.exception 中编写:{
			@Getter
			public class LyException extends RuntimeException {
				private int status;

				public LyException(ExceptionEnum em) {
					super(em.msg());
					this.status = em.value();
				}

				public LyException(ExceptionEnum em, Throwable cause) {
					super(em.msg(), cause);
					this.status = em.value();	
				}
			}
			
			//status:响应状态码			
		}
	
		修改controller代码:{
			@PostMapping("item")
			public ResponseEntity<Item> saveItem(Item item){
				if(item.getPrice() == null){
					throw new LyException(ExceptionEnum.PRICE_CANNOT_BE_NULL);
				}
				Item result = itemService.saveItem(item);
				return ResponseEntity.ok(result);
			}
		}
	
		在com.leyou.common.vo 中定义异常结果对象:{
			@Getter
			public class ExceptionResult {
				private int status;
				private String message;
				private String timestamp;

				public ExceptionResult(LyException e) {
					this.status = e.getStatus();
					this.message = e.getMessage();
					this.timestamp = DateTime.now().toString("yyyy-MM-dd HH:mm:ss");
				}
			}
		}
	
7.使用了日期工具类:JodaTime,我们要引入依赖在ly-common中:
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
		</dependency>
		<dependency>
			<groupId>joda-time</groupId>
			<artifactId>joda-time</artifactId>
		</dependency>

		
	//	修改异常处理逻辑:
	@ControllerAdvice
	public class BasicExceptionHandler {
		@ExceptionHandler(LyException.class)
		public ResponseEntity<ExceptionResult> handleException(LyException e){
			// 返回结果
			return ResponseEntity.status(e.getStatus()).body(new ExceptionResult(e));
		}
	}
依赖查询:

父工程项目依赖:

	<packaging>pom</packaging> 
	
	<parent>	//	继承父类 springBoot
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.4.RELEASE</version>
	</parent>
	
	<properties>	//	统一依赖版本管理
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		......
	</properties>

	<dependencyManagement>	//	统一依赖管理,子工程不添加,不继承
		<dependencies>
			<dependency>	//	<!-- springCloud -->
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<dependency>	//	<!-- 通用Mapper启动器 -->
				<groupId>tk.mybatis</groupId>
				<artifactId>mapper-spring-boot-starter</artifactId>
				<version>${mapper.starter.version}</version>
			</dependency>
			<dependency>	//	<!-- 分页助手启动器 -->
				<groupId>com.github.pagehelper</groupId>
				<artifactId>pagehelper-spring-boot-starter</artifactId>
				<version>${pageHelper.starter.version}</version>
			</dependency>
			<dependency>	//	<!-- mysql驱动 -->
				<groupId>mysql</groupId>
				<artifactId>mysql-connector-java</artifactId>
				<version>${mysql.version}</version>
			</dependency>
			<dependency>	//	<!--FastDFS客户端-->
				<groupId>com.github.tobato</groupId>
				<artifactId>fastdfs-client</artifactId>
				<version>${fastDFS.client.version}</version>
			</dependency>
		</dependencies>
	</dependencyManagement>	
	<dependencies>		//	统一依赖管理 直接继承给所有的子工程
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.4</version>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
	</dependencies>
	<build>				//	插件
		<plugins>
			<plugin> 	//	将Spring Boot应用打包为可执行的jar或war文件,然后以通常的方式运行Spring Boot应用。
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

其他依赖:

	<!-- tk.mybatis 减少数据库的配置 -->
	<dependency>	//	- 连接池,我们用默认的Hykira,引入jdbc启动器
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
	</dependency>
	</dependency>	//	webmvc 依赖
		<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webmvc</artifactId>
	</dependency>
		<dependency>
		<groupId>org.apache.tomcat.embed</groupId>
		<artifactId>tomcat-embed-core</artifactId>
		<scope>provided</scope>
	</dependency>
	
工具类依赖:	
	<dependency>	//	<!--日志启动器-->
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-logging</artifactId>
	</dependency>
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-databind</artifactId>
		<scope>compile</scope>

SpringCloud主要框架依赖:

	//	web 启动器
	<dependency>	
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	//	Eureka 注册中心 - 服务发现	—— Netflix Eureka
	<dependency>	//	服务端
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
	</dependency>
	<dependency>	//	客户端
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>
	//	Hystrix 熔断器
	<dependency>	//	在所需要的服务端添加
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
	</dependency>
	//	Feign 服务调用	
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-openfeign</artifactId>
	</dependency>
	//	Zuul 网关	
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
	</dependencies>
配置查询:
	server:
	  port: 0000  #服务端口
	spring: 
	  application:   
		name: api-gateway #指定服务名 	//	属性来指定应用名称,将来会作为服务的id使用。
	  servlet:
		multipart:
		  max-file-size: 5M #   //	限制文件上传的大小	
	datasource:	//	数据库配置
	  url: jdbc:mysql://localhost:3306/heima54
	  username: root
	  password: 123456	
	mybatis:
		type-aliases-package: 别名扫描包位置 
	// 	配置Eureka注册中心
	//	服务端
	eureka:
	  client:
		register-with-eureka: false 	e# 不注册自己  #是否向服务注册中心注册自己  默认值true
		fetch-registry: false	#是否检索服务 #不拉取服务 	默认值true
		service-url: # EurekaServer的地址,现在是自己的地址,如果是集群,需要写其它Server的地址。
		  defaultZone: http://127.0.0.1:10086/eureka # EurekaServer地址,多个地址以','隔开
		//	Zuul 网关	  
	  instance:
		prefer-ip-address: true 	# 使用ip服务注册,默认host名服务注册	 
		ip-address: 127.0.0.1 	#映射规则	//	默认注册时使用的是主机名,也可以ip注册
		hostname: localhost
		//	服务续约	服务下线、失效剔除 和 自我保护
		lease-renewal-interval-in-seconds: 30	//	 续约时间,默认30s
		lease-expiration-duration-in-seconds: 90	//	服务时效时间,续约到期时间,默认90s
	  Server	//	会自动剔除已经失效的服务,在开发中关闭自我保护
		Enable-self-preservation:  false		关闭自我保护,默认为打开
		Eviction-interval-timer-in-ms:  1000	扫描失效的服务间隔,默认为 60*1000 ms	
	//	Ribbon 负载均衡策略
	user-service:	//	服务名称
	  ribbon:
		NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule	//	值就是IRule的实现类  
		ReadTimeout: 2000 # 读取超时时长
		ConnectTimeout: 1000 # 建立链接的超时时长 默认是1000
		MaxAutoRetries: 0 # 当前服务器的重试次数
		MaxAutoRetriesNextServer: 0 # 重试多少次服务
		OkToRetryOnAllOperations: false # 是否对所有的请求方式都重试
		eager-load:
				enabled: true	//	Ribbon默认是懒加载,第一次访问时才会去创建负载均衡客户端。往往会出现超时。需要饥饿加载,即项目启动即创建,可以这样配置
	//	Ribbon 负载均衡策略	  
	hystrix:
	  command:
		default:
		  execution:
			isolation:
			  thread:
				timeoutInMilliseconds: 2000		//	 # 熔断超时时长:2000ms  默认请求在超过1秒后都会返回错误信息
	//	Netflix Hystrix 熔断器 
	feign:	//	默认情况下是关闭的
	  hystrix:
		enabled: true # 开启Feign的熔断功能		
	//	Zuul 网关	
	zuul:	 
	  routes:
		//	路由前缀	
		prefix: /api   /# 指定路由的前缀,发请求时,路径就要以/api开头。 //	例如: 路径/api/user-service/user/1将会被代理到/user-service/user/1				
		工程名-service: /工程名-service/**  # 指定服务名称: 这里是映射路径
		//	因为有默认的路由规则,如果想要禁用某个路由规则,可以这样:
		ignored-service:  #忽略路由
		  - user-service 	#服务端的ID名
		  - consumer
		  ...
注解查询:
未分类:
	@Configuration: 声明一个类作为配置类,代替xml文件
	@PropertySource: 指定外部属性文件路径
	@Value:	属性注入
	@Bean: 声明在方法上,将方法的返回值加入"Bean容器",代替<bean>标签
	@ConfigurationProperties(prefix ="jdbc" ):		//	读取配置文件
		注解声明当前类为属性读取类:prefix="jdbc"读取属性文件中,前缀为jdbc的值
	@EnableConfigurationProperties(使用的@ConfigurationProperties()的文件名.class):
		声明要使用JdbcProperties(使用的@ConfigurationProperties()的文件名)这个类的对象

启动类:
	类名上:
		@SpringBootApplication:{	"组合注解 重要组成" //	声明当前类是一个配置类	//	核心注解
			- @SpringBootConfiguration	//	声明当前类是SpringBoot应用的配置类,项目中只能有一个
				- @Configuration  //	Spring会自动扫描有该注解的类,并且读取其中的配置信息	//	标注了@Configuration之后,本身也是一个IoC容器。
			- @EnableAutoConfiguration	//	基于所添加的依赖,去“猜测”想要如何配置Spring	//	可以将所有标注了@Configuration的javabean加入当前的IoC容器之中。
			- @ComponentScan	//	-> 包扫描, 从声明这个注解的类所在的包开始,扫描包及子包	//	自动扫描并且加载符合条件的组件,并加入IoC容器之中。
		}
		@MapperScan("com.itcast.user.mapper")	//	<- 添加了 tk.mybatis 才需要这个依赖 mapper扫描包
		//  配置Eureka注册中心
		//	开启Eureka服务端  
		@EnableEurekaServer		//	声明这个应用是一个EurekaServer 服务端	
		// 	开启Eureka客户端	
		@EnableDiscoveryClient  //	推荐使用! 支持多种
		@EnableEurekaClient		//	不推荐! 只支持Enable
		//	Feign 服务调用		
		@EnableFeignClients // 开启Feign功能	
		//	Ribbon 负载均衡
		@LoadBalanced	//	客户端 的启动类
		//	Ribbon 负载均衡策略
		@SpringCloudApplication:{	"组合注解"
			@SpringBootApplication
			@EnableDiscoveryClient	
			@EnableCircuitBreaker	在启动类上添加注解
		}

		//	Zuul 网关
		@EnableZuulProxy:	// 开启Zuul的网关功能  添加在启动类

controller类:
	类名上:
		@Slf4j
		@CrossOrigin  支持跨域请求
		@RestController:{	 组合注解 @RequestMapping + @ResponseBody
			//	@Controller  表示这是表现层
			//	@ResponseBody  表示把返回的对象转成json格式
		}
		@RequestMapping("/接收的参数名")  表示接收所有参数名和括号参数一致的消息
	//	Ribbon 负载均衡策略	
		@DefaultProperties(defaultFallback = "defaultFallBack")	//	在类上指明统一的失败降级方法
	//	Feign 服务调用
		@FeignClient("user-service")	//	Feign的客户端
	属性上:
		@Autowired	//	自动注入
	方法名上:
		@GetMapping("/路径")
		@PostMapping()  表示接收post请求
		@PutMapping("/{参数}")  接收的参数
	方法属性上:
		@RequestBody  将请求信息自动导入到该对象中
		@PathVariable  路径变量
	//	Ribbon 负载均衡策略	
		@HystrixCommand(fallbackMethod = "queryByIdFallBack")	

service类:
	类名上:
		@Service	表示这是业务层
	属性上:
		@Autowired	//	自动注入
	方法名上:
		@Transactional  加事务
	
持久层使用注解:
	方法名上:
		@Query	定义sql语句
		@modifying  表示这是一个怎删改方法


实体类&工具类:
	类名上:
		@Entity  表示这是一个实体类
		@Table(neme="表名")  表示该类与所填的表名进行绑定;可以不写,默认绑定与类名一致的表		
		@Data
	
	属性上:
		@Id  表示该属性对应的字段是这个表的主键
		@GenerateValue  表示自动生成策略,不写就是生动生成策略
		@Column(name="表字段")  表示如果属性名和字段名不一致那么使用该注解,在name后面填上字段名
		//	需要在maven中引入 <groupId>org.projectlombok</groupId> 的依赖:
		@Data :自动提供getter和setter、hashCode、equals、toString等方法以及构造函数
		@Getter:自动提供getter方法
		@Setter:自动提供setter方法
		@Slf4j:自动在bean中提供log变量,其实用的是slf4j的日志功能。
		@KeySql(useGeneratedKeys = true)
		@ControllerAdvice	//	SpringMVC提供的统一异常拦截器 默认情况下,会拦截所有加了@Controller的类

异常类使用的注解:
	使用在类名上:
		@RestControllerAdvice 组合注解 @ControllerAdvice + @ResponseBody
		//	@ControllerAdvice  开启了对Controller增强的功能,使用当前类增强(AOP)
		//	@ResponseBody  表示把返回的对象转成json格式
	使用在方法上:
		 @ExceptionHandler(指定的异常.class)  可以指定抓取具体异常,不填写就是抓取所有异常
			可以使用在任何用@Controller注解修饰的类中,设置出现某种异常的时候执行,
			如果修饰在@RestControllerAdvice或@RestControllerAdvice 修饰的类的方法上,则全局有效。
			优先级:本类的优先级要高,本类 > 全局


跨域处理的注解:
	使用在类名上:
	@CrossOrigin  跨域处理
		默认情况下,@CrossOrigin允许所有在@RequestMapping指定的所有HTTP方法的所有源,
		即允许CrossOrigin允许所有跨域请求。
		如果要指定允许跨域请求的源、最大缓存响应的周期、请求方法等,可以添加如下参数(参考):
			...
			@CrossOrigin(
				origins = "http://anotherdomain.com",	//	指定允许跨域请求的源
				maxAge = 3600,	//	最大缓存响应的周期
				methods = {RequestMethod.GET, RequestMethod.POST}	//	请求方法等
			)
			public class LabelController {
			...
			}			

接口类查询:

	持久层 -> 基础 Mapper<User>		// <-	Mapper 添加的是 tk.mybatis.mapper 的包
	
	持久层的 Spring JPA 继承接口类:
		JpaRepository<实体类类型,主键类型>	 提供了基本的增删改查
		JpaSpecificationExecutor<实体类类型> 用于做复杂的条件查询
			toPredicate方法:		
				Root:查询哪个表
				CriteriaQuery:查询哪些字段,排序是什么
				CriteriaBuilder:字段之间是什么关系,如何生成一个查询条件,每一个查询条件都是什么方式
		Predicate(Expression):单独每一条查询条件的详细描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值