首页 文章 精选 留言 我的

精选列表

搜索[源码阅读],共10000篇文章
优秀的个人博客,低调大师

java源码-LinkedHashMap

开篇 LinkedHashMap是HashMap的变种,有一些额外的特性其中最重要的就是维护数据插入的有序性,这篇文章就是为了讲清楚LinkedHashMap的实现细节。 LinkedHashMap类图 LinkedHashMap类图 LinkedHashMap和HashMap的差别 LinkedHashMap可以认为是HashMap+LinkedList,即它既使用HashMap操作数据结构,又使用LinkedList维护插入元素的先后顺序。 LinkedHashMap除了维持Map的有序性质外,其他和HashMap是一模一样的, LinkedHashMap实现细节 从LinkedHashMap的类依赖图可以看出来,LinkedHashMap其实是继承自HashMap类,所以LinkedHashMap的所有接口基本上都是继承自己HashMap类,当然也存在一个非常核心的差别。 LinkedHashMap用于存储key/value的结果是继承自己HashMap的,但是LinkedHashMap本身维护着一个有序列表。 head是LinkedHashMap的列表头,tail是LinkedHashMap的列表尾,通过这两个变量保证了维护LinkedHashMap的插入顺序。 LinkedHashMap的Entry相比HashMap.Node对象增加了before和after两个变量,由于指向前后节点。 LinkedHashMap通过重写HashMap的newNode方法,创建Entry对象并在内部初始化了HashMap当中的Node节点。 在创建Entry的newNode过程中通过linkNodeLast()方法按照put顺序维持LinkHashMap的有序性。 public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> { static class Entry<K,V> extends HashMap.Node<K,V> { Entry<K,V> before, after; Entry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); } } // 保存HashMap有序列表的头 transient LinkedHashMap.Entry<K,V> head; // 保存HashMap有序列表的尾 transient LinkedHashMap.Entry<K,V> tail; final boolean accessOrder; private void linkNodeLast(LinkedHashMap.Entry<K,V> p) { LinkedHashMap.Entry<K,V> last = tail; tail = p; if (last == null) head = p; else { p.before = last; last.after = p; } } Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) { LinkedHashMap.Entry<K,V> p = new LinkedHashMap.Entry<K,V>(hash, key, value, e); linkNodeLast(p); return p; } private void linkNodeLast(LinkedHashMap.Entry<K,V> p) { LinkedHashMap.Entry<K,V> last = tail; tail = p; if (last == null) head = p; else { p.before = last; last.after = p; } } LinkedHashMap实际存储结构图 image.png 说明: 上述按照Entry1->Entry6的顺序进行存储的,不过这个图有些问题,正常的情况是head就是Entry1的对象,tail是Entry6的对象。 参考文章 图解LinkedHashMap原理

优秀的个人博客,低调大师

ButterKnife源码解析

ButterKnife(https://github.com/JakeWharton/butterknife)是一款android平台的依赖注入框架,通过该工具可以实现View、OnClickListener的注入,省去了findViewById、setOnClickListener的过程。使用方法如下: 通过@BindView注解实现findViewById的功能,完成View注入;通过@OnClick完成OnClickListener点击事件的注入,给ID对应的View设置点击事件和响应函数。关于注解的定义和解析可以参照这篇文章:Java注解。ButterKnife使用的就是编译时解析注解的技术,在编译时对注解进行解析,生成中间文件,在ButterKnife.bind时引用注解编译器生成的中间文件,完成依赖注入。 注解的定义 BindView注解定义 BindView注解定义中使用了元注解@Retention(CLASS)定义了该注解只保留到编译期间,运行时会丢弃;@Target(FIELD)表示该注解只能用在成员变量上面。 OnClick注解 OnClick注解中@Target(METHOD)表示该注解只能用于方法上; ListenerClass ListenerClass是一个@Target(ANNOTATION_TYPE)类型的注解,表示ListenerClass只能用在注解上;且@Retention(RUNTIME)表示该注解可以保留到JVM中,也就是运行时能够通过反射来获取。 注解的解析 下面对@BindView和@OnClick两种注解的解析进行讲解。编译时注解的解析: 编译时 Annotation 指 @Retention 为 CLASS 的 Annotation,由编译器自动解析。需要做的 a. 自定义类集成自 AbstractProcessor(编译器在编译时自动查找所有继承自 AbstractProcessor 的类,然后调用他们的 process 方法去处理) b. 重写其中的 process 函数 ButterKnife实现了ButterKnifeProcessor来进行编译时注解的解析: ButterKnifeProcessor ButterKnifeProcessor.process()函数如下: ButterKnifeProcessor.process process函数先调用findAndParseTargets生成bindingMap,然后通过binding.brewJava老生成Java文件。findAndParseTargets的实现如下(这里只关注@BindView和@OnClick): findAndParseTargets 其中调用parseBindView对注解为@BindView的Field进行解析;findAndParseListener对@OnClick之类的Listener注解进行解析。parseBindView代码如下: parseBindView parseBindView的主要工作是创建了BindingSet.Builder。getOrCreateBindingBuilder()如下: getOrCreateBindingBuilder getOrCreateBindingBuilder内部调用了BindingSet.newBuilder。 BindingSet.newBuilder newBuilder生成了Builder对象,Builder对象定义了生成的Java文件名、mView所属对象的类型等。Builder对象生产后,parseBindView就根据@BindView注解信息生成FieldViewBinding对象,之后调用了Builder.build()函数;@BindView的解析已经完成后,最后通过BindingSet.brewJava来生成中间文件。@BindView在生成文件对应了如下: addViewBinding 生成的中间文件如下所示: 中间文件 可以看到,中间文件里完成了对Target中成员变量的注入。 那么中间文件又是在什么时候被调用的呢?答案就是ButterKnife.bind(this) bind函数根据调用的类名查找其对应的className_ViewBinding的类名,然后反射调用其构造函数。 至此,ButterKnife的@BindView的运行流程就是这样。

优秀的个人博客,低调大师

gobblin 源码分析

最近,开始搞些大数据相关的内容,遇到的第一个问题,就是数据入库,小白刚入手,又不想写太多代码,于是从网上找,入库手段很多: DataX,Sqoop,以及Flume 等以及直接使用 Spark 进行入库,想了下当下的场景(不是简单的倒库,要从kafka拉,然后过滤些东西,在进入库里),后来发现了 linkedin 的 gobblin ,感觉很强大的,说是国内 JD 也在用... 进入正题.... 架构分析 如下图所示, 本人使用的是独立运行的单机程序,因此使用的 EmbeddedGobblin 来启动 Job ,顺着这条路一直缕到 Gobblin 内部运行机制: 架构类图 如上图所示,EmbededGobblin 作为 Gobblin 启动项,通过 Task 的方式将 Job 管理起来,如果存在多个不同的 Fork ,分别将数据进行复制,并传递到各个 Fork 中进行进一步的计算处理。 整个过程中主要可能涉及到的是 Converter 的配置, Watermark, Writer等相关内容的应用,通过结合 Watermark 与 Writer 配合,也能做到反馈当前写到哪里,方便当前程序停掉之后,下次启动时接着这次继续运行。

优秀的个人博客,低调大师

android datepicker源码

/* * Copyright (C) 2007 The Android Open Source Project * * 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 android.widget; import android.annotation.Widget; import android.content.Context; import android.content.res.TypedArray; import android.os.Parcel; import android.os.Parcelable; import android.text.format.DateFormat; import android.text.format.DateUtils; import android.util.AttributeSet; import android.util.SparseArray; import android.view.LayoutInflater; import android.widget.NumberPicker; import android.widget.NumberPicker.OnChangedListener; import com.android.internal.R; import java.text.DateFormatSymbols; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Locale; /** * A view for selecting a month / year / day based on a calendar like layout. * * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date Picker * tutorial</a>.</p> * * For a dialog using this view, see {@link android.app.DatePickerDialog}. */ @Widget public class DatePicker extends FrameLayout { private static final int DEFAULT_START_YEAR = 1900; private static final int DEFAULT_END_YEAR = 2100; // This ignores Undecimber, but we only support real Gregorian calendars. private static final int NUMBER_OF_MONTHS = 12; /* UI Components */ private final NumberPicker mDayPicker; private final NumberPicker mMonthPicker; private final NumberPicker mYearPicker; /** * How we notify users the date has changed. */ private OnDateChangedListener mOnDateChangedListener; private int mDay; private int mMonth; private int mYear; private Object mMonthUpdateLock = new Object(); private volatile Locale mMonthLocale; private String[] mShortMonths; /** * The callback used to indicate the user changes the date. */ public interface OnDateChangedListener { /** * @param view The view associated with this listener. * @param year The year that was set. * @param monthOfYear The month that was set (0-11) for compatibility * with {@link java.util.Calendar}. * @param dayOfMonth The day of the month that was set. */ void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth); } public DatePicker(Context context) { this(context, null); } public DatePicker(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DatePicker(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.date_picker, this, true); mDayPicker = (NumberPicker) findViewById(R.id.day); mDayPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); mDayPicker.setSpeed(100); mDayPicker.setOnChangeListener(new OnChangedListener() { public void onChanged(NumberPicker picker, int oldVal, int newVal) { mDay = newVal; notifyDateChanged(); } }); mMonthPicker = (NumberPicker) findViewById(R.id.month); mMonthPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); final String[] months = getShortMonths(); /* * If the user is in a locale where the month names are numeric, * use just the number instead of the "month" character for * consistency with the other fields. */ if (months[0].startsWith("1")) { for (int i = 0; i < months.length; i++) { months[i] = String.valueOf(i + 1); } mMonthPicker.setRange(1, NUMBER_OF_MONTHS); } else { mMonthPicker.setRange(1, NUMBER_OF_MONTHS, months); } mMonthPicker.setSpeed(200); mMonthPicker.setOnChangeListener(new OnChangedListener() { public void onChanged(NumberPicker picker, int oldVal, int newVal) { /* We display the month 1-12 but store it 0-11 so always * subtract by one to ensure our internal state is always 0-11 */ mMonth = newVal - 1; // Adjust max day of the month adjustMaxDay(); notifyDateChanged(); updateDaySpinner(); } }); mYearPicker = (NumberPicker) findViewById(R.id.year); mYearPicker.setSpeed(100); mYearPicker.setOnChangeListener(new OnChangedListener() { public void onChanged(NumberPicker picker, int oldVal, int newVal) { mYear = newVal; // Adjust max day for leap years if needed adjustMaxDay(); notifyDateChanged(); updateDaySpinner(); } }); // attributes TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker); int mStartYear = a.getInt(R.styleable.DatePicker_startYear, DEFAULT_START_YEAR); int mEndYear = a.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR); mYearPicker.setRange(mStartYear, mEndYear); a.recycle(); // initialize to current date Calendar cal = Calendar.getInstance(); init(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), null); // re-order the number pickers to match the current date format reorderPickers(months); if (!isEnabled()) { setEnabled(false); } } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); mDayPicker.setEnabled(enabled); mMonthPicker.setEnabled(enabled); mYearPicker.setEnabled(enabled); } private void reorderPickers(String[] months) { java.text.DateFormat format; String order; /* * If the user is in a locale where the medium date format is * still numeric (Japanese and Czech, for example), respect * the date format order setting. Otherwise, use the order * that the locale says is appropriate for a spelled-out date. */ if (months[0].startsWith("1")) { format = DateFormat.getDateFormat(getContext()); } else { format = DateFormat.getMediumDateFormat(getContext()); } if (format instanceof SimpleDateFormat) { order = ((SimpleDateFormat) format).toPattern(); } else { // Shouldn't happen, but just in case. order = new String(DateFormat.getDateFormatOrder(getContext())); } /* Remove the 3 pickers from their parent and then add them back in the * required order. */ LinearLayout parent = (LinearLayout) findViewById(R.id.parent); parent.removeAllViews(); boolean quoted = false; boolean didDay = false, didMonth = false, didYear = false; for (int i = 0; i < order.length(); i++) { char c = order.charAt(i); if (c == '\'') { quoted = !quoted; } if (!quoted) { if (c == DateFormat.DATE && !didDay) { parent.addView(mDayPicker); didDay = true; } else if ((c == DateFormat.MONTH || c == 'L') && !didMonth) { parent.addView(mMonthPicker); didMonth = true; } else if (c == DateFormat.YEAR && !didYear) { parent.addView (mYearPicker); didYear = true; } } } // Shouldn't happen, but just in case. if (!didMonth) { parent.addView(mMonthPicker); } if (!didDay) { parent.addView(mDayPicker); } if (!didYear) { parent.addView(mYearPicker); } } public void updateDate(int year, int monthOfYear, int dayOfMonth) { if (mYear != year || mMonth != monthOfYear || mDay != dayOfMonth) { mYear = year; mMonth = monthOfYear; mDay = dayOfMonth; updateSpinners(); reorderPickers(getShortMonths()); notifyDateChanged(); } } private String[] getShortMonths() { final Locale currentLocale = Locale.getDefault(); if (currentLocale.equals(mMonthLocale) && mShortMonths != null) { return mShortMonths; } else { synchronized (mMonthUpdateLock) { if (!currentLocale.equals(mMonthLocale)) { mShortMonths = new String[NUMBER_OF_MONTHS]; for (int i = 0; i < NUMBER_OF_MONTHS; i++) { mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i, DateUtils.LENGTH_MEDIUM); } mMonthLocale = currentLocale; } } return mShortMonths; } } private static class SavedState extends BaseSavedState { private final int mYear; private final int mMonth; private final int mDay; /** * Constructor called from {@link DatePicker#onSaveInstanceState()} */ private SavedState(Parcelable superState, int year, int month, int day) { super(superState); mYear = year; mMonth = month; mDay = day; } /** * Constructor called from {@link #CREATOR} */ private SavedState(Parcel in) { super(in); mYear = in.readInt(); mMonth = in.readInt(); mDay = in.readInt(); } public int getYear() { return mYear; } public int getMonth() { return mMonth; } public int getDay() { return mDay; } @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeInt(mYear); dest.writeInt(mMonth); dest.writeInt(mDay); } public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() { public SavedState createFromParcel(Parcel in) { return new SavedState(in); } public SavedState[] newArray(int size) { return new SavedState[size]; } }; } /** * Override so we are in complete control of save / restore for this widget. */ @Override protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { dispatchThawSelfOnly(container); } @Override protected Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); return new SavedState(superState, mYear, mMonth, mDay); } @Override protected void onRestoreInstanceState(Parcelable state) { SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); mYear = ss.getYear(); mMonth = ss.getMonth(); mDay = ss.getDay(); updateSpinners(); } /** * Initialize the state. * @param year The initial year. * @param monthOfYear The initial month. * @param dayOfMonth The initial day of the month. * @param onDateChangedListener How user is notified date is changed by user, can be null. */ public void init(int year, int monthOfYear, int dayOfMonth, OnDateChangedListener onDateChangedListener) { mYear = year; mMonth = monthOfYear; mDay = dayOfMonth; mOnDateChangedListener = onDateChangedListener; updateSpinners(); } private void updateSpinners() { updateDaySpinner(); mYearPicker.setCurrent(mYear); /* The month display uses 1-12 but our internal state stores it * 0-11 so add one when setting the display. */ mMonthPicker.setCurrent(mMonth + 1); } private void updateDaySpinner() { Calendar cal = Calendar.getInstance(); cal.set(mYear, mMonth, mDay); int max = cal.getActualMaximum(Calendar.DAY_OF_MONTH); mDayPicker.setRange(1, max); mDayPicker.setCurrent(mDay); } public int getYear() { return mYear; } public int getMonth() { return mMonth; } public int getDayOfMonth() { return mDay; } private void adjustMaxDay(){ Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, mYear); cal.set(Calendar.MONTH, mMonth); int max = cal.getActualMaximum(Calendar.DAY_OF_MONTH); if (mDay > max) { mDay = max; } } private void notifyDateChanged() { if (mOnDateChangedListener != null) { mOnDateChangedListener.onDateChanged(DatePicker.this, mYear, mMonth, mDay); } } } <?xml version="1.0" encoding="utf-8"?> <!-- ** ** Copyright 2007, The Android Open Source Project ** ** 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. */ --> <!-- Layout of date picker--> <!-- Warning: everything within the parent is removed and re-ordered depending on the date format selected by the user. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/parent" android:orientation="horizontal" android:layout_gravity="center_horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content"> <!-- Month --> <NumberPicker android:id="@+id/month" android:layout_width="80dip" android:layout_height="wrap_content" android:layout_marginLeft="1dip" android:layout_marginRight="1dip" android:focusable="true" android:focusableInTouchMode="true" /> <!-- Day --> <NumberPicker android:id="@+id/day" android:layout_width="80dip" android:layout_height="wrap_content" android:layout_marginLeft="1dip" android:layout_marginRight="1dip" android:focusable="true" android:focusableInTouchMode="true" /> <!-- Year --> <NumberPicker android:id="@+id/year" android:layout_width="95dip" android:layout_height="wrap_content" android:layout_marginLeft="1dip" android:layout_marginRight="1dip" android:focusable="true" android:focusableInTouchMode="true" /> </LinearLayout> 本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/4989988.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Elasticsearch安装-源码

安装Elasticsearch [root@test opt]#unzip elasticsearch-2.3.4.zip [root@test opt]# ll elasticsearch-2.3.4 总用量44 drwxr-xr-x. 2 root root 4096 6月 30 2016 bin drwxr-xr-x. 2 root root 4096 6月 30 2016 config drwxr-xr-x. 2 root root 4096 6月 30 2016 lib -rw-rw-r--. 1 root root 11358 6月 30 2016 LICENSE.txt drwxr-xr-x. 5 root root 4096 4月 18 22:44 modules -rw-rw-r--. 1 root root 150 6月 30 2016 NOTICE.txt -rw-rw-r--. 1 root root 8700 6月 30 2016 README.textile [root@test opt]# 创建Elasticsearch运行的普通账号 [root@test opt]# useradd elasticsearch 切换到elasticsearch普通账号 [root@test opt]# su - elasticsearch [elasticsearch@test ~]$ cd /opt/ 后台启动Elasticsearch [elasticsearch@test opt]$ ./elasticsearch-2.3.4/bin/elasticsearch -d 简单测试Elasticsearch [root@test ~]# curlhttp://127.0.0.1:9200 { "name" : "Interloper", "cluster_name" : "elasticsearch", "version" : { "number" : "2.3.4", "build_hash" : "e455fd0c13dceca8dbbdbb1665d068ae55dabe3f", "build_timestamp" : "2016-06-30T11:24:31Z", "build_snapshot" : false, "lucene_version" : "5.5.0" }, "tagline" : "You Know, for Search" } [root@test ~]# 成功! 本文转自 cexpert 51CTO博客,原文链接:http://blog.51cto.com/cexpert/1831980

优秀的个人博客,低调大师

Kibana安装-源码

安装kibana [root@test opt]# ll kibana-4.5.2-linux-x64.tar.gz -rw-r--r--. 1 root root 33321872 7月 14 12:04 kibana-4.5.2-linux-x64.tar.gz [root@test opt]#tar -xf kibana-4.5.2-linux-x64.tar.gz [root@test opt]# 链接kibana到elasticsearch [root@test opt]# vim./kibana-4.5.2-linux-x64/config/kibana.yml elasticsearch.url: "http://192.168.81.128:9200" 启动kibana [root@test opt]# ./kibana-4.5.2-linux-x64/bin/kibana 注:kibana启动默认会连本地的elasticsearch,http://localhost:9200/ 简单访问测试 在elasticsearch存在索引的情况下 注: kibana初始化,需要elasticsearch存在初始化的索引,否则kibana无法进行初始化setting Over !! 本文转自 cexpert 51CTO博客,原文链接:http://blog.51cto.com/cexpert/1832268

优秀的个人博客,低调大师

Logstash安装-源码

Logstash下载有点麻烦,由于国内到elk官网速度很慢,下载过程中容易中断。 所以,可以通过有断点续传的工具(迅雷)进行下载好,再进行安装使用。 系统环境: [root@test ~]# cat /etc/issue CentOS release 6.7 (Final) Kernel \r on an \m [root@test ~]# 安装基础环境 # yum install epel-release -y #yum install java-1.8.0-openjdk.x86_64 -y #yum installunzip-y 将下载好的包传到测试机里 [root@test opt]# ll 总用量143200 -rw-r--r--. 1 root root 27552007 7月 14 2016 elasticsearch-2.3.4.zip -rw-r--r--. 1 root root 33321872 7月 14 2016 kibana-4.5.2-linux-x64.tar.gz -rw-r--r--. 1 root root 85757162 7月 14 2016 logstash-2.3.4.zip [root@test opt]# 安装Logstash [root@test opt]# unzip logstash-2.3.4.zip [root@test opt]# ll logstash-2.3.4 总用量156 drwxr-xr-x. 2 root root 4096 4月 18 22:29 bin -rw-rw-r--. 1 root root 104936 7月 7 2016 CHANGELOG.md -rw-rw-r--. 1 root root 2249 7月 7 2016 CONTRIBUTORS -rw-rw-r--. 1 root root 3885 7月 7 2016 Gemfile -rw-rw-r--. 1 root root 21773 7月 7 2016 Gemfile.jruby-1.9.lock drwxr-xr-x. 4 root root 4096 4月 18 22:29 lib -rw-rw-r--. 1 root root 589 7月 7 2016 LICENSE -rw-rw-r--. 1 root root 149 7月 7 2016 NOTICE.TXT drwxr-xr-x. 4 root root 4096 4月 18 22:30 vendor [root@test opt]# 简单验证Logstash [root@test opt]#./logstash-2.3.4/bin/logstash -e 'input { stdin { } } output { stdout {} }' Settings: Default pipeline workers: 1 Pipeline main started Hello World! 2016-04-18T14:33:16.570Z 0.0.0.0 Hello World! ^CSIGINT received. Shutting down the agent. {:level=>:warn} stopping pipeline {:id=>"main"} Received shutdown signal, but pipeline is still waiting for in-flight events to be processed. Sending another ^C will force quit Logstash, but this may cause data loss. {:level=>:warn} Pipeline main has been shutdown [root@test opt]# 本文转自 cexpert 51CTO博客,原文链接:http://blog.51cto.com/cexpert/1831973

优秀的个人博客,低调大师

VasSonic源码解析

H5很重要,H5很重要,H5很重要,重要的事情要说三遍。VasSonic是腾讯开源的解决H5首屏渲染痛点的开源项目,本文通过解读代码来学习WebView的优化思路。 H5的优劣 H5的优势很明显,跨平台、迭代快、开发体验好。H5的劣势同样明显,加载慢,用户体验差。业内大牛想尽各种方法来弥补H5的劣势,初级使用缓存、预加载等常用方案,高级如Hybrid、ReactNative、Weex等H5的进阶解决方案。VasSonic专注于H5的秒开,使用的也是我们常见的性能优化方案。本文尝试了解VasSonic是如何用常见的手段将性能优化做到极致的。 VasSonic解决什么问题 关于WebView为什么打开慢、加载慢,业界已经有很多分析了,结论也是比较一致的,推荐美团点评技术团队的WebView性能、体验分析与优化,腾讯关于VasSonic的官方文

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册