范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Netty线程模型源码剖析(文章尾附带全流程图)

  Netty服务端设置参数
  首先创建bossGroup和workerGroup(Netty客户端和服务端启动源码在上篇文章中), bossGroup只是处理客户端连接请求 ,真正和客户端业务处理会交给workerGroup完成。new NioEventLoopGroup的源码如下(其中有很多调this和super的地方就不一一列出来了,流程图中都包含,只对重要代码做注释分析)://bossGroup和workerGroup都属于MultithreadEventLoopGroup,相当于线程池 protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {     //如果线程数为0,则取默认值,有io.netty.eventLoopThreads取这个值,没有的话默认是cpu核数*2     super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args); } //进入super到MultithreadEventExecutorGroup,然后会给每个children赋值 children[i] = newChild(executor, args);代码如下 protected EventLoop newChild(Executor executor, Object... args) throws Exception {         //创建NioEventLoop,相当于线程池中的每个线程         return new NioEventLoop(this, executor, (SelectorProvider) args[0],             ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);     }  NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,                  SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {         super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);         if (selectorProvider == null) {             throw new NullPointerException("selectorProvider");         }         if (strategy == null) {             throw new NullPointerException("selectStrategy");         }         provider = selectorProvider;         final SelectorTuple selectorTuple = openSelector();//调openSelector()方法,打开Selector处理Channel,就是NIO代码         selector = selectorTuple.selector;         unwrappedSelector = selectorTuple.unwrappedSelector;         selectStrategy = strategy;     }
  创建务器端的启动对象ServerBootstrap(就是一个空对象),然后再对其设置group,设置channel,设置option及在pipeline中加入自己写的Handler。public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {     super.group(parentGroup);//点进去就是给group属性赋值     if (childGroup == null) {         throw new NullPointerException("childGroup");     }     if (this.childGroup != null) {         throw new IllegalStateException("childGroup set already");     }     this.childGroup = childGroup;//给childGroup属性赋值,记住这两个属性,下面会用     return this; }//给ServerBootstrap设置channel,最后会跟到下面这段代码 public ReflectiveChannelFactory(Class<? extends T> clazz) {         ObjectUtil.checkNotNull(clazz, "clazz");         try {            //通过传过来的类对象NioServerSocketChannel.class,得到构造参数,下面函数会用            //会在下面一节中分析这个NioServerSocketChannel.class的构造方法             this.constructor = clazz.getConstructor();         } catch (NoSuchMethodException e) {             throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +                     " does not have a public non-arg constructor", e);         }    } //将上述方法得到的constructor,传到本方法内 public B channelFactory(ChannelFactory<? extends C> channelFactory) {     if (channelFactory == null) {         throw new NullPointerException("channelFactory");     }     if (this.channelFactory != null) {         throw new IllegalStateException("channelFactory set already");     }     this.channelFactory = channelFactory;//给channelFactory属性赋值,用来创建对象,后续会用来创建对象     return self(); }//设置options,就是一个map,可以初始化服务器连接队列大小, //服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接 //多个客户端同时来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理 public  B option(ChannelOption option, T value) {     if (option == null) {         throw new NullPointerException("option");     }     if (value == null) {         synchronized (options) {             options.remove(option);         }     } else {         synchronized (options) {             options.put(option, value);         }     }     return self(); }//创建通道初始化对象,设置初始化参数,在 SocketChannel 建立起来之前执行 ////对workerGroup的SocketChannel设置自己写的处理器,把自己写的处理器加到管道中 public ServerBootstrap childHandler(ChannelHandler childHandler) {     if (childHandler == null) {         throw new NullPointerException("childHandler");     }     this.childHandler = childHandler;     return this; }Netty服务端绑定端口
  Netty服务端绑定一个端口并且同步, 生成了一个ChannelFuture异步对象,通过isDone()等方法可以判断异步事件的执行情况;启动服务器(并绑定端口),bind是异步操作,sync方法是等待异步操作执行完毕(参考上一篇文章中服务端绑定端口代码),绑定源码如下://调用ServerBootstrap的bind函数一直跟最后会到AbstractBootstrap的doBind函数,此函数主要两步 //第一初始化并注册  initAndRegister(),第二 把ServerChannel绑定到网络端口 doBind0,第二步源码就不再分析了 final ChannelFuture initAndRegister() {         Channel channel = null;         try {             //就是用constructor.newInstance()即上一节中NioServerSocketChannel.class的构造方法来初始化             //参考下面源码分析初始化NioServerSocketChannel             channel = channelFactory.newChannel();             //初始化channel,获取管道ChannelPipeline,是在初始化NioServerSocketChannel产生的管道对象,            //向管道中添加ChannelInitializer对象,当channel注册时会调用andlerAdded从而调用initChannel             init(channel);//具体源码参考下面         } catch (Throwable t) {             if (channel != null) {                 channel.unsafe().closeForcibly();                 return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);             }           return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);         } 				//注册channel对象         ChannelFuture regFuture = config().group().register(channel);         if (regFuture.cause() != null) {             if (channel.isRegistered()) {                 channel.close();             } else {                 channel.unsafe().closeForcibly();             }         }         return regFuture;     } //向管道中添加ChannelInitializer对象,当channel注册时会调用andlerAdded从而调用initChannel void init(Channel channel) throws Exception {         final Map, Object> options = options0();         synchronized (options) {             setChannelOptions(channel, options, logger);         }         final Map, Object> attrs = attrs0();         synchronized (attrs) {             for (Entry, Object> e: attrs.entrySet()) {                 @SuppressWarnings("unchecked")                 AttributeKey key = (AttributeKey) e.getKey();                 channel.attr(key).set(e.getValue());             }         }         ChannelPipeline p = channel.pipeline();//获取已经生成的pipeline对象         final EventLoopGroup currentChildGroup = childGroup;         final ChannelHandler currentChildHandler = childHandler;         final Entry, Object>[] currentChildOptions;         final Entry, Object>[] currentChildAttrs;         synchronized (childOptions) {             currentChildOptions = childOptions.entrySet().toArray(newOptionArray(0));         }         synchronized (childAttrs) {             currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));         }        //向管道中添加ChannelInitializer对象,在注册channel时(参考下面的源码)handler的handlerAdded方法再调用initChannel方法,        //调用完initChannel会调用removeState删除临时产生的ChannelInitializer         p.addLast(new ChannelInitializer() {             @Override             public void initChannel(final Channel ch) throws Exception {                 final ChannelPipeline pipeline = ch.pipeline();                 ChannelHandler handler = config.handler();                 if (handler != null) {                     pipeline.addLast(handler);                 }                  ch.eventLoop().execute(new Runnable() {                     @Override                     public void run() {                   			//执行异步方法,向pipeline中添加ServerBootstrapAcceptor,此时pipeline中有 头、ServerBootstrapAcceptor、尾                   			//当满足条件时(客户端连接时),会执行ServerBootstrapAcceptor的channelRead方法                         pipeline.addLast(new ServerBootstrapAcceptor(                                 ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));                     }                 });             }         });     }//初始化NioServerSocketChannel实例 public NioServerSocketChannel() {         this(newSocket(DEFAULT_SELECTOR_PROVIDER));//跟代码最后会调用AbstractNioChannel的构造方法     } //创建ServerSocketChannel,其实就是NIO代码封装 private static ServerSocketChannel newSocket(SelectorProvider provider) {         try {             return provider.openServerSocketChannel();         } catch (IOException e) {             throw new ChannelException(                     "Failed to open a server socket.", e);         }     } //AbstractNioChannel的构造方法 protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {         super(parent);//调用AbstractChannel的构造方法         this.ch = ch;         this.readInterestOp = readInterestOp;         try {             ch.configureBlocking(false);//// 设置ServerSocketChannel为非阻塞         } catch (IOException e) {             try {                 ch.close();             } catch (IOException e2) {                 if (logger.isWarnEnabled()) {                     logger.warn(                             "Failed to close a partially initialized socket.", e2);                 }             }           throw new ChannelException("Failed to enter non-blocking mode.", e);         }     } //AbstractChannel的构造方法 protected AbstractChannel(Channel parent) {         this.parent = parent;//给parent赋值就是NioServerSocketChannel         id = newId();         unsafe = newUnsafe();         pipeline = newChannelPipeline();//初始话管道Pipeline,给pipeline属性,后续一直用到这个属性     }
  注册channel对象,config().group().register(channel)----->MultithreadEventLoopGroup.register----->SingleThreadEventLoop.register----->AbstractUnsafe.register//注册channel public final void register(EventLoop eventLoop, final ChannelPromise promise) {     if (eventLoop == null) {         throw new NullPointerException("eventLoop");     }     if (isRegistered()) {         promise.setFailure(new IllegalStateException("registered to an event loop already"));         return;     }     if (!isCompatible(eventLoop)) {         promise.setFailure(                 new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));         return;     }     AbstractChannel.this.eventLoop = eventLoop;     if (eventLoop.inEventLoop()) {         register0(promise);     } else {       //会走这里,执行异步操作,添加到队列中         try {             eventLoop.execute(new Runnable() {                 @Override                 public void run() {                     register0(promise);//执行异步方法,下面会分析                 }             });         } catch (Throwable t) {             logger.warn(                     "Force-closing a channel whose registration task was not accepted by an event loop: {}",                     AbstractChannel.this, t);             closeForcibly();             closeFuture.setClosed();             safeSetFailure(promise, t);         }     } } public void execute(Runnable task) {         if (task == null) {             throw new NullPointerException("task");         }         boolean inEventLoop = inEventLoop();//判断启动线程与当前线程是否相同   不同则有两种可能:未启动或者线程不同         addTask(task);//把异步任务(上一步的异步方法)添加到taskQueue队列中,后续会取         if (!inEventLoop) {            //第一次会启动,会调用SingleThreadEventExecutor的startThread()然后再调doStartThread            //最后再调用SingleThreadEventExecutor.this.run(),即NioEventLoop的run             startThread();             if (isShutdown()) {                 boolean reject = false;                 try {                     if (removeTask(task)) {                         reject = true;                     }                 } catch (UnsupportedOperationException e) {                 }                 if (reject) {                     reject();                 }             }         }         if (!addTaskWakesUp && wakesUpForTask(task)) {             wakeup(inEventLoop);         }     } //即NioEventLoop的run 无限循环执行selector监听事件 protected void run() {         for (;;) {             try {                 try {                     switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {                     case SelectStrategy.CONTINUE:                         continue;                     case SelectStrategy.BUSY_WAIT:                     case SelectStrategy.SELECT:                         select(wakenUp.getAndSet(false));//会调用selector.select(timeoutMillis)执行selector的监听事件,跟nio一样                         if (wakenUp.get()) {                             selector.wakeup();                         }                     default:                     }                 } catch (IOException e) {                     rebuildSelector0();                     handleLoopException(e);                     continue;                 }                 cancelledKeys = 0;                 needsToSelectAgain = false;                 final int ioRatio = this.ioRatio;                 if (ioRatio == 100) {                     try {                       //这个方法即监听有无链接事件和读写事件等,会循环selector中所有的事件                       //进入后会调用NioEventLoop的processSelectedKey方法,                       //最后当有客户端SelectionKey.OP_READ | SelectionKey.OP_ACCEPT时调用unsafe.read()                       //OP_ACCEPT事件即NioMessageUnsafe的read方法,OP_READ事件即NioByteUnsafe的read方法                         processSelectedKeys();                     } finally {                       //在执行这个方法,会调用SingleThreadEventExecutor的fetchFromScheduledTaskQueue方法                       //从taskQueue队列中不断的取异步任务,在上面源码分析过程中,向  taskQueue中存放了一个异步任务                       //即会执行register0(promise)方法,源码解析参考下面                       runAllTasks();                     }                 } else {                     final long ioStartTime = System.nanoTime();                     try {                         processSelectedKeys();                     } finally {                         final long ioTime = System.nanoTime() - ioStartTime;                         runAllTasks(ioTime * (100 - ioRatio) / ioRatio);                     }                 }             } catch (Throwable t) {                 handleLoopException(t);             }             try {                 if (isShuttingDown()) {                     closeAll();                     if (confirmShutdown()) {                         return;                     }                 }             } catch (Throwable t) {                 handleLoopException(t);             }         }     } //注册时队列中的异步任务 private void register0(ChannelPromise promise) {             try {                 if (!promise.setUncancellable() || !ensureOpen(promise)) {                     return;                 }                 boolean firstRegistration = neverRegistered;                 //会调用AbstractNioChannel的doRegister()方法,                //在javaChannel().register(eventLoop().unwrappedSelector(), 0, this)这一步向selector中注册channel,跟nio一样                 doRegister();                 neverRegistered = false;                 registered = true;                //跟下去最终调用AbstractChannelHandlerContext的callHandlerAdded方法,               //即调用pipeline中每个handler的handlerAdded方法,挨个handler执行,目前pipeline中有三个,头、ChannelInitializer、尾               //在上面代码init(channel);  向  pipeline 中添加过ChannelInitializer,最后会执行他的initChannel方法               pipeline.invokeHandlerAddedIfNeeded();                 safeSetSuccess(promise);                 //调用pipeline中每个handler的channelRegistered方法                 pipeline.fireChannelRegistered();                 if (isActive()) {                     if (firstRegistration) {                       //调用pipeline中每个handler的channelActive方法                         pipeline.fireChannelActive();                     } else if (config().isAutoRead()) {                         beginRead();                     }                 }             } catch (Throwable t) {                 closeForcibly();                 closeFuture.setClosed();                 safeSetFailure(promise, t);             }         }Netty客户端连接事件
  Netty的客户端启动时会连接服务端的端口,当发生客户端连接事件时调用NioMessageUnsafe的read方法,源码如下:public void read() {         assert eventLoop().inEventLoop();         final ChannelConfig config = config();         final ChannelPipeline pipeline = pipeline();//获取channel的pipeline,此时这个是serverSocketChannelPipeline         final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();         allocHandle.reset(config);         boolean closed = false;         Throwable exception = null;         try {             try {                 do {                     //readBuf缓冲区存放所有通过客户端连接事件过来的SocketChannel,                    //封装成NioSocketChannel放到readbuf,封装NioSocketChannel即调用其构造方法,跟NioServerSocketChannel一样,                   //包含设置管道,设置非阻塞,此时NioSocketChannel的pipeline只有头、尾                     int localRead = doReadMessages(readBuf);                     if (localRead == 0) {                         break;                     }                     if (localRead < 0) {                         closed = true;                         break;                     }                      allocHandle.incMessagesRead(localRead);                 } while (allocHandle.continueReading());             } catch (Throwable t) {                 exception = t;             }              int size = readBuf.size();             for (int i = 0; i < size; i ++) {                 readPending = false;                 //readBuf.get(i)即上面产生的NioSocketChannel对象                  //执行pipeline中所有handler的channelRead方法,此时pipeline中包含ServerBootstrapAcceptor                 pipeline.fireChannelRead(readBuf.get(i));             }             readBuf.clear();             allocHandle.readComplete();              pipeline.fireChannelReadComplete();//执行pipeline中所有handler的readComplete方法             if (exception != null) {                 closed = closeOnReadError(exception);                 pipeline.fireExceptionCaught(exception);             }             if (closed) {                 inputShutdown = true;                 if (isOpen()) {                     close(voidPromise());                 }             }         } finally {             if (!readPending && !config.isAutoRead()) {                 removeReadOp();             }         }     } }
  执行ServerBootstrapAcceptor的channelRead方法:public void channelRead(ChannelHandlerContext ctx, Object msg) {     final Channel child = (Channel) msg;     child.pipeline().addLast(childHandler);//向NioSocketChannel的pipeline中添加childHandler,childHandler就是server服务端自己写的那个ChannelInitializer     setChannelOptions(child, childOptions, logger);     for (Entry, Object> e: childAttrs) {         child.attr((AttributeKey) e.getKey()).set(e.getValue());     } 	//向childGroup即workerGroup中注册 NioSocketChannel,注册流程跟NioServerSocketChannel一样     try {       //最终会执行最终会执行自己写的ChannelInitializer的handlerAdded方法,       //再执行initChannel方法,将自己写的handler添加到pipeline中,然后调用removeState移除自己写的ChannelInitializer       //此时NioSocketChannel的pipeline有 头、自己写的handler、尾         childGroup.register(child).addListener(new ChannelFutureListener() {             @Override             public void operationComplete(ChannelFuture future) throws Exception {                 if (!future.isSuccess()) {                     forceClose(child, future.cause());                 }             }         });     } catch (Throwable t) {         forceClose(child, t);     } }Netty客户端写数据到服务端事件
  Netty的客户端启动时会连接服务端的端口,当发生客户端写数据事件时(对服务端来说是读事件)调用NioByteUnsafe的read方法,源码如下:public final void read() {         final ChannelConfig config = config();         if (shouldBreakReadReady(config)) {             clearReadPending();             return;         }         final ChannelPipeline pipeline = pipeline();         final ByteBufAllocator allocator = config.getAllocator();         final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();         allocHandle.reset(config);          ByteBuf byteBuf = null;         boolean close = false;         try {             do {                 byteBuf = allocHandle.allocate(allocator);                 allocHandle.lastBytesRead(doReadBytes(byteBuf));                 if (allocHandle.lastBytesRead() <= 0) {                     byteBuf.release();                     byteBuf = null;                     close = allocHandle.lastBytesRead() < 0;                     if (close) {                         readPending = false;                     }                     break;                 }                  allocHandle.incMessagesRead(1);                 readPending = false;                 pipeline.fireChannelRead(byteBuf);//调用pipeline中所有handler的channelRead方法,即可以调用自己写的handler的方法了                 byteBuf = null;             } while (allocHandle.continueReading());              allocHandle.readComplete();             pipeline.fireChannelReadComplete();//调用pipeline中所有handler的channelReadComplete方法              if (close) {                 closeOnRead(pipeline);             }         } catch (Throwable t) {             handleReadException(pipeline, byteBuf, t, close, allocHandle);         } finally {             if (!readPending && !config.isAutoRead()) {                 removeReadOp();             }         }     } }Netty线程模型源码解析流程图
  Netty线程模型全流程图(包含服务端参数设置、服务端端口注册、客户端请求连接服务端、客户端写数据到服务端)如下链接:
  https://kdocs.cn/l/chTjGr8JajaI
三十九个最科学的长寿法如果你意识到长寿养生的重要性,却无从下手的话,博主推荐大家试试美国公布的40个简单易行的长寿法。1。唱歌瑞典研究者发现,唱歌能改善心脏状况。2。工作努力最新调查显示,工作努力负责的世乒赛大爆冷!男团7号种子惨败出局,世界冠军彻底放弃不上场北京时间10月3日,成都世乒赛爆出超大冷门,男团7号种子世界冠军庄智渊领衔的中国台北队13不敌新加坡,不光输掉了这场比赛,而且还因为在小组赛3连败而排名垫底根据规则,中国台北队已经马龙梁靖崑陈梦孙颖莎王楚钦林高远,他们为何这样配胶随着新材料球的到来,乒乓国手们由起初的正粘反涩,逐步向正反两面粘套靠拢。男有马龙梁靖崑两面狂飙3,女有孙颖莎两面狂虎虎生风,更有陈梦王楚钦反手用上了狂飙8系列,林高远则在反手位试用中国花滑女神秀出小蛮腰,香肩微露气质好,被15岁小将冲击体育出神颜,在体育界中,其中花样滑冰和艺术体操中,美女多多,漂亮的面孔纤细的身材和优雅的气质,都是两者的共同之处。特别是花样滑冰中,不仅需要容貌漂亮,还需要超高的技术。北京时间10继皮克出轨后,曝夏奇拉与卡西约会,卡西公开回应,给足皮克面子近一段时间以来,有关巴萨后防球星前西班牙国家队的后防大将皮克,和比自己大10岁的知名歌手夏奇拉之间的感情纠葛闹得是沸沸扬扬。这对当年在2010年世界杯前因为拍摄主题曲而相识的一对,恩比德成美国公民,法国最强双塔胎死腹中?北京时间9月30日,76人队球星恩比德透露,他已经正式成为一名美国公民,并称为此感到兴奋。在谈到对新赛季的期待时,恩比德直言自己已经不再看重竞争MVP。在谈到自己成为一名美国公民的马龙3比1逆转获胜,梁靖崑林高远首秀零封,国乒击败美国夺两连胜北京时间10月2日消息,2022年世界乒乓球团体锦标赛在成都展开第三日争夺。男团小组赛,马龙先丢一局后连赢三局,以3比1击败莱文斯基,梁靖崑和林高远首秀都以3比0获胜,中国队以3比哈兰德德比战一切皆有可能,希望让球迷感到自豪直播吧10月2日讯在曼市德比前,曼城前锋哈兰德在接受采访时表示,球队希望让球迷感到自豪。哈兰德这样谈道这对所有的球迷来说意义重大,作为一名球迷,我知道这一点。我们想让他们在周日感到中国女排负于巴西仍以小组第一进入第二阶段在昨天进行的2022世界女排锦标赛上,中国女排虽然在第一阶段小组赛最后一场比赛中1比3不敌巴西队,但仍以小组头名晋级16强。请听记者李嵬的报道面对实力强劲的巴西女排,中国队昨晚虽然一款秋冬披肩式保暖外套,简单的钩织(针法)温暖舒适中透着温婉十月金秋,天气渐渐入凉。也正是织友们置办温暖毛衣的忙碌时期。分享一款适合秋冬2季使用的披肩外套。简约大方的钩针(花样)温暖舒适中透着温婉,(样式)宽松休闲,很适合夜晚防寒保暖。样板科技与狠活?如何正确理解海克斯科技制作出来的食品?食品工业的发展,让我们现在的饮食变得丰富多彩,但也有很多人因此担心,科技的过多加入会不会对食品安全产生负面影响。最近,海克斯科技一词在饮食类相关博主的视频中被频繁引用,原本这个词源
队友希望内马尔继续为巴西队效力在巴西队在2022年世界杯早早被淘汰后,许多年轻的球员希望内马尔继续为巴西队做贡献。根据够力足球的说法,维尼修斯罗德里戈理查利森拉菲尼亚卢卡斯帕奎塔和安东尼6人是已经恳求内马尔继续英媒国际足联主席希望世界杯每三年办一次,已获亚非支持国际足联主席因凡蒂诺。(资料图)据英国地铁报等多家英媒12月19日报道,国际足联(FIFA)主席因凡蒂诺希望世界杯每三年举办一次,这一新计划已经得到了亚洲和非洲方面的支持。目前,因男足第二个亚洲先生,退役安置体育局的郑智级别年薪如何?在艰难的条件之下,郑智回归了广州男足,可是奈何的是郑智也没有三头六臂,作为老队长的他可以让这一支球队变得更加的团结,可是想让这一支球队变得强大,需要的因素有很多,而其中最重要的因素体操奥运冠军楼云当年与李宁齐名,退役后事业和婚姻怎样了?头条创作挑战赛点击关注,每天都有名人故事感动您!楼云上世纪80年代,楼云是与体操王子李宁齐名的体操运动员。他参加过1984年洛杉矶1988年汉城两届奥运会,连续夺得两枚体操跳马金牌德安东尼不香吗?曾经唯一跟勇士掰手腕的人,怎么没人看得上呢?德安东尼不香吗?曾经唯一跟勇士掰手腕的人,怎么没人看得上呢?以前禅师,德帅,波波,爵士老爷子,卡尔,小牛的那个教练疯狂的战术发明家,帕克莱利,阿德尔曼,大小范甘迪,现任步行者教练以库兹马29分比尔下半场25分,奇才胜太阳结束10连败奇才113110战胜太阳结束10连败。德文布克和波尔津吉斯缺阵。库兹马2记三分,比尔连突带传加福德两次吃饼,奇才147领先。艾顿篮下连进4球,克雷格快攻突破,补篮,太阳反超比分,首约基奇三双掘金力克灰熊升西部第一,莫兰特空砍3510掘金主场10591击败灰熊。掘金和灰熊掘金同为19胜11负,以交手优势升至西部第一。约基奇两次抛投,波普中距离,布朗三分,戈登补扣,掘金打出110!在约基奇的串联下,布朗戈登连连爆4个导致皮肤变黑的操作,你踩坑了吗?皮肤黑可能是天生的,也有可能是平时护肤不当导致的,下面四个导致皮肤变黑的操作,你踩坑了吗?快来自查吧!1。紫外线照射紫外线是诱发黑色素产生导致皮肤变黑主要原因。日晒之后角质层会变厚这些疾病一个比一个可怕,希望各位不要遇上随着年龄的增大,身边越来越多的人开始谈健康聊养生,朋友圈不经意就刷到熟悉的人分享出来的捐款链接。一场大病,不管是对于患病之人还是家庭都带来很大的经济压力。很多人觉得保险不重要,那可孙莉晒16岁女儿近况,黄多多穿吊带秀事业线,五官精致皮肤白皙12月21日,孙莉晒出女儿黄多多在家中做烘焙的视频,全程黄多多没有说话,却透露着优雅的气质,跟妈妈孙莉越来越像了,这气质越来越出尘了,引来无数网友的围观和热议。在视频中,黄多多身穿女性皮肤超好的总结头条创作挑战赛有没有特别羡慕那些与自己同龄,但皮肤巨好,又白又细嫩,脸上没有任何痘痘的女生,为什么别人的皮肤可以这么好!护肤其实也要讲究内调外养,女生皮肤超好的原因总结,事实也竟如