第二十八章 springboot + zipkin(brave定制-AsyncHttpClient)

brave本身没有对AsyncHttpClient提供类似于brave-okhttp的ClientRequestInterceptor和ClientResponseInterceptor,所以需要我们定制,而ServerRequestInterceptor和ServerResponseInterceptor是在BraveServletFilter部分直接指定就好了(这在任何client技术下都可以复用)。

实际上,ClientRequestInterceptor和ClientResponseInterceptor也是我们的定制点

一、代码

基本参考第二十七章 springboot + zipkin(brave-okhttp实现)

1、service1

1.1、pom.xml

 1 <!-- zipkin brave -->
 2         <dependency>
 3             <groupId>io.zipkin.brave</groupId>
 4             <artifactId>brave-core</artifactId>
 5             <version>3.9.0</version>
 6         </dependency>
 7         <dependency>
 8             <groupId>io.zipkin.brave</groupId>
 9             <artifactId>brave-spancollector-http</artifactId>
10             <version>3.9.0</version>
11         </dependency>
12         <dependency>
13             <groupId>io.zipkin.brave</groupId>
14             <artifactId>brave-web-servlet-filter</artifactId>
15             <version>3.9.0</version>
16         </dependency>
17         <!-- async-http-client -->
18         <dependency>
19             <groupId>com.ning</groupId>
20             <artifactId>async-http-client</artifactId>
21             <version>1.9.31</version>
22         </dependency>

1.2、ZipkinConfig

 1 package com.xxx.service1.zipkin.brave.async;
 2
 3 import org.springframework.context.annotation.Bean;
 4 import org.springframework.context.annotation.Configuration;
 5
 6 import com.github.kristofa.brave.Brave;
 7 import com.github.kristofa.brave.EmptySpanCollectorMetricsHandler;
 8 import com.github.kristofa.brave.Sampler;
 9 import com.github.kristofa.brave.SpanCollector;
10 import com.github.kristofa.brave.http.DefaultSpanNameProvider;
11 import com.github.kristofa.brave.http.HttpSpanCollector;
12 import com.github.kristofa.brave.servlet.BraveServletFilter;
13 import com.ning.http.client.AsyncHttpClient;
14
15 @Configuration
16 public class ZipkinConfig {
17     @Bean
18     public SpanCollector spanCollector() {
19         HttpSpanCollector.Config spanConfig = HttpSpanCollector.Config.builder()
20                                               .compressionEnabled(false)//默认false,span在transport之前是否会被gzipped。
21                                               .connectTimeout(5000)//5s,默认10s
22                                               .flushInterval(1)//1s
23                                               .readTimeout(6000)//5s,默认60s
24                                               .build();
25         return HttpSpanCollector.create("http://localhost:9411",
26                                         spanConfig,
27                                         new EmptySpanCollectorMetricsHandler());
28     }
29
30     @Bean
31     public Brave brave(SpanCollector spanCollector) {
32         Brave.Builder builder = new Brave.Builder("asyn1 - service1 - 1");//指定serviceName
33         builder.spanCollector(spanCollector);
34         builder.traceSampler(Sampler.create(1));//采集率
35         return builder.build();
36     }
37
38     @Bean
39     public BraveServletFilter braveServletFilter(Brave brave) {
40         /**
41          * 设置sr、ss拦截器
42          */
43         return new BraveServletFilter(brave.serverRequestInterceptor(),
44                                       brave.serverResponseInterceptor(),
45                                       new DefaultSpanNameProvider());
46     }
47
48     @Bean
49     public AsyncHttpClient asyncHttpClient(){
50         return new AsyncHttpClient();
51     }
52 }

说明:指定了serviceName:"asyn1 - service1 - 1"

1.3、ZipkinAsyncController

 1 package com.xxx.service1.zipkin.brave.async;
 2
 3 import java.net.URI;
 4 import java.util.concurrent.Future;
 5
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.web.bind.annotation.RequestMapping;
 8 import org.springframework.web.bind.annotation.RequestMethod;
 9 import org.springframework.web.bind.annotation.RestController;
10
11 import com.github.kristofa.brave.Brave;
12 import com.github.kristofa.brave.http.DefaultSpanNameProvider;
13 import com.github.kristofa.brave.http.HttpClientRequest;
14 import com.github.kristofa.brave.http.HttpClientRequestAdapter;
15 import com.github.kristofa.brave.http.HttpClientResponseAdapter;
16 import com.github.kristofa.brave.http.HttpResponse;
17 import com.ning.http.client.AsyncHttpClient;
18 import com.ning.http.client.Request;
19 import com.ning.http.client.RequestBuilder;
20 import com.ning.http.client.Response;
21
22 import io.swagger.annotations.Api;
23 import io.swagger.annotations.ApiOperation;
24
25 @Api("zipkin brave async api")
26 @RestController
27 @RequestMapping("/zipkin/async/service1")
28 public class ZipkinAsyncController {
29
30     @Autowired
31     private AsyncHttpClient asyncHttpClient;
32     @Autowired
33     private Brave           brave;
34
35     @ApiOperation("trace第一步")
36     @RequestMapping(value = "/test1", method = RequestMethod.GET)
37     public String myboot() {
38
39         try {
40             RequestBuilder builder = new RequestBuilder();
41             String url = "http://localhost:8032/zipkin/async/service2/test2";
42             builder.setUrl(url);
43             Request request = builder.build();
44
45             clientRequestInterceptor(request);
46             Future<Response> response = asyncHttpClient.executeRequest(request);
47             clientResponseInterceptor(response.get());
48
49             return response.get().getResponseBody();
50         } catch (Exception e) {
51             e.printStackTrace();
52             return "";
53         }
54     }
55
56     private void clientRequestInterceptor(Request request) {
57         brave.clientRequestInterceptor().handle(new HttpClientRequestAdapter(new HttpClientRequest() {
58
59             @Override
60             public URI getUri() {
61                 return URI.create(request.getUrl());
62             }
63
64             @Override
65             public String getHttpMethod() {
66                 return request.getMethod();
67             }
68
69             @Override
70             public void addHeader(String headerKey, String headerValue) {
71                 request.getHeaders().add(headerKey, headerValue);
72             }
73         }, new DefaultSpanNameProvider()));
74     }
75
76     private void clientResponseInterceptor(Response response) {
77         brave.clientResponseInterceptor().handle(new HttpClientResponseAdapter(new HttpResponse() {
78             public int getHttpStatusCode() {
79                 return response.getStatusCode();
80             }
81         }));
82     }
83
84 }

说明:

  • clientRequestInterceptor(com.ning.http.client.Request request)

    • 其实就是在做cs
  • clientResponseInterceptor(com.ning.http.client.Response response)
    • 其实就是在做cr

2、service2

2.1、pom.xml

 1 <!-- zipkin brave -->
 2         <dependency>
 3             <groupId>io.zipkin.brave</groupId>
 4             <artifactId>brave-core</artifactId>
 5             <version>3.9.0</version>
 6         </dependency>
 7         <dependency>
 8             <groupId>io.zipkin.brave</groupId>
 9             <artifactId>brave-spancollector-http</artifactId>
10             <version>3.9.0</version>
11         </dependency>
12         <dependency>
13             <groupId>io.zipkin.brave</groupId>
14             <artifactId>brave-web-servlet-filter</artifactId>
15             <version>3.9.0</version>
16         </dependency>
17         <!-- async-http-client -->
18         <dependency>
19             <groupId>com.ning</groupId>
20             <artifactId>async-http-client</artifactId>
21             <version>1.9.31</version>
22         </dependency>

2.2、ZipkinConfig

 1 package com.xxx.service1.zipkin.brave.async;
 2
 3 import org.springframework.context.annotation.Bean;
 4 import org.springframework.context.annotation.Configuration;
 5
 6 import com.github.kristofa.brave.Brave;
 7 import com.github.kristofa.brave.EmptySpanCollectorMetricsHandler;
 8 import com.github.kristofa.brave.Sampler;
 9 import com.github.kristofa.brave.SpanCollector;
10 import com.github.kristofa.brave.http.DefaultSpanNameProvider;
11 import com.github.kristofa.brave.http.HttpSpanCollector;
12 import com.github.kristofa.brave.servlet.BraveServletFilter;
13 import com.ning.http.client.AsyncHttpClient;
14
15 @Configuration
16 public class ZipkinConfig {
17     @Bean
18     public SpanCollector spanCollector() {
19         HttpSpanCollector.Config spanConfig = HttpSpanCollector.Config.builder()
20                                               .compressionEnabled(false)//默认false,span在transport之前是否会被gzipped。
21                                               .connectTimeout(5000)//5s,默认10s
22                                               .flushInterval(1)//1s
23                                               .readTimeout(6000)//5s,默认60s
24                                               .build();
25         return HttpSpanCollector.create("http://localhost:9411",
26                                         spanConfig,
27                                         new EmptySpanCollectorMetricsHandler());
28     }
29
30     @Bean
31     public Brave brave(SpanCollector spanCollector) {
32         Brave.Builder builder = new Brave.Builder("asyn2 - service2 - 2");//指定serviceName
33         builder.spanCollector(spanCollector);
34         builder.traceSampler(Sampler.create(1));//采集率
35         return builder.build();
36     }
37
38     @Bean
39     public BraveServletFilter braveServletFilter(Brave brave) {
40         /**
41          * 设置sr、ss拦截器
42          */
43         return new BraveServletFilter(brave.serverRequestInterceptor(),
44                                       brave.serverResponseInterceptor(),
45                                       new DefaultSpanNameProvider());
46     }
47
48     @Bean
49     public AsyncHttpClient asyncHttpClient(){
50         return new AsyncHttpClient();
51     }
52 }

说明:指定了serviceName:"asyn2 - service2 - 2"

2.3、ZipkinAsyncController

 1 package com.xxx.service2.zipkin.brave.async;
 2
 3 import java.net.URI;
 4 import java.util.concurrent.Future;
 5
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.web.bind.annotation.RequestMapping;
 8 import org.springframework.web.bind.annotation.RequestMethod;
 9 import org.springframework.web.bind.annotation.RestController;
10
11 import com.github.kristofa.brave.Brave;
12 import com.github.kristofa.brave.http.DefaultSpanNameProvider;
13 import com.github.kristofa.brave.http.HttpClientRequest;
14 import com.github.kristofa.brave.http.HttpClientRequestAdapter;
15 import com.github.kristofa.brave.http.HttpClientResponseAdapter;
16 import com.github.kristofa.brave.http.HttpResponse;
17 import com.ning.http.client.AsyncHttpClient;
18 import com.ning.http.client.Request;
19 import com.ning.http.client.RequestBuilder;
20 import com.ning.http.client.Response;
21
22 import io.swagger.annotations.Api;
23 import io.swagger.annotations.ApiOperation;
24
25 @Api("zipkin brave async api")
26 @RestController
27 @RequestMapping("/zipkin/async/service2")
28 public class ZipkinAsyncController {
29
30     @Autowired
31     private AsyncHttpClient asyncHttpClient;
32     @Autowired
33     private Brave           brave;
34
35     @ApiOperation("trace第2步")
36     @RequestMapping(value = "/test2", method = RequestMethod.GET)
37     public String myboot2() {
38
39         try {
40             /*****************************serivce3*******************************/
41             RequestBuilder builder3 = new RequestBuilder();
42             String url3 = "http://localhost:8033/zipkin/async/service3/test3";
43             builder3.setUrl(url3);
44             Request request3 = builder3.build();
45
46             clientRequestInterceptor(request3);
47             Future<Response> response3 = asyncHttpClient.executeRequest(request3);
48             clientResponseInterceptor(response3.get());
49
50             /*****************************serivce4*******************************/
51             RequestBuilder builder4 = new RequestBuilder();
52             String url4 = "http://localhost:8034/zipkin/async/service4/test4";
53             builder4.setUrl(url4);
54             Request request4 = builder4.build();
55
56             clientRequestInterceptor(request4);
57             Future<Response> response4 = asyncHttpClient.executeRequest(request4);
58             clientResponseInterceptor(response4.get());
59
60             return response3.get().getResponseBody() + "=====" + response4.get().getResponseBody();
61         } catch (Exception e) {
62             e.printStackTrace();
63             return "";
64         }
65     }
66
67     private void clientRequestInterceptor(Request request) {
68         brave.clientRequestInterceptor().handle(new HttpClientRequestAdapter(new HttpClientRequest() {
69
70             @Override
71             public URI getUri() {
72                 return URI.create(request.getUrl());
73             }
74
75             @Override
76             public String getHttpMethod() {
77                 return request.getMethod();
78             }
79
80             @Override
81             public void addHeader(String headerKey, String headerValue) {
82                 request.getHeaders().add(headerKey, headerValue);
83             }
84         }, new DefaultSpanNameProvider()));
85     }
86
87     private void clientResponseInterceptor(Response response) {
88         brave.clientResponseInterceptor().handle(new HttpClientResponseAdapter(new HttpResponse() {
89             public int getHttpStatusCode() {
90                 return response.getStatusCode();
91             }
92         }));
93     }
94
95 }

3、service3

3.1、pom.xml

 1 <!-- zipkin brave -->
 2         <dependency>
 3             <groupId>io.zipkin.brave</groupId>
 4             <artifactId>brave-core</artifactId>
 5             <version>3.9.0</version>
 6         </dependency>
 7         <dependency>
 8             <groupId>io.zipkin.brave</groupId>
 9             <artifactId>brave-spancollector-http</artifactId>
10             <version>3.9.0</version>
11         </dependency>
12         <dependency>
13             <groupId>io.zipkin.brave</groupId>
14             <artifactId>brave-web-servlet-filter</artifactId>
15             <version>3.9.0</version>
16         </dependency>

3.2、ZipkinConfig

 1 package com.xxx.service3.zipkin.brave.async;
 2
 3 import org.springframework.context.annotation.Bean;
 4 import org.springframework.context.annotation.Configuration;
 5
 6 import com.github.kristofa.brave.Brave;
 7 import com.github.kristofa.brave.EmptySpanCollectorMetricsHandler;
 8 import com.github.kristofa.brave.Sampler;
 9 import com.github.kristofa.brave.SpanCollector;
10 import com.github.kristofa.brave.http.DefaultSpanNameProvider;
11 import com.github.kristofa.brave.http.HttpSpanCollector;
12 import com.github.kristofa.brave.servlet.BraveServletFilter;
13
14 @Configuration
15 public class ZipkinConfig {
16     @Bean
17     public SpanCollector spanCollector() {
18         HttpSpanCollector.Config spanConfig = HttpSpanCollector.Config.builder()
19                                               .compressionEnabled(false)//默认false,span在transport之前是否会被gzipped。
20                                               .connectTimeout(5000)//5s,默认10s
21                                               .flushInterval(1)//1s
22                                               .readTimeout(6000)//5s,默认60s
23                                               .build();
24         return HttpSpanCollector.create("http://localhost:9411",
25                                         spanConfig,
26                                         new EmptySpanCollectorMetricsHandler());
27     }
28
29     @Bean
30     public Brave brave(SpanCollector spanCollector) {
31         Brave.Builder builder = new Brave.Builder("asyn3 - service3 - 3");//指定serviceName
32         builder.spanCollector(spanCollector);
33         builder.traceSampler(Sampler.create(1));//采集率
34         return builder.build();
35     }
36
37     @Bean
38     public BraveServletFilter braveServletFilter(Brave brave) {
39         /**
40          * 设置sr、ss拦截器
41          */
42         return new BraveServletFilter(brave.serverRequestInterceptor(),
43                                       brave.serverResponseInterceptor(),
44                                       new DefaultSpanNameProvider());
45     }
46 }

说明:指定了serviceName:"asyn3 - service3 - 3"

3.3、ZipkinAsyncController

 1 package com.xxx.service3.zipkin.brave.async;
 2
 3 import org.springframework.web.bind.annotation.RequestMapping;
 4 import org.springframework.web.bind.annotation.RequestMethod;
 5 import org.springframework.web.bind.annotation.RestController;
 6
 7 import io.swagger.annotations.Api;
 8 import io.swagger.annotations.ApiOperation;
 9
10 @Api("zipkin brave async api")
11 @RestController
12 @RequestMapping("/zipkin/async/service3")
13 public class ZipkinAsyncController {
14
15     @ApiOperation("trace第3步")
16     @RequestMapping(value = "/test3", method = RequestMethod.GET)
17     public String myboot3() {
18
19         try {
20             return "async - service3";
21         } catch (Exception e) {
22             e.printStackTrace();
23             return "";
24         }
25     }
26
27 }

4、service4

4.1、pom.xml

 1 <!-- zipkin brave -->
 2         <dependency>
 3             <groupId>io.zipkin.brave</groupId>
 4             <artifactId>brave-core</artifactId>
 5             <version>3.9.0</version>
 6         </dependency>
 7         <dependency>
 8             <groupId>io.zipkin.brave</groupId>
 9             <artifactId>brave-spancollector-http</artifactId>
10             <version>3.9.0</version>
11         </dependency>
12         <dependency>
13             <groupId>io.zipkin.brave</groupId>
14             <artifactId>brave-web-servlet-filter</artifactId>
15             <version>3.9.0</version>
16         </dependency>

4.2、ZipkinConfig

 1 package com.xxx.service4.zipkin.brave.async;
 2
 3 import org.springframework.context.annotation.Bean;
 4 import org.springframework.context.annotation.Configuration;
 5
 6 import com.github.kristofa.brave.Brave;
 7 import com.github.kristofa.brave.EmptySpanCollectorMetricsHandler;
 8 import com.github.kristofa.brave.Sampler;
 9 import com.github.kristofa.brave.SpanCollector;
10 import com.github.kristofa.brave.http.DefaultSpanNameProvider;
11 import com.github.kristofa.brave.http.HttpSpanCollector;
12 import com.github.kristofa.brave.servlet.BraveServletFilter;
13
14 @Configuration
15 public class ZipkinConfig {
16     @Bean
17     public SpanCollector spanCollector() {
18         HttpSpanCollector.Config spanConfig = HttpSpanCollector.Config.builder()
19                                               .compressionEnabled(false)//默认false,span在transport之前是否会被gzipped。
20                                               .connectTimeout(5000)//5s,默认10s
21                                               .flushInterval(1)//1s
22                                               .readTimeout(6000)//5s,默认60s
23                                               .build();
24         return HttpSpanCollector.create("http://localhost:9411",
25                                         spanConfig,
26                                         new EmptySpanCollectorMetricsHandler());
27     }
28
29     @Bean
30     public Brave brave(SpanCollector spanCollector) {
31         Brave.Builder builder = new Brave.Builder("asyn4 - service4 - 4");//指定serviceName
32         builder.spanCollector(spanCollector);
33         builder.traceSampler(Sampler.create(1));//采集率
34         return builder.build();
35     }
36
37     @Bean
38     public BraveServletFilter braveServletFilter(Brave brave) {
39         /**
40          * 设置sr、ss拦截器
41          */
42         return new BraveServletFilter(brave.serverRequestInterceptor(),
43                                       brave.serverResponseInterceptor(),
44                                       new DefaultSpanNameProvider());
45     }
46
47 }

说明:指定了serviceName:"asyn4 - service4 - 4"

4.3、ZipkinAsyncController

 1 package com.xxx.service4.zipkin.brave.async;
 2
 3 import org.springframework.web.bind.annotation.RequestMapping;
 4 import org.springframework.web.bind.annotation.RequestMethod;
 5 import org.springframework.web.bind.annotation.RestController;
 6
 7 import io.swagger.annotations.Api;
 8 import io.swagger.annotations.ApiOperation;
 9
10 @Api("zipkin brave async api")
11 @RestController
12 @RequestMapping("/zipkin/async/service4")
13 public class ZipkinAsyncController {
14
15     @ApiOperation("trace第4步")
16     @RequestMapping(value = "/test4", method = RequestMethod.GET)
17     public String myboot3() {
18
19         try {
20             return "async - service4";
21         } catch (Exception e) {
22             e.printStackTrace();
23             return "";
24         }
25     }
26
27 }

二、测试结果

1、依赖关系图:

2、span时间消耗图

3、详情图

点击第4个span,查看详情:

时间: 2024-08-02 06:50:47

第二十八章 springboot + zipkin(brave定制-AsyncHttpClient)的相关文章

Gradle 1.12用户指南翻译——第二十八章. Jetty 插件

其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://github.com/msdx/gradledoc/tree/1.12. 直接浏览双语版的文档请访问: http://gradledoc.qiniudn.com/1.12/userguide/userguide.html. 另外,Android 手机用户可通过我写的一个程序浏览文档,带缓存功能的,目前

“全栈2019”Java第二十八章:数组详解(上篇)

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第二十八章:数组详解(上篇) 下一章 "全栈2019"Java第二十九章:数组详解(中篇) 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学习小组"

“全栈2019”Java多线程第二十八章:公平锁与非公平锁详解

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多线程第二十八章:公平锁与非公平锁详解 下一章 "全栈2019"Java多线程第二十九章:可重入锁与不可重入锁详解 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"J

幻源境第二十八章

不知过了多久,静静站立的孑微微叹了口气,转身走回了自己的居处-- 就在其刚刚步入房门,其身后白光一闪而逝. 孑停止了脚步,转过了身. 只见一老翁和一女子现于小院之中,那正是空老和尚樱. 看着眼前出现的两人,孑淡淡的扫视了一下他们,继而转身继续向屋内步去. 这让身后两人皆是眼神一闪. "孑,不问为什么吗?"尚樱开口问道. 步行中的孑停了下来,淡淡道:"何必要问,既然来了,你们自然会说." 说完孑缓缓的步入到了屋内. 之外的空老和尚樱见了,互相看了看,也是起步走了进去.

【WPF学习】第二十八章 程序集资源

原文:[WPF学习]第二十八章 程序集资源 WPF应用程序中的程序集资源与其他.NET应用程序中的程序集资源在本质上是相同的.基本概念是为项目添加文件,从而Visual studio可将其嵌入到编译过的应用程序的EXE或DLL文件中.WPF程序集资源与其他应用程序中的程序集资源之间的重要区别是引用他们的寻址系统不同. 在前面章节已讨论过程序集资源的工作原理.因为每次编译应用程序时,项目中的每个XAML文件都转换为解析效率更高的BAML文件.这些BAML文件作为独立资源嵌入到程序集中.添加自己的资

C#高级编程第11版 - 第二十八章

导航 C# 全版本特性一览 全书目录 第二十八章 Testing 28.1 概述 678 28.2 使用MSTest 进行单元测试 679 28.2.1 使用MSTest 创建单元测试 679 28.2.2 运行单元测试 681 28.2.3 使用MSTest 预期异常 682 28.2.4 测试全部代码路径 683 28.2.5 外部依赖 683 28.3 使用xUnit 进行单元测试 685 28.3.1 使用xUnit 和.NET Core 686 28.3.2 创建Fact 属性 686

第二十七章 springboot + zipkin(brave-okhttp实现)

本文截取自:http://blog.csdn.net/liaokailin/article/details/52077620 一.前提 1.zipkin基本知识:附8 zipkin 2.启动zipkin server: 2.1.在官网下载服务jar,http://zipkin.io/pages/quickstart.html,之后使用命令启动服务jar即可. nohup java -jar zipkin-server-1.5.1-exec.jar & 之后,查看与该jar同目录下的nohup.o

第十八章 springboot + thymeleaf

代码结构: 1.ThymeleafController 1 package com.xxx.firstboot.web; 2 3 import org.springframework.stereotype.Controller; 4 import org.springframework.ui.Model; 5 import org.springframework.web.bind.annotation.RequestMapping; 6 import org.springframework.we

奋斗吧,程序员——第二十八章 叹年来踪迹,何事苦淹留

二十五岁看十八岁时候朦胧的感情,自是感觉可笑.但如果三十岁回头看看二十五岁的感情依然可笑的话,那未免让人失望. 可二十五岁那年我的的确确是相信着爱这个字眼的. 我只是在漫长的岁月里等待一种表达. 既是在等你,也是等我自己. 我在等自己变得更出色,而这一天有多远我并不知晓. 事实上我认为爱有很多种表达方式,绝非语言. 大爱无言,大言稀声. 真爱大体如此             --2007冬.elber 那天晚上我们聊了很多. 大体上,双方就"爱情"这个共同话题进行了友好磋商,小涵表示要