/** * Index * * @author william.liangf */ public class Index { // 日志输出 private static final Logger logger = LoggerFactory.getLogger(Index.class); @Autowired private HttpServletRequest request; @Autowired private ProviderService providerService; @Autowired private ConsumerService consumerService; public void execute(Context context) { Set<String> applications = new HashSet<String>(); Set<String> services = new HashSet<String>(); List<Provider> pList = new ArrayList<Provider>(); try { pList = providerService.findAll(); } catch (Exception e) { logger.error(e.getMessage(), e); } for (Provider p : pList) { applications.add(p.getApplication()); services.add(p.getService()); } List<Consumer> cList = new ArrayList<Consumer>(); try { cList = consumerService.findAll(); } catch (Exception e) { logger.error(e.getMessage(), e); } for (Consumer c : cList) { applications.add(c.getApplication()); services.add(c.getService()); } context.put("rootContextPath", new RootContextPath(request.getContextPath())); context.put("services", services.size()); context.put("providers", pList.size()); context.put("consumers", cList.size()); context.put("applications", applications.size()); } }
/** * @author li * @version 1 (2014年12月22日 下午2:26:18) * @since Java7 */ public class AbstractRedisRegistry extends FailbackRegistry { private static final Logger logger = LoggerFactory.getLogger(AbstractRedisRegistry.class); private final ScheduledExecutorService expireExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("DubboRegistryExpireTimer", true)); private final ScheduledFuture<?> expireFuture; private final String root; private final Map<String, JedisPool> jedisPools = new ConcurrentHashMap<String, JedisPool>(); private final ConcurrentMap<String, RedisRegistryNotifier> notifiers = new ConcurrentHashMap<String, RedisRegistryNotifier>(); private int reconnectPeriod; private final int expirePeriod; private volatile boolean admin = false; private boolean replicate; public AbstractRedisRegistry(URL url) { super(url); RedisRegistryUtil.assertNotAnyHost(url); GenericObjectPoolConfig config = RedisRegistryUtil.genericObjectPoolConfig(url); List<String> addresses = RedisRegistryUtil.getAddresses(url); for (String address : addresses) { JedisPool jedisPool = RedisRegistryUtil.initJedisPoolAndCheck(url, config, address); jedisPools.put(address, jedisPool); } this.replicate = RedisRegistryUtil.getReplicate(url); this.reconnectPeriod = url.getParameter( Constants.REGISTRY_RECONNECT_PERIOD_KEY, Constants.DEFAULT_REGISTRY_RECONNECT_PERIOD); this.root = RedisRegistryUtil.getGroup(url); this.expirePeriod = url.getParameter(Constants.SESSION_TIMEOUT_KEY, Constants.DEFAULT_SESSION_TIMEOUT); this.expireFuture = expireExecutor.scheduleWithFixedDelay( new Runnable() { public void run() { try { deferExpired(); // 延长过期时间 } catch (Throwable t) { // 防御性容错 logger.error( "Unexpected exception occur at defer expire time, cause: " + t.getMessage(), t); } } }, expirePeriod / 2, expirePeriod / 2, TimeUnit.MILLISECONDS); } private void deferExpired() { for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) { JedisPool jedisPool = entry.getValue(); try { Jedis jedis = jedisPool.getResource(); try { RedisRegistryUtil.publishToJedis(jedis, getRegistered(), root, expirePeriod); if (admin) { clean(jedis); } if (!replicate) { break; // 如果服务器端已同步数据,只需写入单台机器 } } finally { jedisPool.returnResource(jedis); } } catch (Throwable t) { logger.warn( "Failed to write provider heartbeat to redis registry. registry: " + entry.getKey() + ", cause: " + t.getMessage(), t); } } } // 监控中心负责删除过期脏数据 private void clean(Jedis jedis) { RedisRegistryUtil.clean(jedis, root); } public boolean isAvailable() { for (JedisPool jedisPool : jedisPools.values()) { try { Jedis jedis = jedisPool.getResource(); try { if (jedis.isConnected()) { return true; // 至少需单台机器可用 } } finally { jedisPool.returnResource(jedis); } } catch (Throwable t) { } } return false; } public void destroy() { super.destroy(); try { expireFuture.cancel(true); } catch (Throwable t) { logger.warn(t.getMessage(), t); } try { for (RedisRegistryNotifier notifier : notifiers.values()) { notifier.shutdown(); } } catch (Throwable t) { logger.warn(t.getMessage(), t); } for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) { JedisPool jedisPool = entry.getValue(); try { jedisPool.destroy(); } catch (Throwable t) { logger.warn( "Failed to destroy the redis registry client. registry: " + entry.getKey() + ", cause: " + t.getMessage(), t); } } } public void doRegister(URL url) { String key = RedisRegistryUtil.toCategoryPath(url, root); String value = url.toFullString(); String expire = String.valueOf(System.currentTimeMillis() + expirePeriod); boolean success = false; RpcException exception = null; for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) { JedisPool jedisPool = entry.getValue(); try { Jedis jedis = jedisPool.getResource(); try { jedis.hset(key, value, expire); jedis.publish(key, Constants.REGISTER); success = true; if (!replicate) { break; // 如果服务器端已同步数据,只需写入单台机器 } } finally { jedisPool.returnResource(jedis); } } catch (Throwable t) { exception = new RpcException( "Failed to register service to redis registry. registry: " + entry.getKey() + ", service: " + url + ", cause: " + t.getMessage(), t); } } if (exception != null) { if (success) { logger.warn(exception.getMessage(), exception); } else { throw exception; } } } public void doUnregister(URL url) { String key = RedisRegistryUtil.toCategoryPath(url, root); String value = url.toFullString(); RpcException exception = null; boolean success = false; for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) { JedisPool jedisPool = entry.getValue(); try { Jedis jedis = jedisPool.getResource(); try { jedis.hdel(key, value); jedis.publish(key, Constants.UNREGISTER); success = true; if (!replicate) { break; // 如果服务器端已同步数据,只需写入单台机器 } } finally { jedisPool.returnResource(jedis); } } catch (Throwable t) { exception = new RpcException( "Failed to unregister service to redis registry. registry: " + entry.getKey() + ", service: " + url + ", cause: " + t.getMessage(), t); } } if (exception != null) { if (success) { logger.warn(exception.getMessage(), exception); } else { throw exception; } } } public void doSubscribe(final URL url, final NotifyListener listener) { String service = RedisRegistryUtil.toServicePath(url, root); RedisRegistryNotifier notifier = notifiers.get(service); if (notifier == null) { RedisRegistryNotifier newNotifier = new RedisRegistryNotifier(service, this); notifiers.putIfAbsent(service, newNotifier); notifier = notifiers.get(service); if (notifier == newNotifier) { notifier.start(); } } boolean success = false; RpcException exception = null; for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) { JedisPool jedisPool = entry.getValue(); try { Jedis jedis = jedisPool.getResource(); try { if (service.endsWith(Constants.ANY_VALUE)) { admin = true; Set<String> keys = jedis.keys(service); if (keys != null && keys.size() > 0) { Map<String, Set<String>> serviceKeys = RedisRegistryUtil.getServiceKeys(keys, root); for (Set<String> sk : serviceKeys.values()) { doNotify(jedis, sk, url, Arrays.asList(listener)); } } } else { doNotify( jedis, jedis.keys(service + Constants.PATH_SEPARATOR + Constants.ANY_VALUE), url, Arrays.asList(listener)); } success = true; break; // 只需读一个服务器的数据 } finally { jedisPool.returnResource(jedis); } } catch (Throwable t) { // 尝试下一个服务器 exception = new RpcException( "Failed to subscribe service from redis registry. registry: " + entry.getKey() + ", service: " + url + ", cause: " + t.getMessage(), t); } } if (exception != null) { if (success) { logger.warn(exception.getMessage(), exception); } else { throw exception; } } } public void doNotify(Jedis jedis, String key) { for (Map.Entry<URL, Set<NotifyListener>> entry : new HashMap<URL, Set<NotifyListener>>(getSubscribed()).entrySet()) { doNotify( jedis, Arrays.asList(key), entry.getKey(), new HashSet<NotifyListener>(entry.getValue())); } } private void doNotify( Jedis jedis, Collection<String> keys, URL url, Collection<NotifyListener> listeners) { if (keys == null || keys.size() == 0 || listeners == null || listeners.size() == 0) { return; } long now = System.currentTimeMillis(); List<URL> result = new ArrayList<URL>(); List<String> categories = Arrays.asList(url.getParameter(Constants.CATEGORY_KEY, new String[0])); String consumerService = url.getServiceInterface(); for (String key : keys) { if (!Constants.ANY_VALUE.equals(consumerService)) { String prvoiderService = RedisRegistryUtil.toServiceName(key, root); if (!prvoiderService.equals(consumerService)) { continue; } } String category = RedisRegistryUtil.toCategoryName(key); if (!categories.contains(Constants.ANY_VALUE) && !categories.contains(category)) { continue; } Map<String, String> values = jedis.hgetAll(key); List<URL> urls = RedisRegistryUtil.getUrlsForDoNotify(url, now, values); if (urls.isEmpty()) { urls.add(RedisRegistryUtil.setUrlProperties(url, key, category, root)); } result.addAll(urls); if (logger.isWarnEnabled()) { logger.warn("redis notify: " + key + " = " + urls); } } if (result == null || result.size() == 0) { return; } for (NotifyListener listener : listeners) { notify(url, listener, result); } } public void doUnsubscribe(URL url, NotifyListener listener) { // do nothing } public Map<String, JedisPool> getJedisPools() { return jedisPools; } public int getReconnectPeriod() { return reconnectPeriod; } }
/** * GenericImplInvokerFilter * * @author william.liangf */ @Activate(group = Constants.CONSUMER, value = Constants.GENERIC_KEY, order = 20000) public class GenericImplFilter implements Filter { private static final Logger logger = LoggerFactory.getLogger(GenericImplFilter.class); private static final Class<?>[] GENERIC_PARAMETER_TYPES = new Class<?>[] {String.class, String[].class, Object[].class}; public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { String generic = invoker.getUrl().getParameter(Constants.GENERIC_KEY); if (ProtocolUtils.isGeneric(generic) && !Constants.$INVOKE.equals(invocation.getMethodName()) && invocation instanceof RpcInvocation) { RpcInvocation invocation2 = (RpcInvocation) invocation; String methodName = invocation2.getMethodName(); Class<?>[] parameterTypes = invocation2.getParameterTypes(); Object[] arguments = invocation2.getArguments(); String[] types = new String[parameterTypes.length]; for (int i = 0; i < parameterTypes.length; i++) { types[i] = ReflectUtils.getName(parameterTypes[i]); } Object[] args = PojoUtils.generalize(arguments); invocation2.setMethodName(Constants.$INVOKE); invocation2.setParameterTypes(GENERIC_PARAMETER_TYPES); invocation2.setArguments(new Object[] {methodName, types, args}); Result result = invoker.invoke(invocation2); if (!result.hasException()) { Object value = result.getValue(); try { Method method = invoker.getInterface().getMethod(methodName, parameterTypes); return new RpcResult( PojoUtils.realize(value, method.getReturnType(), method.getGenericReturnType())); } catch (NoSuchMethodException e) { throw new RpcException(e.getMessage(), e); } } else if (result.getException() instanceof GenericException) { GenericException exception = (GenericException) result.getException(); try { String className = exception.getExceptionClass(); Class<?> clazz = ReflectUtils.forName(className); Throwable targetException = null; Throwable lastException = null; try { targetException = (Throwable) clazz.newInstance(); } catch (Throwable e) { lastException = e; for (Constructor<?> constructor : clazz.getConstructors()) { try { targetException = (Throwable) constructor.newInstance(new Object[constructor.getParameterTypes().length]); break; } catch (Throwable e1) { lastException = e1; } } } if (targetException != null) { try { Field field = Throwable.class.getDeclaredField("detailMessage"); if (!field.isAccessible()) { field.setAccessible(true); } field.set(targetException, exception.getExceptionMessage()); } catch (Throwable e) { logger.warn(e.getMessage(), e); } result = new RpcResult(targetException); } else if (lastException != null) { throw lastException; } } catch (Throwable e) { throw new RpcException( "Can not deserialize exception " + exception.getExceptionClass() + ", message: " + exception.getExceptionMessage(), e); } } return result; } if (invocation.getMethodName().equals(Constants.$INVOKE) && invocation.getArguments() != null && invocation.getArguments().length == 3 && ProtocolUtils.isGeneric(generic)) { if (ProtocolUtils.isJavaGenericSerialization(generic)) { Object[] args = (Object[]) invocation.getArguments()[2]; for (Object arg : args) { if (!(byte[].class == arg.getClass())) { error(arg.getClass().getName()); } } } ((RpcInvocation) invocation) .setAttachment( Constants.GENERIC_KEY, invoker.getUrl().getParameter(Constants.GENERIC_KEY)); } return invoker.invoke(invocation); } private void error(String type) throws RpcException { throw new RpcException( new StringBuilder(32) .append("Generic serialization [") .append(Constants.GENERIC_SERIALIZATION_NATIVE_JAVA) .append("] only support message type ") .append(byte[].class) .append(" and your message type is ") .append(type) .toString()); } }
/** * ExchangeCodec. * * @author qianlei * @author william.liangf */ public class ExchangeCodec extends TelnetCodec { private static final Logger logger = LoggerFactory.getLogger(ExchangeCodec.class); // header length. protected static final int HEADER_LENGTH = 16; // magic header. protected static final short MAGIC = (short) 0xdabb; protected static final byte MAGIC_HIGH = Bytes.short2bytes(MAGIC)[0]; protected static final byte MAGIC_LOW = Bytes.short2bytes(MAGIC)[1]; // message flag. protected static final byte FLAG_REQUEST = (byte) 0x80; protected static final byte FLAG_TWOWAY = (byte) 0x40; protected static final byte FLAG_EVENT = (byte) 0x20; protected static final int SERIALIZATION_MASK = 0x1f; public Short getMagicCode() { return MAGIC; } public void encode(Channel channel, ChannelBuffer buffer, Object msg) throws IOException { if (msg instanceof Request) { encodeRequest(channel, buffer, (Request) msg); } else if (msg instanceof Response) { encodeResponse(channel, buffer, (Response) msg); } else { super.encode(channel, buffer, msg); } // TODO modified by lishen // System.out.println(">>>>>>>>>>>>>>>>>>>>>> the resulting byte size of encoding is " + // buffer.readableBytes()); if (logger.isTraceEnabled()) { logger.trace("the resulting byte size of encoding is " + buffer.readableBytes()); } } public Object decode(Channel channel, ChannelBuffer buffer) throws IOException { int readable = buffer.readableBytes(); byte[] header = new byte[Math.min(readable, HEADER_LENGTH)]; buffer.readBytes(header); return decode(channel, buffer, readable, header); } protected Object decode(Channel channel, ChannelBuffer buffer, int readable, byte[] header) throws IOException { // check magic number. if (readable > 0 && header[0] != MAGIC_HIGH || readable > 1 && header[1] != MAGIC_LOW) { int length = header.length; if (header.length < readable) { header = Bytes.copyOf(header, readable); buffer.readBytes(header, length, readable - length); } for (int i = 1; i < header.length - 1; i++) { if (header[i] == MAGIC_HIGH && header[i + 1] == MAGIC_LOW) { buffer.readerIndex(buffer.readerIndex() - header.length + i); header = Bytes.copyOf(header, i); break; } } return super.decode(channel, buffer, readable, header); } // check length. if (readable < HEADER_LENGTH) { return DecodeResult.NEED_MORE_INPUT; } // get data length. int len = Bytes.bytes2int(header, 12); checkPayload(channel, len); int tt = len + HEADER_LENGTH; if (readable < tt) { return DecodeResult.NEED_MORE_INPUT; } // limit input stream. ChannelBufferInputStream is = new ChannelBufferInputStream(buffer, len); try { return decodeBody(channel, is, header); } finally { if (is.available() > 0) { try { if (logger.isWarnEnabled()) { logger.warn("Skip input stream " + is.available()); } StreamUtils.skipUnusedStream(is); } catch (IOException e) { logger.warn(e.getMessage(), e); } } } } protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException { byte flag = header[2], proto = (byte) (flag & SERIALIZATION_MASK); Serialization s = CodecSupport.getSerialization(channel.getUrl(), proto); ObjectInput in = s.deserialize(channel.getUrl(), is); // get request id. long id = Bytes.bytes2long(header, 4); if ((flag & FLAG_REQUEST) == 0) { // decode response. Response res = new Response(id); if ((flag & FLAG_EVENT) != 0) { res.setEvent(Response.HEARTBEAT_EVENT); } // get status. byte status = header[3]; res.setStatus(status); if (status == Response.OK) { try { Object data; if (res.isHeartbeat()) { data = decodeHeartbeatData(channel, in); } else if (res.isEvent()) { data = decodeEventData(channel, in); } else { data = decodeResponseData(channel, in, getRequestData(id)); } res.setResult(data); } catch (Throwable t) { res.setStatus(Response.CLIENT_ERROR); res.setErrorMessage(StringUtils.toString(t)); } } else { res.setErrorMessage(in.readUTF()); } return res; } else { // decode request. Request req = new Request(id); req.setVersion("2.0.0"); req.setTwoWay((flag & FLAG_TWOWAY) != 0); if ((flag & FLAG_EVENT) != 0) { req.setEvent(Request.HEARTBEAT_EVENT); } try { Object data; if (req.isHeartbeat()) { data = decodeHeartbeatData(channel, in); } else if (req.isEvent()) { data = decodeEventData(channel, in); } else { data = decodeRequestData(channel, in); } req.setData(data); } catch (Throwable t) { // bad request req.setBroken(true); req.setData(t); } return req; } } protected Object getRequestData(long id) { DefaultFuture future = DefaultFuture.getFuture(id); if (future == null) return null; Request req = future.getRequest(); if (req == null) return null; return req.getData(); } protected void encodeRequest(Channel channel, ChannelBuffer buffer, Request req) throws IOException { Serialization serialization = getSerialization(channel); // header. byte[] header = new byte[HEADER_LENGTH]; // set magic number. Bytes.short2bytes(MAGIC, header); // set request and serialization flag. header[2] = (byte) (FLAG_REQUEST | serialization.getContentTypeId()); if (req.isTwoWay()) header[2] |= FLAG_TWOWAY; if (req.isEvent()) header[2] |= FLAG_EVENT; // set request id. Bytes.long2bytes(req.getId(), header, 4); // encode request data. int savedWriteIndex = buffer.writerIndex(); buffer.writerIndex(savedWriteIndex + HEADER_LENGTH); ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer); ObjectOutput out = serialization.serialize(channel.getUrl(), bos); try { if (req.isEvent()) { encodeEventData(channel, out, req.getData()); } else { encodeRequestData(channel, out, req.getData()); } out.flushBuffer(); } finally { // modified by lishen if (out instanceof Cleanable) { ((Cleanable) out).cleanup(); } } bos.flush(); bos.close(); int len = bos.writtenBytes(); checkPayload(channel, len); Bytes.int2bytes(len, header, 12); // write buffer.writerIndex(savedWriteIndex); buffer.writeBytes(header); // write header. buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len); } protected void encodeResponse(Channel channel, ChannelBuffer buffer, Response res) throws IOException { try { Serialization serialization = getSerialization(channel); // header. byte[] header = new byte[HEADER_LENGTH]; // set magic number. Bytes.short2bytes(MAGIC, header); // set request and serialization flag. header[2] = serialization.getContentTypeId(); if (res.isHeartbeat()) header[2] |= FLAG_EVENT; // set response status. byte status = res.getStatus(); header[3] = status; // set request id. Bytes.long2bytes(res.getId(), header, 4); int savedWriteIndex = buffer.writerIndex(); buffer.writerIndex(savedWriteIndex + HEADER_LENGTH); ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer); ObjectOutput out = serialization.serialize(channel.getUrl(), bos); try { // encode response data or error message. if (status == Response.OK) { if (res.isHeartbeat()) { encodeHeartbeatData(channel, out, res.getResult()); } else { encodeResponseData(channel, out, res.getResult()); } } else out.writeUTF(res.getErrorMessage()); out.flushBuffer(); } finally { // modified by lishen if (out instanceof Cleanable) { ((Cleanable) out).cleanup(); } } bos.flush(); bos.close(); int len = bos.writtenBytes(); checkPayload(channel, len); Bytes.int2bytes(len, header, 12); // write buffer.writerIndex(savedWriteIndex); buffer.writeBytes(header); // write header. buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len); } catch (Throwable t) { // 发送失败信息给Consumer,否则Consumer只能等超时了 if (!res.isEvent() && res.getStatus() != Response.BAD_RESPONSE) { try { // FIXME 在Codec中打印出错日志?在IoHanndler的caught中统一处理? logger.warn( "Fail to encode response: " + res + ", send bad_response info instead, cause: " + t.getMessage(), t); Response r = new Response(res.getId(), res.getVersion()); r.setStatus(Response.BAD_RESPONSE); r.setErrorMessage( "Failed to send response: " + res + ", cause: " + StringUtils.toString(t)); channel.send(r); return; } catch (RemotingException e) { logger.warn( "Failed to send bad_response info back: " + res + ", cause: " + e.getMessage(), e); } } // 重新抛出收到的异常 if (t instanceof IOException) { throw (IOException) t; } else if (t instanceof RuntimeException) { throw (RuntimeException) t; } else if (t instanceof Error) { throw (Error) t; } else { throw new RuntimeException(t.getMessage(), t); } } } @Override protected Object decodeData(ObjectInput in) throws IOException { return decodeRequestData(in); } @Deprecated protected Object decodeHeartbeatData(ObjectInput in) throws IOException { try { return in.readObject(); } catch (ClassNotFoundException e) { throw new IOException(StringUtils.toString("Read object failed.", e)); } } protected Object decodeRequestData(ObjectInput in) throws IOException { try { return in.readObject(); } catch (ClassNotFoundException e) { throw new IOException(StringUtils.toString("Read object failed.", e)); } } protected Object decodeResponseData(ObjectInput in) throws IOException { try { return in.readObject(); } catch (ClassNotFoundException e) { throw new IOException(StringUtils.toString("Read object failed.", e)); } } @Override protected void encodeData(ObjectOutput out, Object data) throws IOException { encodeRequestData(out, data); } private void encodeEventData(ObjectOutput out, Object data) throws IOException { out.writeObject(data); } @Deprecated protected void encodeHeartbeatData(ObjectOutput out, Object data) throws IOException { encodeEventData(out, data); } protected void encodeRequestData(ObjectOutput out, Object data) throws IOException { out.writeObject(data); } protected void encodeResponseData(ObjectOutput out, Object data) throws IOException { out.writeObject(data); } @Override protected Object decodeData(Channel channel, ObjectInput in) throws IOException { return decodeRequestData(channel, in); } protected Object decodeEventData(Channel channel, ObjectInput in) throws IOException { try { return in.readObject(); } catch (ClassNotFoundException e) { throw new IOException(StringUtils.toString("Read object failed.", e)); } } @Deprecated protected Object decodeHeartbeatData(Channel channel, ObjectInput in) throws IOException { try { return in.readObject(); } catch (ClassNotFoundException e) { throw new IOException(StringUtils.toString("Read object failed.", e)); } } protected Object decodeRequestData(Channel channel, ObjectInput in) throws IOException { return decodeRequestData(in); } protected Object decodeResponseData(Channel channel, ObjectInput in) throws IOException { return decodeResponseData(in); } protected Object decodeResponseData(Channel channel, ObjectInput in, Object requestData) throws IOException { return decodeResponseData(channel, in); } @Override protected void encodeData(Channel channel, ObjectOutput out, Object data) throws IOException { encodeRequestData(channel, out, data); } private void encodeEventData(Channel channel, ObjectOutput out, Object data) throws IOException { encodeEventData(out, data); } @Deprecated protected void encodeHeartbeatData(Channel channel, ObjectOutput out, Object data) throws IOException { encodeHeartbeatData(out, data); } protected void encodeRequestData(Channel channel, ObjectOutput out, Object data) throws IOException { encodeRequestData(out, data); } protected void encodeResponseData(Channel channel, ObjectOutput out, Object data) throws IOException { encodeResponseData(out, data); } }
/** * 包装的一个chanelhandler 提供线程池给子类调度用 具体操作可以看子类的覆盖 适配 * * @author wuzl */ public class WrappedChannelHandler implements ChannelHandlerDelegate { protected static final Logger logger = LoggerFactory.getLogger(WrappedChannelHandler.class); // 初始化共享的线程池 protected static final ExecutorService SHARED_EXECUTOR = Executors.newCachedThreadPool(new NamedThreadFactory("DubboSharedHandler", true)); // 对象独自的线程池 protected final ExecutorService executor; protected final ChannelHandler handler; protected final URL url; public WrappedChannelHandler(ChannelHandler handler, URL url) { this.handler = handler; this.url = url; // 从扩展实现中初始化线程池 executor = (ExecutorService) ExtensionLoader.getExtensionLoader(ThreadPool.class) .getAdaptiveExtension() .getExecutor(url); String componentKey = Constants.EXECUTOR_SERVICE_COMPONENT_KEY; if (Constants.CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(Constants.SIDE_KEY))) { componentKey = Constants.CONSUMER_SIDE; } DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension(); dataStore.put(componentKey, Integer.toString(url.getPort()), executor); // 保存起来 } public void close() { try { if (executor instanceof ExecutorService) { ((ExecutorService) executor).shutdown(); } } catch (Throwable t) { logger.warn("fail to destroy thread pool of server: " + t.getMessage(), t); } } public void connected(Channel channel) throws RemotingException { handler.connected(channel); } public void disconnected(Channel channel) throws RemotingException { handler.disconnected(channel); } public void sent(Channel channel, Object message) throws RemotingException { handler.sent(channel, message); } public void received(Channel channel, Object message) throws RemotingException { handler.received(channel, message); } public void caught(Channel channel, Throwable exception) throws RemotingException { handler.caught(channel, exception); } public ExecutorService getExecutor() { return executor; } public ChannelHandler getHandler() { if (handler instanceof ChannelHandlerDelegate) { return ((ChannelHandlerDelegate) handler).getHandler(); } else { return handler; } } public URL getUrl() { return url; } }
public class RedisTemplate { private static final Logger logger = LoggerFactory.getLogger(RedisTemplate.class); private ShardedJedisPool masterShardedJedisPool; public void setMasterShardedJedisPool(ShardedJedisPool masterShardedJedisPool) { this.masterShardedJedisPool = masterShardedJedisPool; } public void setSlaveShardedJedisPool(ShardedJedisPool slaveShardedJedisPool) { this.slaveShardedJedisPool = slaveShardedJedisPool; } private ShardedJedisPool slaveShardedJedisPool; /** * 设置一个key的过期时间(单位:秒) * * @param key key值 * @param seconds 多少秒后过期 * @return 1:设置了过期时间 0:没有设置过期时间/不能设置过期时间 */ public long expire(String key, int seconds) { if (key == null || key.equals("")) { return 0; } ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); return shardedJedis.expire(key, seconds); } catch (Exception ex) { logger.error("EXPIRE error[key=" + key + " seconds=" + seconds + "]" + ex.getMessage(), ex); } finally { returnResource(shardedJedis); } return 0; } /** * 设置一个key在某个时间点过期 * * @param key key值 * @param unixTimestamp unix时间戳,从1970-01-01 00:00:00开始到现在的秒数 * @return 1:设置了过期时间 0:没有设置过期时间/不能设置过期时间 */ public long expireAt(String key, int unixTimestamp) { if (key == null || key.equals("")) { return 0; } ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); return shardedJedis.expireAt(key, unixTimestamp); } catch (Exception ex) { logger.error( "EXPIRE error[key=" + key + " unixTimestamp=" + unixTimestamp + "]" + ex.getMessage(), ex); } finally { returnResource(shardedJedis); } return 0; } /** * 截断一个List * * @param key 列表key * @param start 开始位置 从0开始 * @param end 结束位置 * @return 状态码 */ public String trimList(String key, long start, long end) { if (key == null || key.equals("")) { return "-"; } ShardedJedis shardedJedis = null; try { shardedJedis = slaveShardedJedisPool.getResource(); return shardedJedis.ltrim(key, start, end); } catch (Exception ex) { logger.error( "LTRIM 出错[key=" + key + " start=" + start + " end=" + end + "]" + ex.getMessage(), ex); } finally { returnResource(shardedJedis); } return "-"; } /** * 检查Set长度 * * @param key * @return */ public long countSet(String key) { if (key == null) { return 0; } ShardedJedis shardedJedis = null; try { shardedJedis = slaveShardedJedisPool.getResource(); return shardedJedis.scard(key); } catch (Exception ex) { logger.error("countSet error.", ex); } finally { returnResource(shardedJedis); } return 0; } /** * 添加到Set中(同时设置过期时间) * * @param key key值 * @param seconds 过期时间 单位s * @param value * @return */ public boolean addSet(String key, int seconds, String... value) { boolean result = addSet(key, value); if (result) { long i = expire(key, seconds); return i == 1; } return false; } /** * 添加到Set中 * * @param key * @param value * @return */ public boolean addSet(String key, String... value) { if (key == null || value == null) { return false; } ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); shardedJedis.sadd(key, value); return true; } catch (Exception ex) { logger.error("setList error.", ex); } finally { returnResource(shardedJedis); } return false; } /** * @param key * @param value * @return 判断值是否包含在set中 */ public boolean containsInSet(String key, String value) { if (key == null || value == null) { return false; } ShardedJedis shardedJedis = null; try { shardedJedis = slaveShardedJedisPool.getResource(); return shardedJedis.sismember(key, value); } catch (Exception ex) { logger.error("setList error.", ex); } finally { returnResource(shardedJedis); } return false; } /** * 获取Set * * @param key * @return */ public Set<String> getSet(String key) { ShardedJedis shardedJedis = null; try { shardedJedis = slaveShardedJedisPool.getResource(); return shardedJedis.smembers(key); } catch (Exception ex) { logger.error("getList error.", ex); } finally { returnResource(shardedJedis); } return null; } /** * 从set中删除value * * @param key * @return */ public boolean removeSetValue(String key, String... value) { ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); shardedJedis.srem(key, value); return true; } catch (Exception ex) { logger.error("getList error.", ex); } finally { returnResource(shardedJedis); } return false; } /** * 从list中删除value 默认count 1 * * @param key * @param values 值list * @return */ public int removeListValue(String key, List<String> values) { return removeListValue(key, 1, values); } /** * 从list中删除value * * @param key * @param count * @param values 值list * @return */ public int removeListValue(String key, long count, List<String> values) { int result = 0; if (values != null && values.size() > 0) { for (String value : values) { if (removeListValue(key, count, value)) { result++; } } } return result; } /** * 从list中删除value * * @param key * @param count 要删除个数 * @param value * @return */ public boolean removeListValue(String key, long count, String value) { ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); shardedJedis.lrem(key, count, value); return true; } catch (Exception ex) { logger.error("getList error.", ex); ; } finally { returnResource(shardedJedis); } return false; } /** * 截取List * * @param key * @param start 起始位置 * @param end 结束位置 * @return */ public List<String> rangeList(String key, long start, long end) { if (key == null || key.equals("")) { return null; } ShardedJedis shardedJedis = null; try { shardedJedis = slaveShardedJedisPool.getResource(); return shardedJedis.lrange(key, start, end); } catch (Exception ex) { logger.error( "rangeList 出错[key=" + key + " start=" + start + " end=" + end + "]" + ex.getMessage(), ex); } finally { returnResource(shardedJedis); } return null; } /** * 检查List长度 * * @param key * @return */ public long countList(String key) { if (key == null) { return 0; } ShardedJedis shardedJedis = null; try { shardedJedis = slaveShardedJedisPool.getResource(); return shardedJedis.llen(key); } catch (Exception ex) { logger.error("countList error.", ex); } finally { returnResource(shardedJedis); } return 0; } /** * 添加到List中(同时设置过期时间) * * @param key key值 * @param seconds 过期时间 单位s * @param value * @return */ public boolean addList(String key, int seconds, String... value) { boolean result = addList(key, value); if (result) { long i = expire(key, seconds); return i == 1; } return false; } /** * 添加到List * * @param key * @param value * @return */ public boolean addList(String key, String... value) { if (key == null || value == null) { return false; } ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); shardedJedis.lpush(key, value); return true; } catch (Exception ex) { logger.error("setList error.", ex); } finally { returnResource(shardedJedis); } return false; } /** * 添加到List(只新增) * * @param key * @param value * @return */ public boolean addList(String key, List<String> list) { if (key == null || list == null || list.size() == 0) { return false; } for (String value : list) { addList(key, value); } return true; } /** * 获取List * * @param key * @return */ public List<String> getList(String key) { ShardedJedis shardedJedis = null; try { shardedJedis = slaveShardedJedisPool.getResource(); return shardedJedis.lrange(key, 0, -1); } catch (Exception ex) { logger.error("getList error.", ex); } finally { returnResource(shardedJedis); } return null; } /** * 设置HashSet对象 * * @param domain 域名 * @param key 键值 * @param value Json String or String value * @return */ public boolean setHSet(String domain, String key, String value) { if (value == null) return false; ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); shardedJedis.hset(domain, key, value); return true; } catch (Exception ex) { logger.error("setHSet error.", ex); } finally { returnResource(shardedJedis); } return false; } /** * 获得HashSet对象 * * @param domain 域名 * @param key 键值 * @return Json String or String value */ public String getHSet(String domain, String key) { ShardedJedis shardedJedis = null; try { shardedJedis = slaveShardedJedisPool.getResource(); return shardedJedis.hget(domain, key); } catch (Exception ex) { logger.error("getHSet error.", ex); } finally { returnResource(shardedJedis); } return null; } /** * 删除HashSet对象 * * @param domain 域名 * @param key 键值 * @return 删除的记录数 */ public long delHSet(String domain, String key) { ShardedJedis shardedJedis = null; long count = 0; try { shardedJedis = masterShardedJedisPool.getResource(); count = shardedJedis.hdel(domain, key); } catch (Exception ex) { logger.error("delHSet error.", ex); } finally { returnResource(shardedJedis); } return count; } /** * 删除HashSet对象 * * @param domain 域名 * @param key 键值 * @return 删除的记录数 */ public long delHSet(String domain, String... key) { ShardedJedis shardedJedis = null; long count = 0; try { shardedJedis = masterShardedJedisPool.getResource(); count = shardedJedis.hdel(domain, key); } catch (Exception ex) { logger.error("delHSet error.", ex); } finally { returnResource(shardedJedis); } return count; } /** * 判断key是否存在 * * @param domain 域名 * @param key 键值 * @return */ public boolean existsHSet(String domain, String key) { ShardedJedis shardedJedis = null; boolean isExist = false; try { shardedJedis = slaveShardedJedisPool.getResource(); isExist = shardedJedis.hexists(domain, key); } catch (Exception ex) { logger.error("existsHSet error.", ex); } finally { returnResource(shardedJedis); } return isExist; } /** * 全局扫描hset * * @param match field匹配模式 * @return */ public List<Map.Entry<String, String>> scanHSet(String domain, String match) { ShardedJedis shardedJedis = null; try { int cursor = 0; shardedJedis = slaveShardedJedisPool.getResource(); ScanParams scanParams = new ScanParams(); scanParams.match(match); Jedis jedis = shardedJedis.getShard(domain); ScanResult<Map.Entry<String, String>> scanResult; List<Map.Entry<String, String>> list = new ArrayList<Map.Entry<String, String>>(); do { scanResult = jedis.hscan(domain, String.valueOf(cursor), scanParams); list.addAll(scanResult.getResult()); cursor = Integer.parseInt(scanResult.getStringCursor()); } while (cursor > 0); return list; } catch (Exception ex) { logger.error("scanHSet error.", ex); } finally { returnResource(shardedJedis); } return null; } /** * 返回 domain 指定的哈希集中所有字段的value值 * * @param domain * @return */ public List<String> hvals(String domain) { ShardedJedis shardedJedis = null; List<String> retList = null; try { shardedJedis = slaveShardedJedisPool.getResource(); retList = shardedJedis.hvals(domain); } catch (Exception ex) { logger.error("hvals error.", ex); } finally { returnResource(shardedJedis); } return retList; } /** * 返回 domain 指定的哈希集中所有字段的key值 * * @param domain * @return */ public Set<String> hkeys(String domain) { ShardedJedis shardedJedis = null; Set<String> retList = null; try { shardedJedis = slaveShardedJedisPool.getResource(); retList = shardedJedis.hkeys(domain); } catch (Exception ex) { logger.error("hkeys error.", ex); } finally { returnResource(shardedJedis); } return retList; } /** * 返回 domain 指定的哈希key值总数 * * @param domain * @return */ public long lenHset(String domain) { ShardedJedis shardedJedis = null; long retList = 0; try { shardedJedis = slaveShardedJedisPool.getResource(); retList = shardedJedis.hlen(domain); } catch (Exception ex) { logger.error("hkeys error.", ex); } finally { returnResource(shardedJedis); } return retList; } /** * 设置排序集合 * * @param key * @param score * @param value * @return */ public boolean setSortedSet(String key, long score, String value) { ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); shardedJedis.zadd(key, score, value); return true; } catch (Exception ex) { logger.error("setSortedSet error.", ex); } finally { returnResource(shardedJedis); } return false; } /** * 获得排序集合 * * @param key * @param startScore * @param endScore * @param orderByDesc * @return */ public Set<String> getSoredSet(String key, long startScore, long endScore, boolean orderByDesc) { ShardedJedis shardedJedis = null; try { shardedJedis = slaveShardedJedisPool.getResource(); if (orderByDesc) { return shardedJedis.zrevrangeByScore(key, endScore, startScore); } else { return shardedJedis.zrangeByScore(key, startScore, endScore); } } catch (Exception ex) { logger.error("getSoredSet error.", ex); } finally { returnResource(shardedJedis); } return null; } /** * 计算排序长度 * * @param key * @param startScore * @param endScore * @return */ public long countSoredSet(String key, long startScore, long endScore) { ShardedJedis shardedJedis = null; try { shardedJedis = slaveShardedJedisPool.getResource(); Long count = shardedJedis.zcount(key, startScore, endScore); return count == null ? 0L : count; } catch (Exception ex) { logger.error("countSoredSet error.", ex); } finally { returnResource(shardedJedis); } return 0L; } /** * 删除排序集合 * * @param key * @param value * @return */ public boolean delSortedSet(String key, String value) { ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); long count = shardedJedis.zrem(key, value); return count > 0; } catch (Exception ex) { logger.error("delSortedSet error.", ex); } finally { returnResource(shardedJedis); } return false; } /** * 获得排序集合 * * @param key * @param startRange * @param endRange * @param orderByDesc * @return */ public Set<String> getSoredSetByRange( String key, int startRange, int endRange, boolean orderByDesc) { ShardedJedis shardedJedis = null; try { shardedJedis = slaveShardedJedisPool.getResource(); if (orderByDesc) { return shardedJedis.zrevrange(key, startRange, endRange); } else { return shardedJedis.zrange(key, startRange, endRange); } } catch (Exception ex) { logger.error("getSoredSetByRange error.", ex); } finally { returnResource(shardedJedis); } return null; } /** * 获得排序打分 * * @param key * @return */ public Double getScore(String key, String member) { ShardedJedis shardedJedis = null; try { shardedJedis = slaveShardedJedisPool.getResource(); return shardedJedis.zscore(key, member); } catch (Exception ex) { logger.error("getSoredSet error.", ex); } finally { returnResource(shardedJedis); } return null; } public boolean set(String key, String value, int second) { ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); shardedJedis.setex(key, second, value); return true; } catch (Exception ex) { logger.error("set error.", ex); } finally { returnResource(shardedJedis); } return false; } public boolean set(String key, String value) { ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); shardedJedis.set(key, value); return true; } catch (Exception ex) { logger.error("set error.", ex); } finally { returnResource(shardedJedis); } return false; } public String get(String key) { ShardedJedis shardedJedis = null; try { shardedJedis = slaveShardedJedisPool.getResource(); return shardedJedis.get(key); } catch (Exception ex) { logger.error("get error.", ex); return null; } finally { returnResource(shardedJedis); } } public boolean del(String key) { ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); shardedJedis.del(key); return true; } catch (Exception ex) { logger.error("del error.", ex); } finally { returnResource(shardedJedis); } return false; } public long incr(String key) { ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); return shardedJedis.incr(key); } catch (Exception ex) { logger.error("incr error.", ex); } finally { returnResource(shardedJedis); } return 0; } public long decr(String key) { ShardedJedis shardedJedis = null; try { shardedJedis = masterShardedJedisPool.getResource(); return shardedJedis.decr(key); } catch (Exception ex) { logger.error("incr error.", ex); } finally { returnResource(shardedJedis); } return 0; } private void returnResource(ShardedJedis shardedJedis) { try { shardedJedis.close(); } catch (Exception e) { logger.error("returnResource error.", e); } } }
/** * MinaServer mina用的是session类似于netty的chanel * * @author qian.lei * @author william.liangf * @author ding.lid */ public class MinaServer extends AbstractServer { private static final Logger logger = LoggerFactory.getLogger(MinaServer.class); private SocketAcceptor acceptor; public MinaServer(URL url, ChannelHandler handler) throws RemotingException { super( url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME))); } @Override protected void doOpen() throws Throwable { // set thread pool. acceptor = new SocketAcceptor( getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS), Executors.newCachedThreadPool(new NamedThreadFactory("MinaServerWorker", true))); // config SocketAcceptorConfig cfg = (SocketAcceptorConfig) acceptor.getDefaultConfig(); cfg.setThreadModel(ThreadModel.MANUAL); // set codec. acceptor .getFilterChain() .addLast( "codec", new ProtocolCodecFilter(new MinaCodecAdapter(getCodec(), getUrl(), this))); acceptor.bind(getBindAddress(), new MinaHandler(getUrl(), this)); } @Override protected void doClose() throws Throwable { try { if (acceptor != null) { acceptor.unbind(getBindAddress()); } } catch (Throwable e) { logger.warn(e.getMessage(), e); } } public Collection<Channel> getChannels() { Set<IoSession> sessions = acceptor.getManagedSessions(getBindAddress()); Collection<Channel> channels = new HashSet<Channel>(); for (IoSession session : sessions) { if (session.isConnected()) { channels.add(MinaChannel.getOrAddChannel(session, getUrl(), this)); } } return channels; } public Channel getChannel(InetSocketAddress remoteAddress) { Set<IoSession> sessions = acceptor.getManagedSessions(getBindAddress()); for (IoSession session : sessions) { if (session.getRemoteAddress().equals(remoteAddress)) { return MinaChannel.getOrAddChannel(session, getUrl(), this); } } return null; } public boolean isBound() { return acceptor.isManaged(getBindAddress()); } }
/** * AbstractRegistry. (SPI, Prototype, ThreadSafe) * * @author chao.liuc * @author william.liangf */ public abstract class AbstractRegistry implements Registry { // 日志输出 protected final Logger logger = LoggerFactory.getLogger(getClass()); // URL地址分隔符,用于文件缓存中,服务提供者URL分隔 private static final char URL_SEPARATOR = ' '; // URL地址分隔正则表达式,用于解析文件缓存中服务提供者URL列表 private static final String URL_SPLIT = "\\s+"; private URL registryUrl; // 本地磁盘缓存文件 private File file; // 本地磁盘缓存,其中特殊的key值.registies记录注册中心列表,其它均为notified服务提供者列表 private final Properties properties = new Properties(); // 文件缓存定时写入 private final ExecutorService registryCacheExecutor = Executors.newFixedThreadPool(1, new NamedThreadFactory("DubboSaveRegistryCache", true)); // 是否是同步保存文件 private final boolean syncSaveFile; private final AtomicLong lastCacheChanged = new AtomicLong(); private final Set<URL> registered = new ConcurrentHashSet<URL>(); private final ConcurrentMap<URL, Set<NotifyListener>> subscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>(); private final ConcurrentMap<URL, Map<String, List<URL>>> notified = new ConcurrentHashMap<URL, Map<String, List<URL>>>(); public AbstractRegistry(URL url) { setUrl(url); // 启动文件保存定时器 syncSaveFile = url.getParameter(Constants.REGISTRY_FILESAVE_SYNC_KEY, false); String filename = url.getParameter( Constants.FILE_KEY, System.getProperty("user.home") + "/.dubbo/dubbo-registry-" + url.getHost() + ".cache"); File file = null; if (ConfigUtils.isNotEmpty(filename)) { file = new File(filename); if (!file.exists() && file.getParentFile() != null && !file.getParentFile().exists()) { if (!file.getParentFile().mkdirs()) { throw new IllegalArgumentException( "Invalid registry store file " + file + ", cause: Failed to create directory " + file.getParentFile() + "!"); } } } this.file = file; loadProperties(); notify(url.getBackupUrls()); } protected void setUrl(URL url) { if (url == null) { throw new IllegalArgumentException("registry url == null"); } this.registryUrl = url; } public URL getUrl() { return registryUrl; } public Set<URL> getRegistered() { return registered; } public Map<URL, Set<NotifyListener>> getSubscribed() { return subscribed; } public Map<URL, Map<String, List<URL>>> getNotified() { return notified; } public File getCacheFile() { return file; } public Properties getCacheProperties() { return properties; } public AtomicLong getLastCacheChanged() { return lastCacheChanged; } private class SaveProperties implements Runnable { private long version; private SaveProperties(long version) { this.version = version; } public void run() { doSaveProperties(version); } } public void doSaveProperties(long version) { if (version < lastCacheChanged.get()) { return; } if (file == null) { return; } Properties newProperties = new Properties(); // 保存之前先读取一遍,防止多个注册中心之间冲突 InputStream in = null; try { if (file.exists()) { in = new FileInputStream(file); newProperties.load(in); } } catch (Throwable e) { logger.warn("Failed to load registry store file, cause: " + e.getMessage(), e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { logger.warn(e.getMessage(), e); } } } // 保存 try { newProperties.putAll(properties); File lockfile = new File(file.getAbsolutePath() + ".lock"); if (!lockfile.exists()) { lockfile.createNewFile(); } RandomAccessFile raf = new RandomAccessFile(lockfile, "rw"); try { FileChannel channel = raf.getChannel(); try { FileLock lock = channel.tryLock(); if (lock == null) { throw new IOException( "Can not lock the registry cache file " + file.getAbsolutePath() + ", ignore and retry later, maybe multi java process use the file, please config: dubbo.registry.file=xxx.properties"); } // 保存 try { if (!file.exists()) { file.createNewFile(); } FileOutputStream outputFile = new FileOutputStream(file); try { newProperties.store(outputFile, "Dubbo Registry Cache"); } finally { outputFile.close(); } } finally { lock.release(); } } finally { channel.close(); } } finally { raf.close(); } } catch (Throwable e) { if (version < lastCacheChanged.get()) { return; } else { registryCacheExecutor.execute(new SaveProperties(lastCacheChanged.incrementAndGet())); } logger.warn("Failed to save registry store file, cause: " + e.getMessage(), e); } } private void loadProperties() { if (file != null && file.exists()) { InputStream in = null; try { in = new FileInputStream(file); properties.load(in); if (logger.isInfoEnabled()) { logger.info("Load registry store file " + file + ", data: " + properties); } } catch (Throwable e) { logger.warn("Failed to load registry store file " + file, e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { logger.warn(e.getMessage(), e); } } } } } public List<URL> getCacheUrls(URL url) { for (Map.Entry<Object, Object> entry : properties.entrySet()) { String key = (String) entry.getKey(); String value = (String) entry.getValue(); if (key != null && key.length() > 0 && key.equals(url.getServiceKey()) && (Character.isLetter(key.charAt(0)) || key.charAt(0) == '_') && value != null && value.length() > 0) { String[] arr = value.trim().split(URL_SPLIT); List<URL> urls = new ArrayList<URL>(); for (String u : arr) { urls.add(URL.valueOf(u)); } return urls; } } return null; } public List<URL> lookup(URL url) { List<URL> result = new ArrayList<URL>(); Map<String, List<URL>> notifiedUrls = getNotified().get(url); if (notifiedUrls != null && notifiedUrls.size() > 0) { for (List<URL> urls : notifiedUrls.values()) { for (URL u : urls) { if (!Constants.EMPTY_PROTOCOL.equals(u.getProtocol())) { result.add(u); } } } } else { final AtomicReference<List<URL>> reference = new AtomicReference<List<URL>>(); NotifyListener listener = new NotifyListener() { public void notify(List<URL> urls) { reference.set(urls); } }; subscribe(url, listener); // 订阅逻辑保证第一次notify后再返回 List<URL> urls = reference.get(); if (urls != null && urls.size() > 0) { for (URL u : urls) { if (!Constants.EMPTY_PROTOCOL.equals(u.getProtocol())) { result.add(u); } } } } return result; } public void register(URL url) { if (url == null) { throw new IllegalArgumentException("register url == null"); } if (logger.isInfoEnabled()) { logger.info("Register: " + url); } registered.add(url); } public void unregister(URL url) { if (url == null) { throw new IllegalArgumentException("unregister url == null"); } if (logger.isInfoEnabled()) { logger.info("Unregister: " + url); } registered.remove(url); } public void subscribe(URL url, NotifyListener listener) { if (url == null) { throw new IllegalArgumentException("subscribe url == null"); } if (listener == null) { throw new IllegalArgumentException("subscribe listener == null"); } if (logger.isInfoEnabled()) { logger.info("Subscribe: " + url); } Set<NotifyListener> listeners = subscribed.get(url); if (listeners == null) { subscribed.putIfAbsent(url, new ConcurrentHashSet<NotifyListener>()); listeners = subscribed.get(url); } listeners.add(listener); } public void unsubscribe(URL url, NotifyListener listener) { if (url == null) { throw new IllegalArgumentException("unsubscribe url == null"); } if (listener == null) { throw new IllegalArgumentException("unsubscribe listener == null"); } if (logger.isInfoEnabled()) { logger.info("Unsubscribe: " + url); } Set<NotifyListener> listeners = subscribed.get(url); if (listeners != null) { listeners.remove(listener); } } protected void recover() throws Exception { // register Set<URL> recoverRegistered = new HashSet<URL>(getRegistered()); if (!recoverRegistered.isEmpty()) { if (logger.isInfoEnabled()) { logger.info("Recover register url " + recoverRegistered); } for (URL url : recoverRegistered) { register(url); } } // subscribe Map<URL, Set<NotifyListener>> recoverSubscribed = new HashMap<URL, Set<NotifyListener>>(getSubscribed()); if (!recoverSubscribed.isEmpty()) { if (logger.isInfoEnabled()) { logger.info("Recover subscribe url " + recoverSubscribed.keySet()); } for (Map.Entry<URL, Set<NotifyListener>> entry : recoverSubscribed.entrySet()) { URL url = entry.getKey(); for (NotifyListener listener : entry.getValue()) { subscribe(url, listener); } } } } protected static List<URL> filterEmpty(URL url, List<URL> urls) { if (urls == null || urls.size() == 0) { List<URL> result = new ArrayList<URL>(1); result.add(url.setProtocol(Constants.EMPTY_PROTOCOL)); return result; } return urls; } protected void notify(List<URL> urls) { if (urls == null || urls.isEmpty()) return; for (Map.Entry<URL, Set<NotifyListener>> entry : getSubscribed().entrySet()) { URL url = entry.getKey(); if (!UrlUtils.isMatch(url, urls.get(0))) { continue; } Set<NotifyListener> listeners = entry.getValue(); if (listeners != null) { for (NotifyListener listener : listeners) { try { notify(url, listener, filterEmpty(url, urls)); } catch (Throwable t) { logger.error( "Failed to notify registry event, urls: " + urls + ", cause: " + t.getMessage(), t); } } } } } protected void notify(URL url, NotifyListener listener, List<URL> urls) { if (url == null) { throw new IllegalArgumentException("notify url == null"); } if (listener == null) { throw new IllegalArgumentException("notify listener == null"); } if ((urls == null || urls.size() == 0) && !Constants.ANY_VALUE.equals(url.getServiceInterface())) { logger.warn("Ignore empty notify urls for subscribe url " + url); return; } if (logger.isInfoEnabled()) { logger.info("Notify urls for subscribe url " + url + ", urls: " + urls); } Map<String, List<URL>> result = new HashMap<String, List<URL>>(); for (URL u : urls) { if (UrlUtils.isMatch(url, u)) { String category = u.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); List<URL> categoryList = result.get(category); if (categoryList == null) { categoryList = new ArrayList<URL>(); result.put(category, categoryList); } categoryList.add(u); } } if (result.size() == 0) { return; } Map<String, List<URL>> categoryNotified = notified.get(url); if (categoryNotified == null) { notified.putIfAbsent(url, new ConcurrentHashMap<String, List<URL>>()); categoryNotified = notified.get(url); } for (Map.Entry<String, List<URL>> entry : result.entrySet()) { String category = entry.getKey(); List<URL> categoryList = entry.getValue(); categoryNotified.put(category, categoryList); saveProperties(url); listener.notify(categoryList); } } private void saveProperties(URL url) { if (file == null) { return; } try { StringBuilder buf = new StringBuilder(); Map<String, List<URL>> categoryNotified = notified.get(url); if (categoryNotified != null) { for (List<URL> us : categoryNotified.values()) { for (URL u : us) { if (buf.length() > 0) { buf.append(URL_SEPARATOR); } buf.append(u.toFullString()); } } } properties.setProperty(url.getServiceKey(), buf.toString()); long version = lastCacheChanged.incrementAndGet(); if (syncSaveFile) { doSaveProperties(version); } else { registryCacheExecutor.execute(new SaveProperties(version)); } } catch (Throwable t) { logger.warn(t.getMessage(), t); } } public void destroy() { if (logger.isInfoEnabled()) { logger.info("Destroy registry:" + getUrl()); } Set<URL> destroyRegistered = new HashSet<URL>(getRegistered()); if (!destroyRegistered.isEmpty()) { for (URL url : new HashSet<URL>(getRegistered())) { if (url.getParameter(Constants.DYNAMIC_KEY, true)) { try { unregister(url); if (logger.isInfoEnabled()) { logger.info("Destroy unregister url " + url); } } catch (Throwable t) { logger.warn( "Failed to unregister url " + url + " to registry " + getUrl() + " on destroy, cause: " + t.getMessage(), t); } } } } Map<URL, Set<NotifyListener>> destroySubscribed = new HashMap<URL, Set<NotifyListener>>(getSubscribed()); if (!destroySubscribed.isEmpty()) { for (Map.Entry<URL, Set<NotifyListener>> entry : destroySubscribed.entrySet()) { URL url = entry.getKey(); for (NotifyListener listener : entry.getValue()) { try { unsubscribe(url, listener); if (logger.isInfoEnabled()) { logger.info("Destroy unsubscribe url " + url); } } catch (Throwable t) { logger.warn( "Failed to unsubscribe url " + url + " to registry " + getUrl() + " on destroy, cause: " + t.getMessage(), t); } } } } } public String toString() { return getUrl().toString(); } }
/** * AbstractRegistryService * * @author william.liangf */ public abstract class AbstractRegistryService implements RegistryService { // 日志输出 protected final Logger logger = LoggerFactory.getLogger(getClass()); // 已注册的服务 // Map<serviceName, Map<url, queryString>> private final ConcurrentMap<String, List<URL>> registered = new ConcurrentHashMap<String, List<URL>>(); // 已订阅的服务 // Map<serviceName, queryString> private final ConcurrentMap<String, Map<String, String>> subscribed = new ConcurrentHashMap<String, Map<String, String>>(); // 已通知的服务 // Map<serviceName, Map<url, queryString>> private final ConcurrentMap<String, List<URL>> notified = new ConcurrentHashMap<String, List<URL>>(); // 已订阅服务的监听器列表 // Map<serviceName, List<notificationListener>> private final ConcurrentMap<String, List<NotifyListener>> notifyListeners = new ConcurrentHashMap<String, List<NotifyListener>>(); public void register(URL url) { if (logger.isInfoEnabled()) { logger.info("Register service: " + url.getServiceKey() + ",url:" + url); } register(url.getServiceKey(), url); } public void unregister(URL url) { if (logger.isInfoEnabled()) { logger.info("Unregister service: " + url.getServiceKey() + ",url:" + url); } unregister(url.getServiceKey(), url); } public void subscribe(URL url, NotifyListener listener) { if (logger.isInfoEnabled()) { logger.info("Subscribe service: " + url.getServiceKey() + ",url:" + url); } subscribe(url.getServiceKey(), url, listener); } public void unsubscribe(URL url, NotifyListener listener) { if (logger.isInfoEnabled()) { logger.info("Unsubscribe service: " + url.getServiceKey() + ",url:" + url); } unsubscribe(url.getServiceKey(), url, listener); } public List<URL> lookup(URL url) { return getRegistered(url.getServiceKey()); } public void register(String service, URL url) { if (service == null) { throw new IllegalArgumentException("service == null"); } if (url == null) { throw new IllegalArgumentException("url == null"); } List<URL> urls = registered.get(service); if (urls == null) { registered.putIfAbsent(service, new CopyOnWriteArrayList<URL>()); urls = registered.get(service); } if (!urls.contains(url)) { urls.add(url); } } public void unregister(String service, URL url) { if (service == null) { throw new IllegalArgumentException("service == null"); } if (url == null) { throw new IllegalArgumentException("url == null"); } List<URL> urls = registered.get(service); if (urls != null) { URL deleteURL = null; for (URL u : urls) { if (u.toIdentityString().equals(url.toIdentityString())) { deleteURL = u; break; } } if (deleteURL != null) { urls.remove(deleteURL); } } } public void subscribe(String service, URL url, NotifyListener listener) { if (service == null) { throw new IllegalArgumentException("service == null"); } if (url == null) { throw new IllegalArgumentException("parameters == null"); } if (listener == null) { throw new IllegalArgumentException("listener == null"); } subscribed.put(service, url.getParameters()); addListener(service, listener); } public void unsubscribe(String service, URL url, NotifyListener listener) { if (service == null) { throw new IllegalArgumentException("service == null"); } if (url == null) { throw new IllegalArgumentException("parameters == null"); } if (listener == null) { throw new IllegalArgumentException("listener == null"); } subscribed.remove(service); removeListener(service, listener); } // consumer 与 provider的 listener可以一起存储,都是根据服务名称共享 private void addListener(final String service, final NotifyListener listener) { if (listener == null) { return; } List<NotifyListener> listeners = notifyListeners.get(service); if (listeners == null) { notifyListeners.putIfAbsent(service, new CopyOnWriteArrayList<NotifyListener>()); listeners = notifyListeners.get(service); } if (listeners != null && !listeners.contains(listener)) { listeners.add(listener); } } private void removeListener(final String service, final NotifyListener listener) { if (listener == null) { return; } List<NotifyListener> listeners = notifyListeners.get(service); if (listeners != null) { listeners.remove(listener); } } private void doNotify(String service, List<URL> urls) { notified.put(service, urls); List<NotifyListener> listeners = notifyListeners.get(service); if (listeners != null) { for (NotifyListener listener : listeners) { try { notify(service, urls, listener); } catch (Throwable t) { logger.error( "Failed to notify registry event, service: " + service + ", urls: " + urls + ", cause: " + t.getMessage(), t); } } } } protected void notify(String service, List<URL> urls, NotifyListener listener) { listener.notify(urls); } protected final void forbid(String service) { doNotify(service, new ArrayList<URL>(0)); } protected final void notify(String service, List<URL> urls) { if (service == null || service.length() == 0 || urls == null || urls.size() == 0) { return; } doNotify(service, urls); } public Map<String, List<URL>> getRegistered() { return Collections.unmodifiableMap(registered); } public List<URL> getRegistered(String service) { return Collections.unmodifiableList(registered.get(service)); } public Map<String, Map<String, String>> getSubscribed() { return Collections.unmodifiableMap(subscribed); } public Map<String, String> getSubscribed(String service) { return subscribed.get(service); } public Map<String, List<URL>> getNotified() { return Collections.unmodifiableMap(notified); } public List<URL> getNotified(String service) { return Collections.unmodifiableList(notified.get(service)); } public Map<String, List<NotifyListener>> getListeners() { return Collections.unmodifiableMap(notifyListeners); } }