All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rpc.turbo.invoke.ServerInvokerFactory Maven / Gradle / Ivy

The newest version!
package rpc.turbo.invoke;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.common.base.Strings;
import com.google.common.collect.Streams;

import rpc.turbo.annotation.TurboService;
import rpc.turbo.common.TurboConnectService;
import rpc.turbo.server.TurboConnectServiceServerImpl;
import rpc.turbo.util.FastMap;
import rpc.turbo.util.concurrent.ConcurrentArrayList;
import rpc.turbo.util.concurrent.ConcurrentIntToObjectArrayMap;

/**
 * 服务端invoker工程类
 * 
 * @author Hank
 *
 */
public class ServerInvokerFactory {
	private static final Log logger = LogFactory.getLog(ServerInvokerFactory.class);

	private final String group;
	private final String app;

	public final String restPrefix;

	// 低频使用
	private final ConcurrentMap classRegisterMap = new ConcurrentHashMap<>();
	// 高频使用
	private final ConcurrentArrayList> invokerMap = new ConcurrentArrayList<>();
	// 高频使用, 非线程安全, 使用CopyOnWrite的方式添加元素
	private volatile FastMap> restInvokerMap = new FastMap<>(32, 0.5F);
	// 高频使用
	private final ConcurrentIntToObjectArrayMap serviceMethodNameMap = new ConcurrentIntToObjectArrayMap<>();

	private final AtomicInteger classIdGenerator = new AtomicInteger();
	private final ConcurrentMap classIdMap = new ConcurrentHashMap<>();

	public ServerInvokerFactory(String group, String app) {
		this.group = group;
		this.app = app;
		this.restPrefix = "/" + group + "/" + app + "/";

		TurboConnectService connectService = new TurboConnectServiceServerImpl(this);
		register(TurboConnectService.class, connectService);
	}

	public ServerInvokerFactory() {
		this(TurboService.DEFAULT_GROUP, TurboService.DEFAULT_APP);
	}

	/**
	 * 通过服务id获取invoker
	 * 
	 * @param serviceId
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public  Invoker get(int serviceId) {
		return (Invoker) invokerMap.get(serviceId);
	}

	/**
	 * 通过restPath获取invoker
	 * 
	 * @param restPath
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public  Invoker get(String restPath) {
		return (Invoker) restInvokerMap.get(restPath);
	}

	/**
	 * 通过服务id获取服务名称
	 * 
	 * @param serviceId
	 * 
	 * @return
	 */
	public String getServiceMethodName(int serviceId) {
		String serviceMethodName = serviceMethodNameMap.get(serviceId);

		if (serviceMethodName != null) {
			return serviceMethodName;
		}

		return serviceMethodNameMap.getOrUpdate(serviceId, () -> {
			Method method = get(serviceId).getMethod();
			return InvokerUtils.getServiceMethodName(group, app, method);
		});
	}

	/**
	 * 注册invoker
	 * 
	 * @param service
	 *            实现类实例,重复调用时不会覆盖,会一直使用首次注册的实例
	 * 
	 * @param clazz
	 *            服务接口
	 * 
	 */
	public synchronized void register(Class clazz, Object service) {
		register(Map.of(clazz, service));
	}

	/**
	 * 注册invoker
	 * 
	 * @param map
	 *            key:服务接口 value:实现类
	 */
	public synchronized void register(Map, Object> map) {
		if (map == null) {
			throw new InvokeException("map is null");
		}

		final AtomicInteger serviceIdCounter = new AtomicInteger(invokerMap.size());

		List> invokers = map//
				.entrySet()//
				.stream()//
				.flatMap(kv -> convertToInvokerStream(kv.getKey(), kv.getValue(), serviceIdCounter))//
				.collect(Collectors.toList());

		if (invokers.isEmpty()) {
			return;
		}

		invokerMap.addAll(invokers);
		putRestInvoker(invokers);
	}

	// copy on write
	private synchronized void putRestInvoker(List> invokers) {
		FastMap> map = new FastMap<>(restInvokerMap);

		invokers.forEach(invoker -> {
			String restPath = InvokerUtils.getRestPath(invoker.method);

			if (!Strings.isNullOrEmpty(restPath)) {
				map.put(restPath, invoker);

				if (logger.isInfoEnabled()) {
					logger.info(InvokerUtils.getServiceMethodName(group, app, invoker.method) + " restPath:"
							+ restPrefix + restPath);
				}
			}
		});

		restInvokerMap = map;
	}

	private  Stream> convertToInvokerStream(Class clazz, Object service,
			AtomicInteger serviceIdCounter) {

		if (clazz == null) {
			throw new InvokeException("clazz cannot be null");
		}

		if (service == null) {
			throw new InvokeException("service cannot be null");
		}

		if (!clazz.isInstance(service)) {
			throw new InvokeException("clazz is the interface, service is the implemention");
		}

		if (!clazz.isInterface()) {
			throw new InvokeException("the clazz must be interface");
		}

		if (!Modifier.isPublic(clazz.getModifiers())) {
			throw new InvokeException("the clazz must be public");
		}

		TurboService classConfig = clazz.getAnnotation(TurboService.class);
		if (classConfig != null && classConfig.ignore()) {
			if (logger.isInfoEnabled()) {
				logger.info(clazz + " ignore");
			}

			return Stream.empty();
		}

		if (classRegisterMap.containsKey(InvokerUtils.getServiceClassName(group, app, clazz))) {
			return Stream.empty();
		}

		Method[] allMethods = clazz.getMethods();
		for (Method method : allMethods) {
			if (!CompletableFuture.class.equals(method.getReturnType())) {
				throw new RuntimeException("method return-type must be CompletableFuture, "
						+ InvokerUtils.getServiceMethodName(group, app, method));
			}
		}

		classRegisterMap.put(InvokerUtils.getServiceClassName(group, app, clazz), Boolean.TRUE);
		if (logger.isInfoEnabled()) {
			logger.info("service " + clazz + " register");
		}

		Stream methodStream = Stream//
				.of(allMethods)//
				.filter(m -> Modifier.isPublic(m.getModifiers()))//
				.filter(m -> !Modifier.isStatic(m.getModifiers()))//
				.peek(m -> {
					if (!CompletableFuture.class.equals(m.getReturnType())) {
						throw new RuntimeException("method return-type must be CompletableFuture, "
								+ InvokerUtils.getServiceMethodName(group, app, m));
					}
				})//
				.filter(m -> {
					TurboService methodConfig = m.getAnnotation(TurboService.class);

					if (methodConfig != null && methodConfig.ignore()) {
						if (logger.isInfoEnabled()) {
							logger.info(InvokerUtils.getServiceMethodName(group, app, m) + " ignore");
							return false;
						}
					}

					return true;
				});

		// 特殊处理,保证编号正确性
		if (TurboConnectService.class.equals(clazz)) {
			methodStream = methodStream.sorted((m0, m1) -> {
				int sort0 = TurboConnectService.serviceOrderMap.get(m0.getName());
				int sort1 = TurboConnectService.serviceOrderMap.get(m1.getName());

				return sort0 - sort1;
			});
		}

		// 注册classId
		for (Method method : allMethods) {
			registerClassId(method);
		}

		Stream> invokerStream = methodStream//
				.map(m -> {
					int serviceId = serviceIdCounter.getAndIncrement();

					if (logger.isInfoEnabled()) {
						logger.info(InvokerUtils.getServiceMethodName(group, app, m) + " serviceId:" + serviceId);
					}

					return new JavassistInvoker<>(serviceId, service, m.getDeclaringClass(), m);
				});

		return invokerStream;
	}

	/**
	 * 获取已注册的class
	 * 
	 * @return
	 */
	public List getClassRegisterList() {
		return new ArrayList<>(classRegisterMap.keySet());
	}

	/**
	 * 获取已注册的method:serviceId映射
	 * 
	 * @return
	 */
	public Map getMethodRegisterMap() {
		Map registerMap = new HashMap<>();

		for (int i = 0; i < invokerMap.size(); i++) {
			JavassistInvoker invoker = invokerMap.get(i);
			Method method = invoker.method;

			registerMap.put(InvokerUtils.getServiceMethodName(group, app, method), i);
		}

		return registerMap;
	}

	/**
	 * 获取已注册的 className:id 映射
	 * 
	 * @return
	 */
	public Map getClassIdMap() {
		return classIdMap;
	}

	/**
	 * 获取已注册的rest服务列表
	 * 
	 * @return
	 */
	public List getRestRegisterList() {
		return Streams//
				.stream((Iterable) restInvokerMap.keys())//
				.map(path -> restPrefix + path)//
				.collect(Collectors.toList());
	}

	private void registerClassId(Method method) {
		if (method == null) {
			return;
		}

		Type returnType = method.getGenericReturnType();
		registerClassId(returnType);

		Type[] genericParameterTypes = method.getGenericParameterTypes();
		for (int i = 0; i < genericParameterTypes.length; i++) {
			registerClassId(genericParameterTypes[i]);
		}
	}

	private void registerClassId(Type type) {
		if (type == null) {
			return;
		}

		if (type instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType) type;
			Type rawType = parameterizedType.getRawType();
			registerClassId(rawType);

			Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
			for (int i = 0; i < actualTypeArguments.length; i++) {
				registerClassId(actualTypeArguments[i]);
			}
		} else if (type instanceof Class) {
			Class clazz = (Class) type;

			if (clazz.isInterface()) {
				return;
			}

			if (clazz.isPrimitive()) {
				return;
			}

			if (clazz.isArray()) {
				return;
			}

			if (clazz.isEnum()) {
				return;
			}

			if (clazz.isAnnotation()) {
				return;
			}

			if (clazz.isAnonymousClass()) {
				return;
			}

			if (clazz.equals(CompletableFuture.class)) {
				return;
			}

			String className = clazz.getName();

			if (className.startsWith("java.lang.")) {
				return;
			}

			if (classIdMap.containsKey(className)) {
				return;
			}

			int classId = classIdMap//
					.computeIfAbsent(className, key -> classIdGenerator.getAndIncrement());

			logger.info("register Serializer.classId " + className + ":" + classId);

			Method[] childMethods = getChildMethods(clazz);
			for (int i = 0; i < childMethods.length; i++) {
				registerClassId(childMethods[i]);
			}
		}
	}

	private Method[] getChildMethods(Class clazz) {
		BeanInfo info;
		try {
			info = Introspector.getBeanInfo(clazz);
		} catch (Throwable t) {
			return new Method[0];
		}

		PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
		if (descriptors.length == 0) {
			return new Method[0];
		}

		Method[] childMethods = new Method[descriptors.length << 1];

		for (int i = 0; i < descriptors.length; i++) {
			PropertyDescriptor descriptor = descriptors[i];
			childMethods[i] = descriptor.getReadMethod();
			childMethods[i << 1] = descriptor.getWriteMethod();
		}

		return childMethods;
	}

	public static void main(String[] args) throws Exception {

	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy