微服务特点 微服务的优缺点
优点: 缺点:
项目结构:
先导入相关的依赖及插件
<!--导入所需的依赖--> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version> </dependency> </dependencies> <!--spring-boot项目必须要的一个插件--> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>新建启动类CourseListApplication.java:
package com.luo.course; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * 项目启动类 */ @SpringBootApplication public class CourseListApplication { public static void main(String[] args) { SpringApplication.run(CourseListApplication.class, args); } }新建配置文件application.properties:
server.port=8071 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/course_practice?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=123456 logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx} mybatis.configuration.map-underscore-to-camel-case=true spring.application.name=course-list随后书写控制类,实体类,Mapper接口,service接口以及service接口实现
CourseMapper.java
package com.luo.course.dao; import com.luo.course.entity.Course; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import org.springframework.stereotype.Repository; import java.util.List; /** * 课程的Mapper类 */ @Mapper @Repository public interface CourseMapper { @Select("SELECT * FROM course WHERE valid=1") List<Course> findValidCourses(); }Course.java(实体类)
package com.luo.course.entity; import java.io.Serializable; /** * Course实体类 */ public class Course implements Serializable { Integer id; Integer sourseId; String courseName; Integer valid; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getCourseName() { return courseName; } public void setCourseName(String courseName) { this.courseName = courseName; } public Integer getValid() { return valid; } public void setValid(Integer valid) { this.valid = valid; } public Integer getSourseId() { return sourseId; } public void setSourseId(Integer sourseId) { this.sourseId = sourseId; } @Override public String toString() { return "Course{" + "id=" + id + ", sourseId=" + sourseId + ", courseName='" + courseName + '\'' + ", valid=" + valid + '}'; } }这里一定要实现Serializable接口以及get和set方法,否则会报错: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed;
16:33:49.528 -ERROR 9080 --- [nio-8071-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.luo.course.entity.Course]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.luo.course.entity.Course and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0])] with root cause com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.luo.course.entity.Course and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]) at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.9.10.2.jar:2.9.10.2] at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1191) ~[jackson-databind-2.9.10.2.jar:2.9.10.2] at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:313) ~[jackson-databind-2.9.10.2.jar:2.9.10.2] at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:71) ~[jackson-databind-2.9.10.2.jar:2.9.10.2] at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:33) ~[jackson-databind-2.9.10.2.jar:2.9.10.2] at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:145) ~[jackson-databind-2.9.10.2.jar:2.9.10.2] at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107) ~[jackson-databind-2.9.10.2.jar:2.9.10.2] at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25) ~[jackson-databind-2.9.10.2.jar:2.9.10.2] at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480) ~[jackson-databind-2.9.10.2.jar:2.9.10.2] at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:400) ~[jackson-databind-2.9.10.2.jar:2.9.10.2] at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1392) ~[jackson-databind-2.9.10.2.jar:2.9.10.2] at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:913) ~[jackson-databind-2.9.10.2.jar:2.9.10.2] at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:287) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:103) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:291) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:181) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:123) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:893) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:798) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.1.13.RELEASE.jar:5.1.13.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.30.jar:9.0.30] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:94) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.13.RELEASE.jar:5.1.13.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367) [tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860) [tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598) [tomcat-embed-core-9.0.30.jar:9.0.30] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.30.jar:9.0.30] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_212] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_212] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.30.jar:9.0.30] at java.lang.Thread.run(Thread.java:748) [na:1.8.0_212]CourseListController.java
package com.luo.course.controller; import com.luo.course.entity.Course; import com.luo.course.service.CourseListService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * CourseListController 课程列表控制器 */ @RestController public class CourseListController { @Autowired CourseListService courseListService; @GetMapping("/course") public List<Course> courseList() { return courseListService.getCourseList(); } }CourseListService.java
package com.luo.course.service; import com.luo.course.entity.Course; import java.util.List; /** * 课程列表服务 */ public interface CourseListService { List<Course> getCourseList(); }CourseListServiceImpl.java
package com.luo.course.service.impl; import com.luo.course.dao.CourseMapper; import com.luo.course.entity.Course; import com.luo.course.service.CourseListService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class CourseListServiceImpl implements CourseListService { @Autowired CourseMapper courseMapper; @Override public List<Course> getCourseList() { List<Course> courses = courseMapper.findValidCourses(); return courses; } }此时有些数据并没有读取到,我们还需要加上驼峰命名转换 在配置文件中添加驼峰命名转换
mybatis.configuration.map-underscore-to-camel-case=true先导入所需的依赖,书写配置文件,与course-list完全相同,但配置文件中的端口后不能一样。然后类似于前面的,书写根据courseId查找价格的方法 实体类CoursePrice.java:
package com.luo.course.entity; import java.io.Serializable; /** * CoursePrice的实体类 */ public class CoursePrice implements Serializable { Integer id; Integer courseId; Integer price; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getCourseId() { return courseId; } public void setCourseId(Integer courseId) { this.courseId = courseId; } public Integer getPrice() { return price; } public void setPrice(Integer price) { this.price = price; } @Override public String toString() { return "CoursePrice{" + "id=" + id + ", courseId=" + courseId + ", price=" + price + '}'; } }CoursePriceMapper.java
package com.luo.course.dao; import com.luo.course.entity.CoursePrice; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import org.springframework.stereotype.Repository; /** * 课程价格Mapper类 */ @Mapper @Repository public interface CoursePriceMapper { @Select("SELECT * FROM course_price WHERE course_id=#{courseId}") CoursePrice findCoursePrice(Integer courseId); }CoursePriceService.java
package com.luo.course.service; import com.luo.course.entity.CoursePrice; /** * 课程价格服务 */ public interface CoursePriceService { CoursePrice getCoursePrice(Integer courseId); }CoursePriceServiceImpl.java
package com.luo.course.service.impl; import com.luo.course.dao.CoursePriceMapper; import com.luo.course.entity.CoursePrice; import com.luo.course.service.CoursePriceService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * 课程价格的实现类 */ @Service public class CoursePriceServiceImpl implements CoursePriceService { @Autowired CoursePriceMapper coursePriceMapper; @Override public CoursePrice getCoursePrice(Integer courseId) { return coursePriceMapper.findCoursePrice(courseId); } }CoursePriceController.java
package com.luo.course.controller; import com.luo.course.entity.CoursePrice; import com.luo.course.service.CoursePriceService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * 课程价格控制器 */ @RestController public class CoursePriceController { @Autowired CoursePriceService coursePriceService; @GetMapping("/price") public Integer getCoursePrice(Integer courseId) { CoursePrice coursePrice = coursePriceService.getCoursePrice(courseId); return coursePrice.getPrice(); } }服务注册与发现 启用Eureka的过程: 先导入依赖:
<!--导入所需的依赖--> <dependencies> <!-- eureka-server的依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> <!--spring-boot项目必须要的一个插件--> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>在项目最外层的配置文件中配置spring cloud的版本:
<!--表示spring cloud的版本--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.SR5</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>对Eureka-server进行配置: application.properties:
spring.application.name=eureka-server server.port=8070 eureka.instance.hostname=localhost #fetch-registry:获取注册表。不需要同步其他节点数据 eureka.client.fetch-registry=false #register-with-eureka:代表是否将自己注册到Eureka Server,默认是true eureka.client.register-with-eureka=false #服务所提供的地址 eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/启动类:EurekaServerApplication.java
package com.luo.course; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /** * Eureka的服务端(启动类) */ @EnableEurekaServer @SpringBootApplication public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }Eureka Client的改造 将course-list和course-price都作为Eureka-client注册到Eureka-server porm中添加依赖
<!-- spring cloud的依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>配置文件中添加:
eureka.client.service-url.defaultZone=http://localhost:8070/eureka/声明式、模板式的HTTP客户端 步骤: 导入依赖:
<!-- feign的依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!-- 自动加入的--> <dependency> <groupId>com.luo</groupId> <artifactId>course-list</artifactId> <version>0.0.1-SNAPSHOT</version> <scope>compile</scope> </dependency>在启动类中加入@EnableFeignClients注解 新建client包,并新建CourseListClient.java接口客户端 在客户端中引入list中控制器的一个方法,
package com.luo.course.client; import com.luo.course.entity.Course; import com.luo.course.entity.CoursePrice; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import java.util.List; /** * 课程列表的Feign客户端 */ @FeignClient("course-list") public interface CourseListClient { @GetMapping("/course") List<Course> courseList() ; }然后在控制器中新建通过feign获取的方法:
@GetMapping("/coursesInPrice") public List<Course> getCourseListPrice(Integer courseId) { List<Course> courses = courseListClient.courseList(); return courses; }在配置文件中配置负载均衡方式 在配置文件中配置负载均衡:
course-list.ribbon.NFLoadBeanLancerRuleClassName=com.netflix.loadbalancer.RoundRobinRule添加断路器: 先导入相应的依赖:
<!-- 添加断路器的依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>然后在配置文件中打开断路器功能:
feign.hystrix.enabled=true并在启动类中加入断路器注解:@EnableCircuitBreaker 然后在调用接口的FeignClient注解中配置断路的类:
@FeignClient(value = "course-list", fallback = CourseListClientHystrix.class)并在断路的类中配置短路之后返回的信息:
package com.luo.course.client; import com.luo.course.entity.Course; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; /** * 断路器实现类 */ @Component public class CourseListClientHystrix implements CourseListClient{ @Override public List<Course> courseList() { List<Course> defaultCourses = new ArrayList<>(); Course course = new Course(); course.setId(1); course.setSourseId(1); course.setCourseName("默认课程"); course.setValid(1); defaultCourses.add(course); return defaultCourses; } }
新建Zuul项目后, 添加依赖
<dependencies> <!--导入Eureka依赖--> <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> <!--spring-boot项目必须要的一个插件--> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>配置启动类,并在启动类前面加上注解:`@EnableZuulProxy@SpringCloudApplication
package com.luo.course; import org.springframework.boot.SpringApplication; import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; /** * 网关启动类 */ @EnableZuulProxy @SpringCloudApplication public class ZuulGatewayApplication { public static void main(String[] args) { SpringApplication.run(ZuulGatewayApplication.class, args); } }再添加配置文件:
spring.application.name=course-gateway server.port=8073 logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx} mybatis.configuration.map-underscore-to-camel-case=true eureka.client.service-url.defaultZone=http://localhost:8070/eureka/ zuul.prefix=/luo zuul.routes.course-list.path=/list/** zuul.routes.course-list.service-id=course-list zuul.routes.course-price.path=/price/** zuul.routes.course-price.service-id=course-pricezuul.prefix=/luo是指在所有网关的地址前添加luo zuul.routes.course-list.path=/list/** zuul.routes.course-list.service-id=course-list 是将course-list项目链接为list
书写两个过滤器记录时间戳: 在请求之前的过滤器:PreRequestFilter.java
package com.luo.course.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; import org.springframework.stereotype.Component; /** * 记录请求时间 * 起始过滤器 */ @Component public class PreRequestFilter extends ZuulFilter { @Override public String filterType() { //过滤器的类型 return FilterConstants.PRE_TYPE; } @Override public int filterOrder() { //过滤器的顺序 return 0; } @Override public boolean shouldFilter() { //是否启用过滤器 return true; } @Override public Object run() throws ZuulException { //想要做的过滤器的内容 RequestContext currentContext = RequestContext.getCurrentContext(); currentContext.set("startTime", System.currentTimeMillis()); System.out.println("过滤器已经记录时间"); return null; } }在请求之后的过滤器:PostRequestFilter.java
package com.luo.course.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; import org.springframework.stereotype.Component; /** * 请求处理后的过滤器 */ @Component public class PostRequestFilter extends ZuulFilter { @Override public String filterType() { //过滤器的类型 return FilterConstants.POST_TYPE; } @Override public int filterOrder() { //过滤器的顺序 return FilterConstants.SEND_RESPONSE_FILTER_ORDER-1; } @Override public boolean shouldFilter() { //是否启用过滤器 return true; } @Override public Object run() throws ZuulException { //想要做的过滤器的内容 RequestContext currentContext = RequestContext.getCurrentContext(); Long startTime=(Long)currentContext.get("startTime"); long duration = System.currentTimeMillis() - startTime; //获取当前请求的URI String requestURI = currentContext.getRequest().getRequestURI(); System.out.println("uri" + requestURI + ",处理时长:" + duration); return null; } }