使用 @CacheResult 注解 使用Hystrix 请求缓存

1. 消费端 Controller 代码

package com.example.server1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.model.User;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandProperties;

import scala.annotation.meta.param;

@RestController
public class UserController {
	@Autowired
	UserService userService;
	//RestTemplate restTemplate;
	
	/*
	 * 由于我们这里使用的是 http://localhost:9000/users?id=4&name=liubei&xingBie 的方式访问,
	 * 所以需要使用 @RequestParam 注解把请求参数的值绑定到方法的参数上。
	 * */
	/*@RequestMapping(value="/users",method=RequestMethod.GET)
	public User UserConsumber(@RequestParam(value="id") Long id,@RequestParam(value="name") 
	     String name,@RequestParam(value="xingBie") String xingBie) {
		//return restTemplate.getForEntity("http://hello-service/hello", String.class).getBody();
		System.out.println("UserController 方法");
		System.out.println("id:" + id + "  name:"+name + "  xingBie:"+xingBie );
		return userService.getUserById(id,name,xingBie);
		
		
	}*/
	
	
	@RequestMapping(value="/users",method=RequestMethod.GET)
	public User UserConsumber(@RequestParam(value="id") Long id) {
		//return restTemplate.getForEntity("http://hello-service/hello", String.class).getBody();
		System.out.println("UserController 方法");
		System.out.println("id:" + id );
		return userService.getUserById(id);
		
		
	}
	
}

2. 消费端 service 代码

package com.example.server1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.model.User;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;






@Service
public class UserService {
	@Autowired
	private RestTemplate restTemplate;
	
	private Long id;
	private String name = "caocao";
	private String  xingBie = "男";
	private User user;
	

	
	@CacheResult(cacheKeyMethod = "getCacheKey")
	@HystrixCommand
	public User getUserById(Long id) {
		System.out.println("getUserById 方法");
		 user = restTemplate.getForObject("http://hello-service/users/{id}/{name}/{xingBie}", User.class,id,name,xingBie);
		System.out.println("getUserById 方法  user:"+ user.getId() +"  " + user.getName() +"   " + user.getXingBie());
		return user;
	}
	
	/*@CacheResult(cacheKeyMethod = "getCacheKey")
	@HystrixCommand(commandKey = "commandKey1")
	public Long getUserById(Long id) {
		System.out.println("getUserById 方法");
		this.id=id;
		// user = restTemplate.getForObject("http://hello-service/users/{id}/{name}/{xingBie}", User.class,id,name,xingBie);
		//System.out.println("getUserById 方法  user:"+ user.getId() +"  " + user.getName() +"   " + user.getXingBie());
		return this.id;
	}*/
	
	// getCacheKey 方法的参数要与 getUserById 方法保持一致否则会报错
	//public String getCacheKey(Long id,String name,String xingBie) { 
	public String getCacheKey(Long id) { 
		//HystrixRequestContext.initializeContext(); // 缓存上线文初始化代码放在这个方法中,会导致每次调用这个方法缓存都会被清空(初始化)
		System.out.println("执行缓存方法:" + id );
		//System.out.println("查看缓存数据:"  + String.valueOf(id));
        //return String.valueOf(this.id) + String.valueOf(this.name) + String.valueOf(this.xingBie);
	
		return String.valueOf(id);
    }
	
	
}

3. 消费端 过滤器代码。注意过滤器类和过滤器注册配置类都要与工程中的 springboot 主类放在同一个包中。

package com.support;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;



@Component
public class HystrixInterceptor implements HandlerInterceptor {
	
	Integer i = 0;
	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response,Object handler) throws Exception {
		System.out.println("执行控制器之前执行拦截器");
		
		if (i==0) {
		   HystrixRequestContext.initializeContext();
		   //return true;
		   i++;
		}
		
		return true;
		
	}
	
	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response,Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("执行控制器之后执行拦截器");
		//HystrixRequestContext.initializeContext();
	}
	
	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response,Object handler ,
			Exception ex) throws Exception {
		System.out.println("前端控制器之后执行拦截器");
	}
}

4. 过滤器注册配置类

package com.example.server1;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class WebComponent2Config {
    @Bean
    public FilterRegistrationBean someFilterRegistration1() {
        //新建过滤器注册类
        FilterRegistrationBean registration = new FilterRegistrationBean();
        // 添加我们写好的过滤器
        registration.setFilter( new HystrixRequestContextServletFilter());
        // 设置过滤器的URL模式
        registration.addUrlPatterns("/*");
        return registration;
    }

}

5. 通过浏览器访问消费端

6. 消费端和服务端控制台输出的日志

6.1 消费端控制台日志

6.2 服务端控制台日志

通过控制台的输出我们看到,通过浏览器访问两次,两次都调用了 SERVER 端,缓存并没效果。
通过测试分析,每次请求通过过滤器时都会重新初始化 Hystrix  缓存上下文。如果不让初始化就会报错。
如何才能让缓存起效果,消费端在第一次被访问的后续访问不再调服务端,直接通过缓存返回数据给浏览器。

7. 我们也可以不使用过滤器,而是使用拦截器对 Hystrix缓存上下文进行初始化。注意拦截器类和拦截器注册配置类都要与工程中的 springboot 主类放在同一个包中。

7.1 拦截器代码

package com.example.server1;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;



@Component
public class HystrixInterceptor implements HandlerInterceptor {
	
	Integer i = 0;
	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response,Object handler) throws Exception {
		System.out.println("执行控制器之前执行拦截器");
		
		if (i==0) {
		   HystrixRequestContext.initializeContext();
		   //return true;
		   i++;
		}
		
		return true;
		
	}
	
	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response,Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("执行控制器之后执行拦截器");
		//HystrixRequestContext.initializeContext();
	}
	
	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response,Object handler ,
			Exception ex) throws Exception {
		System.out.println("前端控制器之后执行拦截器");
	}
}

7.2 拦截器注册配置类代码

package com.example.server1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.example.server1.HystrixInterceptor;


@SpringBootConfiguration
public class MySpringMVCConfig extends WebMvcConfigurerAdapter {
	@Autowired
	private HystrixInterceptor hystrixInterceptor;
	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(hystrixInterceptor).addPathPatterns("/**");
	}
}

猜你喜欢

转载自blog.csdn.net/lixiaxin200319/article/details/81131188