SpringCloud 通过继承 HystrixCollapser 实现请求合并

1. 消费端 service 代码:

package com.service;

import java.util.List;
import com.model.User;

public interface UserService {
	public User find(Long id);
	
	public List<User> findAll(List<Long> ids);
}
package com.serviceImpl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.ctc.wstx.util.StringUtil;
import com.model.User;
import com.service.UserService;

import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.StringUtils;

@Service
public class UserServiceImpl implements UserService {
	
	@Autowired
	private RestTemplate restTemplate;
	
	@Override
	public User find(Long id) {
		return restTemplate.getForObject("http://hello-service/users/{1}",User.class,id);
	}
	
	@Override
	public List<User> findAll(List<Long> ids) {
		System.out.println("UserService findAll()");
		//RestTemplate restTemplate2 = new RestTemplate();
		//List<User> listUser2 = new ArrayList<>();
		
		User[] users =   restTemplate.getForObject("http://hello-service/users?ids={1}",User[].class,
				StringUtils.join(ids,","));
		//User[] users =   restTemplate2.getForObject("http://localhost:8090/users?ids={1}",User[].class,
		//		StringUtils.join(ids,","));
		
		//listUser2 =  Arrays.asList(users);
		
		/*System.out.println("listUser2.size():" + listUser2.size());
		Integer integer=1;
		for (User user : listUser2) {
			
			System.out.println("UserID:" + user.getId());
			System.out.println("UserName:" + user.getName());
			System.out.println("UserXingBie:" + user.getXingBie());
			System.out.println("integer:" + integer);
			integer=integer+1;
		}
		
		System.out.println("==================================================");
		for (int i = 0; i < listUser2.size(); i++) {
			System.out.println("UserID:" + listUser2.get(i).getId());
			System.out.println("UserName:" + listUser2.get(i).getName());
			System.out.println("UserXingBie:" + listUser2.get(i).getXingBie());
			System.out.println("integer:" + i);
			
		}*/
        
		 return  Arrays.asList(users);
		 //return listUser2;
		
	}
}

2. 消费端 UserBatchCommand 类

package com.support;

import java.util.ArrayList;
import java.util.List;

import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.springframework.beans.factory.annotation.Autowired;

import com.model.User;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.service.UserService;
import com.serviceImpl.UserServiceImpl;

import scala.sys.process.processInternal;

public class UserBatchCommand extends HystrixCommand<List<User>> {
	
	@Autowired
	private UserService userService;
	private List<Long> userIds;
	
	public UserBatchCommand(UserService userService,
			List<Long> userIds) {
		super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("userServiceCommand")));
		this.userIds = userIds;
		this.userService = userService;
		}
	
	@Override
	protected List<User> run() throws Exception {
		System.out.println("UserBatchCommand run():" + userIds.get(0) +"  " + userIds.get(1));
		return userService.findAll(userIds);
	}
	
	public static void main(String[] args) throws Exception {
		List<Long> list = new ArrayList<>();
		UserService userService =  new UserServiceImpl();
		list.add(1L);
		list.add(2L);
		UserBatchCommand userBatchCommand = new UserBatchCommand(userService,list);
		List<User> listUser = new ArrayList<>();
		listUser=userBatchCommand.run();
		
	}
}

3. 消费端 UserCollapseCommand 类

package com.support;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import com.model.*;

import com.netflix.hystrix.HystrixCollapser;
import com.netflix.hystrix.HystrixCollapserKey;
import com.netflix.hystrix.HystrixCollapserProperties;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
//import com.netflix.hystrix.HystrixCommand.Setter;
import com.service.UserService;

public class UserCollapseCommand extends HystrixCollapser<List<User>, User, Long> {
	private UserService userService;
	private Long userId;
	
	public UserCollapseCommand(UserService userService,Long userId) {
		super(Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey("userCollapseCommand"))
				.andCollapserPropertiesDefaults(
						HystrixCollapserProperties.Setter()
						.withTimerDelayInMilliseconds(100)));
		this.userService = userService;
		this.userId = userId;
	}
	
	@Override
	public Long getRequestArgument() {
		return userId;
	}
	
	@Override
	protected HystrixCommand<List<User>>
	createCommand(Collection<CollapsedRequest<User, Long>>
	collapsedRequests) {
		List<Long> userIds = new ArrayList<>(collapsedRequests.size());
		userIds.addAll(collapsedRequests.stream().map(CollapsedRequest::getArgument).collect(
				Collectors.toList()));
		return new UserBatchCommand(userService, userIds);
	}
	
	@Override
	protected void mapResponseToRequests(List<User> batchResponse,
			Collection<CollapsedRequest<User, Long>> collapsedRequests) {
		System.out.println("mapResponseToRequests========>");
		int count = 0;
		for (CollapsedRequest<User, Long> collapsedRequest:collapsedRequests) {
			User user = batchResponse.get(count++);
			collapsedRequest.setResponse(user);
		}
	}
}

4. 消费端 Controller 

package com.controller;

import org.springframework.beans.factory.annotation.Autowired;
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 com.model.User;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
//import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import com.service.UserService;
import com.support.UserCollapseCommand;

import java.util.ArrayList;
import java.util.List;
//import com.support.UserCollapseCommand;
//import ch.qos.logback.core.Context;
import java.util.concurrent.Future;

@RestController
public class CollapseCommandController2 {
	
	@Autowired
	private UserService userService;
	 
	
	
	@RequestMapping(value="/collapse2",method = RequestMethod.GET)
	public List<User> requestCollapse(@RequestParam(value="ids") List<Long> ids) {
		List<User> listUser = new ArrayList<>();
		System.out.println("CollapseCommandController requestCollapse 方法");
	
			//HystrixRequestContext context = HystrixRequestContext.initializeContext();
			
			List<Future<User>> futures = new ArrayList<Future<User>>();

	        for(Long id : ids) {
	        	UserCollapseCommand userCollapseCommand = 
	                    new UserCollapseCommand(userService,id); 
	            futures.add(userCollapseCommand.queue());
	        }

	        try {
	            for(Future<User> future : futures) {
	                System.out.println("CacheController的结果:" + future.get());  
	                listUser.add(future.get());
	            }
	        } catch (Exception e) {
	            e.printStackTrace();
	        }

		return listUser;
	}
	
}

5. 消费端过滤器,注意我们在过滤器中初始化 HystrixRequestContext (Hystrix 请求上下文),如果没有初始化Hystrix请求上下文会报错。

package com.example.server1;

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 com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;

public class HystrixRequestContextServletFilter implements Filter {
	private Integer i = 0;
	private HystrixRequestContext context;
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
		     throws IOException, ServletException {
		        //if(i==0) {
		          System.out.println("过滤器");
		          context = HystrixRequestContext.initializeContext();
		         // i++;
		       // }
		        try {
		            chain.doFilter(request, response);
		        } finally {
		            context.shutdown();
		        }
		    }

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub
		
	}
}

6. 消费端 Bean 配置类。注意 Bean配置文件需要与 SpringBoot 工程主类放在同一个包下,不然扫描步到 Bean 配置文件,无法加载配置的Bean 。

package com.example.server1;

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

import com.controller.CollapseCommandController;
import com.controller.CollapseCommandController2;
import com.controller.ListUserColltroller;
import com.controller.TestController2;
import com.serviceImpl.UserServiceImpl;
import com.support.UserBatchCommand;
import com.service.UserService;

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

7. 服务端 Controller 

package com.controller;

import java.io.LineNumberInputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.cloud.client.ServiceInstance;
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 com.model.User;



@RestController
public class UserController {
	private final Logger logger = Logger.getLogger(UserController.class);
	
	
	@RequestMapping(value="/users",method = RequestMethod.GET)
	public List<User> index(@RequestParam(value="ids") List<Long> ids) throws Exception {
		//System.out.println("hell-service UserService :");
		List<User> listUser = new ArrayList<User>();
		for (Long long1 : ids) {
			User user = new User();
			user.setId(long1);
			user.setName("lixia"+long1);
			user.setXingBie("男");
			
			listUser.add(user);
			
			/*System.out.println("long1:" + long1);
			System.out.println("userID:"+ user.getId());
			System.out.println("userID:"+ user.getName());
			System.out.println("userID:"+ user.getXingBie());*/
			
			System.out.println("long1:" + long1);
			Integer integer = 0;
			System.out.println("userID:"+ listUser.get(integer).getId());
			System.out.println("userID:"+ listUser.get(integer).getName());
			System.out.println("userID:"+ listUser.get(integer).getXingBie());
			integer++;
		}
		System.out.println("listUser.size():" +listUser.size());
		
		/*System.out.println("userID:"+ listUser.get(2).getId());
		System.out.println("userID:"+ listUser.get(2).getName());
		System.out.println("userID:"+ listUser.get(2).getXingBie());*/
		
		
		//System.out.println("user:" + listUser.get(0).getId() + " " + listUser.get(0).getName() +" "+ listUser.get(0).getXingBie());
		//System.out.println("user2:" + listUser.get(1).getId() + " " + listUser.get(1).getName() +" "+ listUser.get(1).getXingBie());
		return listUser;
		
	}
	
}

8. 服务端 Bean 配置类。注意 Bean配置文件需要与 SpringBoot 工程主类放在同一个包下,不然扫描步到 Bean 配置文件,无法加载配置的Bean 。

package com.example.server1;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;

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



@Configuration
public class WebComponent2Config {
    @Bean
    UserController userController() {
    	return new UserController();
    }
    
}

8. 通过浏览器访问消费端 Controller 进行测试

9. Hystrix 的请求合并功能非常鸡肋,只能在一次请求消费端的 Controller 中多次请求 service 时进行请求合并,不能在对多次请求消费端的 Controller 进行合并。如果只想在消费端的 Controller 代码中实现一次请求获取多个对象,直接用消费端 Controller 通过传 List 参数直接调用消费端 service 就可以实现了。

消费端直接批量调用 service 的 Controller 的方式编码比 Hystrix 请求合并少。

消费端直接批量调用 service 的 Controller 代码:

package com.controller;

import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
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 com.model.User;
import com.service.UserService;

import scala.unchecked;

@RestController
public class ListUserColltroller {
	private final Logger logger = Logger.getLogger(ListUserColltroller.class);

	@Autowired
	private UserService userService;
	@RequestMapping(value="/listUser",method = RequestMethod.GET)
	public List<User> requestCollapse(@RequestParam(value="ids") List<Long> ids) {
		System.out.println("/listUser");
		return userService.findAll(ids);
	}
}

测试:

猜你喜欢

转载自blog.csdn.net/lixiaxin200319/article/details/81188019
今日推荐