整合Hystrix/请求合并与缓存(二)
1、读取缓存
- 新建过滤器
- 使用缓存注解
- 多次同一请求(同一请求中调用同样的资源),可考虑使用缓存
1.1、添加过滤器
package com.atm.cloud.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
@WebFilter(urlPatterns = "/*", filterName = "hystrixFilter")
public class MyFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("开始执行过滤器....");
HystrixRequestContext ctx = HystrixRequestContext.initializeContext();
try {
chain.doFilter(request, response);
} catch (Exception e) {
} finally {
ctx.shutdown();
}
}
public void init(FilterConfig config) throws ServletException {
}
}
package com.atm.cloud
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.web.servlet.ServletComponentScan
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker
import org.springframework.cloud.client.loadbalancer.LoadBalanced
import org.springframework.cloud.netflix.eureka.EnableEurekaClient
import org.springframework.context.annotation.Bean
import org.springframework.web.client.RestTemplate
@SpringBootApplication
@EnableEurekaClient
// 打开断路器
@EnableCircuitBreaker
// 扫描
@ServletComponentScan
public class HystrixInvokerApp {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate()
}
public static void main(String[] args) {
SpringApplication.run(HystrixInvokerApp.class, args)
}
}
package com.atm.cloud
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.web.servlet.ServletComponentScan
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker
import org.springframework.cloud.client.loadbalancer.LoadBalanced
import org.springframework.cloud.netflix.eureka.EnableEurekaClient
import org.springframework.context.annotation.Bean
import org.springframework.web.client.RestTemplate
@SpringBootApplication
@EnableEurekaClient
// 打开断路器
@EnableCircuitBreaker
// 扫描
@ServletComponentScan
public class HystrixInvokerApp {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate()
}
public static void main(String[] args) {
SpringApplication.run(HystrixInvokerApp.class, args)
}
}
1.2、新增Service/controller
package com.atm.cloud.cache
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate
import com.atm.cloud.Person
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult
@Service
public class CacheService {
@Autowired
RestTemplate restTemplate
// @CacheResult需要配合@HystrixCommand一起使用
@CacheResult
@HystrixCommand
public Person cachePerson(Integer personId) {
System.out.println("调用CachePerson()...")
return null
}
}
package com.atm.cloud.cache
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RestController
import com.atm.cloud.Person
@RestController
public class CacheController {
@Autowired
private CacheService cacheService
@RequestMapping(value = "/cache", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String router() {
for (int i = 0
cacheService.cachePerson(1)
}
return "访问成功"
}
}
- 浏览器访问127.0.0.1:9000/cache
2、删除缓存
2.1、CacheService
package com.atm.cloud.cache
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate
import com.atm.cloud.Person
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult
@Service
public class CacheService {
// 调用这个方法将设置缓存
@CacheResult
@HystrixCommand(commandKey = "cacheKey")
public String getCache(Integer id) {
System.out.println("查询缓存()....")
return ""
}
// 调用这个方法将设清除缓存
@CacheRemove(commandKey = "cacheKey")
@HystrixCommand
public String removePerson(Integer id) {
System.out.println("删除()....")
return ""
}
}
2.2、CacheController
package com.atm.cloud.cache
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RestController
import com.atm.cloud.Person
@RestController
public class CacheController {
@Autowired
private CacheService cacheService
@RequestMapping(value = "/rmCache", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String removeCahce() {
cacheService.getCache(1)
// 形式上调用了两次,实际上,当一次调用成功,第二次不再调用,因为已经存在缓存
cacheService.getCache(1)
// 删除缓存
cacheService.removePerson(1)
System.out.println("================")
// 缓存如果删除成功,则会再次请求方法
cacheService.getCache(1)
return "访问成功"
}
}
3、合并请求
- 实际应用中可能调用多次服务来获取信息(同一个服务调用多次),这些请求的URL相同,传入参数不同,对于这样的请求我们考虑将其合并【 同一个请求中调用同一个服务多次,但是参数不一样】
- 我们可以配置在多久的一个时间段内发生的请求,将这些请求合并成一次请求(如:发送/person/{i},10次,使用合并后,只发送/person一次,但是会传入10个id【就是调用一个服务,传入10个参数】),前提是:服务端需要提供URL
- 合并的弊端:你发送的一次请求,响应的结果可能是多个
- 减少服务间的交互
3.1、CallService
package com.atm.cloud.collapser
import java.util.ArrayList
import java.util.List
import java.util.concurrent.Future
import org.springframework.stereotype.Service
import com.atm.cloud.Person
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty
@Service
public class CallService {
// 查询单个Person
// @HystrixCollapser请求收集器
// batchMethod:收集的id给谁处理?给getPersons方法处理
// timerDelayInMilliseconds:收集1s内请求这个服务的id
// 这个方法只是负责收集参数,实际执行的方法是getPersonList
@HystrixCollapser(batchMethod = "getPersonList", collapserProperties = { @HystrixProperty(name = "timerDelayInMilliseconds", value = "1000") })
public Future<Person> getPerson(Integer id) {
// 无需实现,自动帮我们实现收集
System.out.println("执行单个查询方法...")
return null
}
// 查询多个,这个就是实际处理的方法
// ids:就是上面方法帮我们收集的
// 这个方法会放到命令中执行
@HystrixCommand
public List<Person> getPersonList(List<Integer> ids) {
List<Person> persons = new ArrayList<Person>()
for (Integer id : ids) {
System.out.println(id)
Person p = new Person()
p.setAge(18)
p.setId(id)
p.setName("atm")
persons.add(p)
}
return persons
}
}
3.2、CallController
package com.atm.cloud.collapser
import java.util.concurrent.Future
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RestController
import com.atm.cloud.Person
@RestController
public class CallController {
@Autowired
private CallService collService
@RequestMapping(value = "/coll", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String testCollapse() throws Exception {
// 连续执行3次请求
Future<Person> f1 = collService.getPerson(1)
Future<Person> f2 = collService.getPerson(2)
Future<Person> f3 = collService.getPerson(3)
Person p1 = f1.get()
Person p2 = f2.get()
Person p3 = f3.get()
return "访问成功"
}
}