/* * Copyright 2009-2016 Weibo, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.weibo.api.motan.transport.netty; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ThreadPoolExecutor; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import com.weibo.api.motan.common.URLParamType; import com.weibo.api.motan.exception.MotanErrorMsgConstant; import com.weibo.api.motan.exception.MotanFrameworkException; import com.weibo.api.motan.exception.MotanServiceException; import com.weibo.api.motan.rpc.Request; import com.weibo.api.motan.rpc.Response; import com.weibo.api.motan.rpc.DefaultResponse; import com.weibo.api.motan.rpc.RpcContext; import com.weibo.api.motan.transport.Channel; import com.weibo.api.motan.transport.MessageHandler; import com.weibo.api.motan.util.LoggerUtil; import com.weibo.api.motan.util.NetUtils; /** * * @author maijunsheng * @version 创建时间:2013-5-31 * */ public class NettyChannelHandler extends SimpleChannelHandler { private ThreadPoolExecutor threadPoolExecutor; private MessageHandler messageHandler; private Channel serverChannel; public NettyChannelHandler(Channel serverChannel) { this.serverChannel = serverChannel; } public NettyChannelHandler(Channel serverChannel, MessageHandler messageHandler) { this.serverChannel = serverChannel; this.messageHandler = messageHandler; } public NettyChannelHandler(Channel serverChannel, MessageHandler messageHandler, ThreadPoolExecutor threadPoolExecutor) { this.serverChannel = serverChannel; this.messageHandler = messageHandler; this.threadPoolExecutor = threadPoolExecutor; } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { LoggerUtil.info("NettyChannelHandler channelConnected: remote=" + ctx.getChannel().getRemoteAddress() + " local=" + ctx.getChannel().getLocalAddress() + " event=" + e.getClass().getSimpleName()); } @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { LoggerUtil.info("NettyChannelHandler channelDisconnected: remote=" + ctx.getChannel().getRemoteAddress() + " local=" + ctx.getChannel().getLocalAddress() + " event=" + e.getClass().getSimpleName()); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object message = e.getMessage(); if (message instanceof Request) { processRequest(ctx, e); } else if (message instanceof Response) { processResponse(ctx, e); } else { LoggerUtil.error("NettyChannelHandler messageReceived type not support: class=" + message.getClass()); throw new MotanFrameworkException("NettyChannelHandler messageReceived type not support: class=" + message.getClass()); } } /** * <pre> * request process: 主要来自于client的请求,需要使用threadPoolExecutor进行处理,避免service message处理比较慢导致iothread被阻塞 * </pre> * * @param ctx * @param e */ private void processRequest(final ChannelHandlerContext ctx, MessageEvent e) { final Request request = (Request) e.getMessage(); request.setAttachment(URLParamType.host.getName(), NetUtils.getHostName(ctx.getChannel().getRemoteAddress())); final long processStartTime = System.currentTimeMillis(); // 使用线程池方式处理 try { threadPoolExecutor.execute(new Runnable() { @Override public void run() { try{ RpcContext.init(request); processRequest(ctx, request, processStartTime); }finally{ RpcContext.destroy(); } } }); } catch (RejectedExecutionException rejectException) { DefaultResponse response = new DefaultResponse(); response.setRequestId(request.getRequestId()); response.setException(new MotanServiceException("process thread pool is full, reject", MotanErrorMsgConstant.SERVICE_REJECT)); response.setProcessTime(System.currentTimeMillis() - processStartTime); e.getChannel().write(response); LoggerUtil .debug("process thread pool is full, reject, active={} poolSize={} corePoolSize={} maxPoolSize={} taskCount={} requestId={}", threadPoolExecutor.getActiveCount(), threadPoolExecutor.getPoolSize(), threadPoolExecutor.getCorePoolSize(), threadPoolExecutor.getMaximumPoolSize(), threadPoolExecutor.getTaskCount(), request.getRequestId()); } } private void processRequest(ChannelHandlerContext ctx, Request request, long processStartTime) { Object result = messageHandler.handle(serverChannel, request); DefaultResponse response = null; if (!(result instanceof DefaultResponse)) { response = new DefaultResponse(result); } else { response = (DefaultResponse) result; } response.setRequestId(request.getRequestId()); response.setProcessTime(System.currentTimeMillis() - processStartTime); if (ctx.getChannel().isConnected()) { ctx.getChannel().write(response); } } private void processResponse(ChannelHandlerContext ctx, MessageEvent e) { messageHandler.handle(serverChannel, e.getMessage()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { LoggerUtil.error("NettyChannelHandler exceptionCaught: remote=" + ctx.getChannel().getRemoteAddress() + " local=" + ctx.getChannel().getLocalAddress() + " event=" + e.getCause(), e.getCause()); ctx.getChannel().close(); } }