首页 文章 精选 留言 我的

精选列表

搜索[全栈管理],共10000篇文章
优秀的个人博客,低调大师

Android DataBinding 实战全解

2015年的Google IO大会上,Android 团队发布了一个数据绑定框架(Data Binding Library),官方原生支持 MVVM 模型。数据绑定的概念并不陌生,Web开发中已经很是普遍,因此DataBinding或多或少地都借鉴了Web端开成熟的经验,其语法与使用方式都和JSP中的EL表达式非常类似。经过不断地强化,到了2016年,DataBinding已经可以支持数据双向绑定。 1. DataBinding简介 DataBinding解决了Android UI 编程的一个痛点,其主要优势在于: 对于MVVM的支持:官方原生支持 MVVM 模型可以让我们在不改变既有代码框架的前提下,非常容易地使用这些新特性。 提高开发效率: 去掉Acitivity和Fragments中更新UI数据的代码,让业务逻辑和UI代码分离; XML成为UI数据的唯一真实来源; 减少定义view id 和使用findViewById(); 性能高、功能强: 充分考虑了性能因素,高效的绑定和更新数据; 更安全,在编译时会发现由于错误的ID而引起的Errors; 保证代码在主线程经常; 在DataBinding推出之前,市面上已经有类似的第三方库在被使用,比如: ButterKnife; Android Annotations; RoboBinding; DataBinding让这些依赖注入框架会慢慢地失去市场,因为在 Java代码中直接使用View变量的情况会越来越少。 但是DataBinding毕竟还在发展阶段,有些地方还值得完善: IDE的支持不足善:虽然DataBinding是Google亲生的,但是Android Studio中的支持还不是不尽如人意,尤其是在XML文件中代码提示有待加强; 报错信息不直接:这个是老生常谈的问题,虽然DataBinding在编译时能发现数据绑定的错误,但是报错信息往往不直观,需要用户在很多错误信息中自己去找错误点。 没有重构的支持:这可以说是所有数据绑定框架都会面临的问题,因为数据的绑定都是在XML中,一旦用户需要继承原来的代码,就压面临这将所有数据绑定代码重新编写。 2. DataBinding的基本使用 准备工作 确保Android stuido的版本一定要大于1.3。 Android的Gradle插件版本不低于 1.5.0-alpha1: classpath 'com.android.tools.build:gradle:1.5.0' 然后修改对应模块(Module)的 build.grade: android { .... dataBinding { enabled = true } } 工程创建完成后,我们通过一个最简单的例子来说明 Data Binding 的基本用法。 布局文件 使用DataBinding之后,xml的布局文件就不再用于单纯地展示UI元素,还需要定义UI元素用到的变量。所以,它的根节点不再是一个 ViewGroup,而是变成了layout,并且新增了一个节点data,用来定义绑定的数据。 <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <!--添加要绑定的数据--> </data> <!--下面的布局文件就是原先的根节点(Root Element)--> <LinearLayout> .... </LinearLayout> </layout> data节点的作用就像一个桥梁,Activity中将data需要数据传入,XML定义data数据绑定的位置,搭建了 View 和 Model 之间的通路,也就是实现MVVM的ViewModel。 下面说明下如何在XML定义data节点:我们先在 xml 布局文件的data节点中声明variable节点,这个节点将会定义变量的名称、类型,为UI元素提供数据(例如将String绑定到TextView的android:text属性上)。 <data> <!--java.lang.*包是自动导入的不需要你再次的导入--> <!--当出现了import相同的类名的时候需要为其指定外号alias加以区分--> <import type="com.example.administrator.databindingdemo.Student"/> <import type="com.example.administrator.databindingdemo.MainActivity.Presenter"/> <variable name="student" type="Student"/> <variable name="presenter" type="Presenter"/> <variable name="visibility" type="Boolean"/> </data> 其中Presenter类时用来绑定方法的类,我们稍后再说;Student类是我们定义的一个类,用来呈现数据,其定义如下: public class Student extends BaseObservable{ private String firstName; private String lastName; public void setFirstName(String firstName) { this.firstName = firstName; //提示该属性刷新了 notifyPropertyChanged(BR.firstName); //提示所有的属性都刷新 //notifyAll(); } //注解来提示Binding生成这个字段 @Bindable public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; notifyPropertyChanged(BR.lastName); } @Bindable public String getFirstName() { return firstName; } public Student(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } @Override public String toString() { return "Student{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '}'; } } Studnet类继承了BaseObservable,这个是数据更新时所需要的,我们稍后在再来讨论。 当我们设置DataBinding生效后,如果一个xml文件的被如上这般设置了Data节点,编译器就会自动生成一个继承自 ViewDataBinding 的类(build 目录下)。其命名规则也是固定的:如果 xml 的文件名叫 activity_main.xml,那么生成的类就是 ActivityMainBinding。 绑定数据变量 下面需要修改MainActivity的onCreate方法,用 DatabindingUtil.setContentView()来替换掉setContentView(),然后创建一个Student对象,通过mBinding.setStudent(mStudent)与 variable 进行绑定。 Student mStudent = new Student("guo","chengqian"); private ActivityMainBinding mBinding; Boolean visiblity = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBinding = DataBindingUtil.setContentView(this,R.layout.activity_main); //绑定变量 mBinding.setStudent(mStudent); mBinding.setPresenter(new Presenter()); mBinding.setVisibility(visiblity); } ActivityMainBinding类中所有的set方法是根据variable名称生成的。我们在XML文件中定义了三个变量,所以会生成三个set方法。 在XML中使用变量 当数据传入ViewDataBinding与Variable绑定之后,xml的UI元素就可以直接使用了。 <TextView android:id="@+id/textView1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{student.firstName}" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="@{visibility?View.VISIBLE:View.GONE}" android:text="@{student.lastName}" /> 直接在对应属性上@{variable}就可以使用该变量的值以及对应的属性。 现在运行程序,就会看到我们传入Student的姓名已经显示出来了 1500001896236.png 3. 事件方法绑定 仅仅是在UI上绑定数据还远远不够,UI上的响应事件也需要被处理,因此需要要把响应事件的方法绑定到View上。 事件方法的绑定有两种方法:第一种是方法引用,这种方法要求函数的参数个数,类型以及顺序都会原生的事件方法相同;第二种方法是使用lambda表达式,这种方法更为灵活,可以自定义参数。 我们来看下例子: 这是一个方法类的实现,之前在xml的data节点中已经声明了变量,在Activity中也进行了绑定。 //方法类 public class Presenter{ //方法引用 参数要求符合接口定义 public void onTextChanged(CharSequence s, int start, int before, int count){ mStudent.setFirstName(s.toString()); //如果已经为该类继承了BaseObservable 就不需要再赋值了; //mBinding.setStudent(mStudent); } //方法引用,参数要求符合接口定义; public void onClick(View view){ Toast.makeText(MainActivity.this,"onClick!",Toast.LENGTH_SHORT).show(); } //自定义方法 public void onClickListenerBinding(Student student){ Toast.makeText(MainActivity.this, student.getLastName(),Toast.LENGTH_SHORT).show(); } } 首先在EidtText控件中使用,将onTextChanged方法绑定。 <EditText android:id="@+id/first_name_ed_txt" android:onTextChanged="@{presenter.onTextChanged}" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="First Name"/> 这样一旦输入的内容改变,变量student中对应的firstName属性也会跟着改变。 同样,我们将onClick方法绑定到一个TextView上 <TextView android:id="@+id/textView1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{student.firstName}" android:onClick="@{presenter.onClick}" /> 但是这种方法不够灵活,绑定的方法必须和View所要求的接口参数一致。为了更为灵活的绑定方法,还可以使用Lambda表达式。 <TextView android:id="@+id/textView2" android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="@{visibility?View.VISIBLE:View.GONE}" android:text="@{student.lastName}" android:onClick="@{()-> presenter.onClickListenerBinding(student)}"/> lambda表达式实际上也是创建了匿名函数,然后再这个匿名函数中调用了Presenter中的方法,只不过省去了匿名函数的申明,只保留最为核心的逻辑部分。 此外,lambd表达式支持传入Context参数,比如Presenter中定义这样的函数 public void onStudentLongClick(Student student, Context context){ Toast.makeText(LambdaActivity.this, "LongClick: "+student.toString(), Toast.LENGTH_SHORT).show(); } Button中可以这样调用,Context参数会被自动生成: <Button ...... android:longClickable="true" android:onClick="@{() -> presenter.onStudentLongClick(student,context)}" ...... /> 4. DataBinding所支持的表达式 为了扩展更为强大的功能,DataBinding在使用变量时支持一下表达式: 运算符:Mathematical + - / * % 字符串连接:String concatenation + 逻辑运算:Logical && || 位操作: Binary & | ^ Unary + - ! ~ 移位操作:Shift >> >>> << 比较操作:Comparison == > < >= <= 类型判断:instanceof Grouping () Literals - character, String, numeric, null 类型转化:Cast Method calls Field access Array access [] Ternary operator ?: 但不支持的表达式: this super new Explicit generic invocation Null Coalescing 运算符 DataBinding对于引用变量是否为空,也有特殊的支持,使用符号??。 android:text="@{student.firstName ??student.lastName}" 就等价于 android:text="@{student.firstName != null ? student.firstName : student.lastName}" 5. 在include文件里使用BataBinding 为了让Xml布局文件更为简洁易懂,对于重复使用的布局可以单独建立布局文件,然后使用include导入。DataBinding也考虑到了这种使用情况。可以使用bind:variable_name导入数据变量。 <!--当你使用include的时候,你可以使用命名空间和属性中的变量名将数据传送到另一个布局中去--> <include layout="@layout/include_show_name" bind:presenter="@{presenter}" bind:student="@{student}" bind:visibility="@{visibility}" /> 需要注意的是: 一定要使用app命名空间xmlns:app="http://schemas.android.com/apk/res-auto" 必须在ViewGroup的根布局中导入布局文件,如果在非根节点的ViewGroup中使用include会导致错误; 6. 在SubView中的使用 在SubView的使用方式和在Include中使用是类似的。 <ViewStub bind:visibility="@{visibility}" android:id="@+id/view_stub" android:layout_width="368dp" android:layout_height="wrap_content" android:layout="@layout/viewstub" /> 然后在Activity中通过DataBindingUtil获得SubView对象,然后填充View; //viewstub inflate; View inflate = mBinding.viewStub.getViewStub().inflate(); 7. 双向绑定 上面提的内容都是单向绑定,也就是把后台的数据绑定到前台显示出来。DataBinding如果只有如此功能,也不足为奇,最重要的功能点还是还在于双向绑定,前台显示的数据改变也会自动影响后台的数据。 首先我们新建一个数据对象类 public class FormModel extends BaseObservable { private String name; private String password; @Bindable //该注解表示数据绑定 public String getName() { return name; } public void setName(String name) { this.name = name; //通知name属性发生改变 notifyPropertyChanged(BR.name); } //注解标志该属性是绑定的 @Bindable public String getPassword() { return password; } public void setPassword(String password) { this.password = password; //通知有属性发生改变 notifyPropertyChanged(BR.password); } public FormModel(String name, String password) { this.name = name; this.password = password; } } 该类继承了BaseObservable,在getter方法之前使用@Bindable,标记该属性就是需要绑定的,会在BR类中生成对应的ID;在setter方法中notifyPropertyChanged(BR.ID),通知对应ID的属性发生了改变。 然后在XML中使用“@={variable}”表示数据绑定,如下。 <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <data> <variable name="model" type="com.example.administrator.databindingdemo.FormModel"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.administrator.databindingdemo.TowWayBindingActivity"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Name" android:text="@={model.name}"/> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="pwd" android:text="@={model.password}"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{model.name}"/> </LinearLayout> </layout> 最后在Activity中传入变量。 public class TowWayBindingActivity extends AppCompatActivity { ActivityTowWayBindingBinding mBinding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBinding = DataBindingUtil. setContentView(this,R.layout.activity_tow_way_binding); FormModel model = new FormModel("user", "12345"); mBinding.setModel(model); //属性改变监听器 model.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() { @Override public void onPropertyChanged(Observable sender, int propertyId) { if(BR.name == propertyId) Toast.makeText(TowWayBindingActivity.this, "姓名改变", Toast.LENGTH_SHORT).show(); } }); } } 这是运行程序就会发现,在前端输入姓名时,其他绑定name属性的地方也会改变,说明后台数据也响应改变了。 8. 表达式链与隐式更新 当多个View的属性相互关联式时,可以通过表达式链实现隐式更新,比如: <CheckBox android:id="@+id/check_box"/> <ImageView android:visibility="check_box.checked?View.VISIBILE:View.GONE"/> 9. 添加动画 数据绑定必然涉及到UI的变化,默认情况下往往都是很生硬的UI变化,没有任何过度。DataBinding也提供办法来插入动画。 实现方法也很简单,就是设置一个重新绑定时的回调函数addOnRebindCallback,在函数中设置当前View的UI变化时开启一定延时。 public class AnimationActivity extends AppCompatActivity { ActivityAnimationBinding mBinding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBinding = DataBindingUtil.setContentView(this,R.layout.activity_animation); mBinding.setPresenter(new AnimatorPresenter()); //设置重绑定回调函数 mBinding.addOnRebindCallback(new OnRebindCallback() { @Override public boolean onPreBind(ViewDataBinding binding) { ViewGroup viewGroup = (ViewGroup) binding.getRoot(); //开启延时位移动画 TransitionManager.beginDelayedTransition(viewGroup); return true; } }); } public class AnimatorPresenter{ public void onCheckedChanged(boolean isChecked){ mBinding.setShowImage(isChecked); } } } 在XML中正常使用DataBinding <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <data> <import type="android.view.View"/> <variable name="presenter" type="com.example.administrator.databindingdemo.AnimationActivity.AnimatorPresenter"/> <variable name="showImage" type="Boolean"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.administrator.databindingdemo.AnimationActivity"> <ImageView android:contentDescription="Animation Show" android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/default_avatar" android:visibility="@{showImage?View.VISIBLE:View.GONE}"/> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="showImage" android:onCheckedChanged = "@{(v,isChecked)->presenter.onCheckedChanged(isChecked)}"/> </LinearLayout> </layout> 这样图片在显示或者出现的过程中都会添加一个CheckBox位移匀速渐变的动画效果。 需要说明的是,虽然布局文件中CheckBox原本并没有onCheckedChanged属性,但是CheckBox类有对应的属性,并且设有setOnCheckedChanged方法来设置该属性,所以也是可以进行绑定的。 按照惯例,给出Demo源码:https://github.com/sunrongxin7666 欢迎大家指正批评 需要说明的是,由于篇幅的限制,还有动态绑定和在RecyclerView中使用没有介绍,如果感兴趣请读者参考一下两篇文章,基于以上的内容,相信读者不会很难理解。Android DataBinding完全解析精通 Android Data Binding

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

hadoop 2.6全分布安装

环境:centos 6.6 + hadoop2.6 虚拟机:(vmware fusion 7.0.0) 虚拟机hostname / IP地址 master / 192.168.187.102 slave01 / 192.168.187.103 slave02 / 192.168.187.104 注:前三个步骤都是准备工作,如果已经完成,可直接进入步骤四 步骤一: 先在3台虚拟机上,设置hostname及修改hosts文件 1.1 先正确设置各虚拟机的hostname sudo vi /etc/sysconfig/network 将HOSTNAME=后的内容,改成想要的机器名 1.2 修改hosts文件 sudo vi /etc/hosts 192.168.187.102 master 192.168.187.103 slave01 192.168.187.104 slave02 这样,就不用记IP了 这一步完成后,最好重启一次系统,以便生效。然后可以用ping master(或slave01、slave02)试下,正常的话,应该能ping通 注:hostname不要命名为“xxx.01,xxx.02”之类以“.数字”结尾,否则到最后hadoop的NameNode服务将启动失败。 步骤二:在3台虚拟机上安装jdk yum install java 注:hadoop是java写的,jdk是必须的。上述命令,会安装openjdk最基本的运行时,没有源码和javac等其它工具。如果要安装javac等编译工具及源码 yum install java-1.7.0-openjdk-devel yum install java-1.7.0-openjdk-src 另外openjdk安装后,不会默许设置JAVA_HOME环境变量,要查看安装后的目录,可以用命令 sudo update-alternatives --config java 看到 默认jre目录为:/usr/lib/java/jvm/jre-1.7.0-openjdk.x86_64 如要设置环境变量,可用命令 sudo vi /etc/profile 在最后添加 export JAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.75.x86_64 export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/jre/lib/dt.jar:$JAVA_HOME/jre/lib/tools.jar export PATH=$PATH:$JAVA_HOME/bin 注:如果不喜欢openjdk,想安装oracle官方的jdk,可按下面步骤操作 a) rpm -qa | grep java 即:查看当前已经安装的跟java相关的包,如果显示有openjdk在其中 b) yum -y remove java 一般这样就会卸载干净,执行完以后,再运行 a)中的rpm -qa | grep java看看,如果还有残留,可运行 rpm -e --nodeps tzdata-java-2015a-1.el6.noarch (最后的部分为要删除的包名,即刚才查出来的结果) 重新安装sun jdk,先从官网下载安装文件 a) 上传rpm安装文件到虚拟机,参考下面的命令 scp jdk-7u51-linux-x64.rpm root@master:/home/hadoop/ b) 到虚拟机上,执行安装 rpm -ivh jdk-7u51-linux-x64.rpm c) 然后修改环境变量 sudo vi /etc/profile,在最后加下面三行 export JAVA_HOME=/usr/java/jdk1.7.0_51 export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export PATH=$PATH:$JAVA_HOME/bin 保存退出,然后输入 source /etc/profile 以便让新环境变量生效 注:如果机器上之前用 yum install hadoop之类的命令安装过低版本的hadoop,也必须先卸载干净 步骤三:在3台虚拟机上创建专门用户hadoop useradd hadoop (创建用户) passwd hadoop (设置密码,为简单起见,3台机器上的hadoop密码最好设置成一样,比如hadoop123) 为了方便,建议将hadoop加入root用户组,操作方法: 先以root身份登录,然后输入 usermod -g root hadoop ,执行完后hadoop即归属于root组了,可以再输入 id hadoop 查看输出验证一下,如果看到类似下面的输出: uid=502(hadoop) gid=0(root) 组=0(root) 就表示OK了 步骤四:配置ssh免密码登录 hadoop工作时,各节点要相互通讯,正常情况下linux之间通讯要提供用户名、密码(目的是保证通讯安全),如果需要人工干预输入密码,显然不方便,做这一步的目的,是让各节点能自动通过安全认证,不影响正常通讯。 4.1 先在master上,生成公钥、私钥对 以hadoop身份登录到系统 cd (进入个人主目录,默认为/home/hadoop) ssh-keygen -t rsa -P '' (注:最后是二个单引号) 即:以rsa算法,生成公钥、私钥对,-P ''表示空密码。该命令运行完后,会在个人主目录下生成.ssh目录,里面会有二个文件id_rsa(私钥) ,id_rsa.pub(公钥) 4.2 导入公钥 cat .ssh/id_rsa.pub >> .ssh/authorized_keys 执行完以后,可以在本机上测试下,用ssh连接自己,即:ssh localhost (或ssh master),如果不幸还是提示要输入密码,说明还没起作用,还有一个关键的操作 chmod 600 .ssh/authorized_keys (修改文件权限,否则不起作用) 然后再测试下 ssh localhost ,如果不需要输入密码,就连接成功,表示ok,一台机器已经搞定了。 4.3 在其它机器上生成公钥、密钥,并将公钥文件复制到master a) 以hadoop身份登录其它二台机器 slave01、slave02,执行 ssh-keygen -t rsa -P '' 生成公钥、密钥 b) 然后用scp命令,把公钥文件发放给master(即:刚才已经搞定的那台机器) slave01上: scp .ssh/id_rsa.pub hadoop@master:/home/hadoop/id_rsa_01.pub slave02上: scp .ssh/id_rsa.pub hadoop@master:/home/hadoop/id_rsa_02.pub 这二行执行完后,回到master中,查看下/home/hadoop目录,应该有二个新文件id_rsa_01.pub、id_rsa_02.pub,然后在master上,导入这二个公钥 cat id_rsa_01.pub >> .ssh/authorized_keys cat id_rsa_02.pub >> .ssh/authorized_keys 这样,master这台机器上,就有所有3台机器的公钥了。 4.4 将master上的“最全”公钥,复制到其它机器 a) 继续保持在master上, scp .ssh/authorized_keys hadoop@slave01:/home/hadoop/.ssh/authorized_keys scp .ssh/authorized_keys hadoop@slave02:/home/hadoop/.ssh/authorized_keys b) 修改其它机器上authorized_keys文件的权限 slave01以及slave02机器上,均执行命令 chmod 600 .ssh/authorized_keys 4.5 验证 在每个虚拟机上,均用 ssh 其它机器的hostname 验证下,如果能正常无密码连接成功,表示ok 小结:该步骤非常重要,主要思路是在各节点上生成公钥、私钥,然后将公钥发放其它所有节点。RSA算法是非对称加密算法,仅公布“公钥”,只要私钥不外泄,还是不能解密的,所以安全性依然有保障。 如果本步骤失败,根据我个人经验,多半是权限问题,请检查hadoop是否具有足够权限,建议将hadoop加入sudoers列表及root用户组。另外,这里也整理了一些SSH免密码设置失败的原因,请移步ssh 免密码设置失败原因总结 步骤五:上传并解压hadoop2.6 a)在本机上,用scp命令上传hadoop2.6到master scphadoop-2.6.0.tar.gz hadoop@master:/home/hadoop/ b) 以hadoop身份登录到master,运行以下命令解压 tar -zxvfhadoop-2.6.0.tar.gz 步骤六:修改配置 一共有7个文件要修改: $HADOOP_HOME/etc/hadoop/hadoop-env.sh $HADOOP_HOME/etc/hadoop/yarn-env.sh $HADOOP_HOME/etc/hadoop/core-site.xml $HADOOP_HOME/etc/hadoop/hdfs-site.xml $HADOOP_HOME/etc/hadoop/mapred-site.xml $HADOOP_HOME/etc/hadoop/yarn-site.xml $HADOOP_HOME/etc/hadoop/slaves 其中$HADOOP_HOME表示hadoop根目录,本文中默认为/home/hadoop/hadoop-2.6.0 a) hadoop-env.sh 、yarn-env.sh 这二个文件主要是修改JAVA_HOME后的目录,改成实际本机jdk所在目录位置 vi etc/hadoop/hadoop-env.sh (及 vi etc/hadoop/yarn-env.sh) 找到下面这行的位置,改成(jdk目录位置,大家根据实际情况修改) export JAVA_HOME=/usr/java/jdk1.7.0_51 另外 hadoop-env.sh中 , 建议加上这句: export HADOOP_PREFIX=/home/hadoop/hadoop-2.6.0 b) core-site.xml 参考下面的内容修改: 1 <?xml version="1.0" encoding="UTF-8"?> 2 <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> 3 <configuration> 4 <property> 5 <name>fs.defaultFS</name> 6 <value>hdfs://master:9000</value> 7 </property> 8 <property> 9 <name>hadoop.tmp.dir</name> 10 <value>/home/hadoop/tmp</value> 11 </property> 12 </configuration> 注:/home/hadoop/tmp 目录如不存在,则先mkdir手动创建 core-site.xml的完整参数请参考 http://hadoop.apache.org/docs/r2.6.0/hadoop-project-dist/hadoop-common/core-default.xml c) hdfs-site.xml 1 <?xml version="1.0" encoding="UTF-8"?> 2 <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> 3 <configuration> 4 <property> 5 <name>dfs.datanode.ipc.address</name> 6 <value>0.0.0.0:50020</value> 7 </property> 8 <property> 9 <name>dfs.datanode.http.address</name> 10 <value>0.0.0.0:50075</value> 11 </property> 12 <property> 13 <name>dfs.replication</name> 14 <value>2</value> 15 </property> 16 </configuration> 注:dfs.replication表示数据副本数,一般不大于datanode的节点数。 hdfs-site.xml的完整参数请参考 http://hadoop.apache.org/docs/r2.6.0/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml d)mapred-site.xml 1 <?xml version="1.0"?> 2 <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> 3 <configuration> 4 <property> 5 <name>mapreduce.framework.name</name> 6 <value>yarn</value> 7 </property> 8 </configuration> mapred-site.xml的完整参数请参考 http://hadoop.apache.org/docs/r2.6.0/hadoop-mapreduce-client/hadoop-mapreduce-client-core/mapred-default.xml e)yarn-site.xml 1 <?xml version="1.0"?> 2 <configuration> 3 <property> 4 <name>yarn.nodemanager.aux-services</name> 5 <value>mapreduce_shuffle</value> 6 </property> 7 </configuration> yarn-site.xml的完整参数请参考 http://hadoop.apache.org/docs/r2.6.0/hadoop-yarn/hadoop-yarn-common/yarn-default.xml 另外,hadoop 1.x与2.x相比, 1.x中的很多参数已经被标识为过时,具体可参考 http://hadoop.apache.org/docs/r2.6.0/hadoop-project-dist/hadoop-common/DeprecatedProperties.html 最后一个文件slaves暂时不管(可以先用mv slaves slaves.bak将它改名),上述配置弄好后,就可以在master上启用 NameNode测试了,方法: $HADOOP_HOME/bin/hdfs namenode –format 先格式化 15/02/12 21:29:53 INFO namenode.FSImage: Allocated new BlockPoolId: BP-85825581-192.168.187.102-1423747793784 15/02/12 21:29:53 INFO common.Storage: Storage directory /home/hadoop/tmp/dfs/name has been successfully formatted. 等看到这个时,表示格式化ok $HADOOP_HOME/sbin/start-dfs.sh 启动完成后,输入jps查看进程,如果看到以下二个进程: 5161 SecondaryNameNode 4989 NameNode 表示master节点基本ok了 再输入$HADOOP_HOME/sbin/start-yarn.sh ,完成后,再输入jps查看进程 5161 SecondaryNameNode 5320 ResourceManager 4989 NameNode 如果看到这3个进程,表示yarn也ok了 f) 修改slaves 如果刚才用mv slaves slaves.bak对该文件重命名过,先运行 mv slaves.bak slaves 把名字改回来,再 vi slaves 编辑该文件,输入 slave01 slave02 保存退出,最后运行 $HADOOP_HOME/sbin/stop-dfs.sh $HADOOP_HOME/sbin/stop-yarn.sh 停掉刚才启动的服务 步骤七:将master上的hadoop目录复制到slave01,slave02 仍然保持在master机器上 cd 先进入主目录 scp -r hadoop-2.6.0 hadoop@slave01:/home/hadoop/ scp -r hadoop-2.6.0 hadoop@slave02:/home/hadoop/ 注:slave01、slave02上的hadoop临时目录(tmp)及数据目录(data),仍然要先手动创建。 步骤八:验证 master节点上,重新启动 $HADOOP_HOME/sbin/start-dfs.sh $HADOOP_HOME/sbin/start-yarn.sh 顺利的话,master节点上有几下3个进程: 7482 ResourceManager 7335 SecondaryNameNode 7159 NameNode slave01、slave02上有几下2个进程: 2296 DataNode 2398 NodeManager 同时可浏览: http://master:50070/ http://master:8088/ 查看状态 另外也可以通过 bin/hdfs dfsadmin -report 查看hdfs的状态报告 其它注意事项: a) master(即:namenode节点)若要重新格式化,请先清空各datanode上的data目录(最好连tmp目录也一起清空),否则格式化完成后,启动dfs时,datanode会启动失败 b) 如果觉得master机器上只运行namenode比较浪费,想把master也当成一个datanode,直接在slaves文件里,添加一行master即可 c) 为了方便操作,可修改/etc/profile,把hadoop所需的lib目录,先加到CLASSPATH环境变量中,同时把hadoop/bin,hadoop/sbin目录也加入到PATH变量中,可参考下面的内容: export HADOOP_HOME=/home/hadoop/hadoop-2.6.0 export JAVA_HOME=/usr/java/jdk1.7.0_51 export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$HADOOP_HOME/share/hadoop/common/hadoop-common-2.6.0.jar:$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-client-core-2.6.0.jar:$HADOOP_HOME/share/hadoop/common/lib/commons-cli-1.2.jar export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/sbin:$HADOOP_HOME/bin 参考文档:Hadoop MapReduce Next Generation - Cluster Setup

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

Java + Python:混合技术栈的专业实践与代码实现

Java 与 Python 是两种在企业级系统中长期共存的语言:Java 以强类型、JVM 生态、高并发与企业级中间件见长;Python 以生态丰富、开发效率高、AI 与数据能力强大著称。在现代系统中,二者不是替代关系,而是分工关系:Java 承担交易、订单、风控、网关与企业级服务;Python 承担模型推理、数据分析、算法策略与科学计算。本文从互操作方式、架构设计、性能权衡、代码实战、部署与安全等角度,给出一套可落地的 Java + Python 混合开发方法,并附带可直接运行的 Java 与 Python 代码。

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

Go + Python:混合技术栈的专业实践与代码实现

Go 与 Python 是两种哲学迥异的语言:Go 追求简洁、并发、静态编译与部署效率;Python 追求表达力、生态丰富与快速迭代。在现代后端与 AI 系统中,二者并非竞争关系,而是天然互补。Go 适合构建高并发网关、编排层、基础设施与数据面;Python 适合模型推理、数据分析、算法策略与科学计算。本文从专业视角系统论述 Go + Python 混合架构的设计原则、互操作模式、性能权衡、部署与安全,并给出可直接运行的代码示例,涵盖 HTTP、gRPC、子进程与 cgo 四种集成方式。

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

微服务技术栈:流量整形算法,服务熔断与降级

云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 一、流量控制 1、基本概念流量控制的核心作用是限制流出某一网络的某一连接的流量与突发,使这类报文以比较均匀的速度流动发送,达到保护系统相对稳定的目的。通常是将请求放入缓冲区或队列内,然后基于特定策略处理请求,匀速或者批量处理,该过程也称流量整形。 流量控制的核心算法有以下两种:漏桶算法和令牌桶算法。 2、漏桶算法 基础描述漏桶算法是流量整形或速率限制时经常使用的一种算法,它的主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。 漏桶算法提供了一种机制,通过它,突发流量可以被整形以便为网络提供一个稳定的流量。漏桶算法基本思路:请求(水流)先进入到容器(漏桶)里,漏桶以一定的速度出水,这里就是指流量流出的策略,当流量流入速度过大容器无法承接就会直接溢出,通过该过程限制数据的传输速率。 核心要素 通过上述流程,不难发现漏桶算法涉及下面几个要素: 容器容量 容器的大小直接决定能承接流量的多少,容器一但接近饱和,要么溢出,要么加快流速; 流出速度 流量流出的速度取决于服务的请求处理能力,接口支撑的并发越高,流速就可以越大; 时间控制 基于时间记录,判断流量流出速度,控制匀速模式。 注意:需要一个基本的判定策略,漏桶算法在系统能承接当前并发流量时,不需要启用。 3、令牌桶算法 基础描述令牌桶可自行以恒定的速率源源不断地产生令牌。如果令牌不被消耗,或者被消耗的速度小于产生的速度,令牌就会不断地增多,直到把桶填满。后面再产生的令牌就会从桶中溢出。 令牌桶算法虽然根本目的也是控制流量速度,但是当令牌桶内的令牌足够多时,则允许流量阶段性的并发。传送到令牌桶的数据包需要消耗令牌。不同大小的数据包,消耗的令牌数量不一样。核心要素令牌桶存放按照特定的速率生成的令牌,以此控制流量速度。匹配规则这里的匹配规则更多是服务于分布式系统,例如服务A是系统的核心交易,当出现并发时,基于令牌桶最匹配规则,只允许交易请求通过,例如:常见双十一期间,各大电商平台提示,为保证核心交易,边缘服务的数据延迟或暂停等。注意:令牌桶算法和漏桶算法的目的虽然相同,但是实现策略是相反的,不过都存在一个问题,为保证大部分请求流量成功,会牺牲小部分请求。二、限流组件1、Nginx代理组件Nginx反向代理实际运行方式是指以代理服务器来接收客户端连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给客户端,此时代理服务器对外就表现为一个服务器。流量限制是Nginx作为代理服务中一个非常实用的功能,通过配置方式来限制用户在给定时间内HTTP请求的数量,两个主要的配置指令limit_req_zone和limit_req,以此保护高并发下系统的稳定。2、CDN边缘节点CDN边缘节点,准确的说并不是用来处理流量限制的,而是存放静态页面。内容缓存为CDN网络节点,位于用户接入点,是面向最终用户的内容提供设备,可缓存静态Web内容和流媒体内容,实现内容的边缘传播和存储,以便用户的就近访问,这样避免用户大量刷新数据服务器,节省骨干网带宽,减少带宽需求量。在高并发场景下,尤其是倒计时抢购类似业务,在活动开始前后用户会产生大量刷新页面的操作,基于CDN节点,这些请求不会下沉到数据的服务接口上。也可以基于页面做一些请求拦截,比如点击页面单位时间内只放行一定量的请求,以此也可以实现一个限流控制。三、熔断器组件所谓熔断器机制,即类似电流的保险器,当然电压过高会自动跳闸,从而保护电路系统。微服务架构中服务保护也是这个策略,当服务被判断异常,会从服务列表断开,等待恢复在重新连接。服务熔断降级的策略实现有如下几个常用的组件。1、Hystrix组件基础简介Hystrix当前处于维护模式,即不再更新,作为SpringCloud微服务组件中,最原生的一个熔断组件,很多思路还是有必要了解一下。例如:服务熔断,阻止故障的连锁反应,快速失败并迅速恢复,服务降级等。某个微服务发生故障时,要快速切断服务,提示用户,后续请求,不调用该服务,直接返回,释放资源,这就是服务熔断。熔断器策略服务器高并发下,压力剧增的时候,根据当业务情况以及流量,对一些服务和页面有策略的降级(可以理解为关闭不必要的服务),以此缓解服务器资源的压力以保障核心任务的正常运行。熔断生效后,会在指定的时间后调用请求来测试依赖是否恢复,依赖的应用恢复后关闭熔断。基本流程:首先判断服务熔断器开关状态,服务如果未熔断则放行请求;如果服务处于熔断中则直接返回。每次调用都执行两个函数markSuccess(duration)和markFailure(duration) 来统计在一定的时间段内的调用是成功和失败次数。基于上述的成功和失败次数的计算策略,来判断是否应该打开熔断器,如果错误率高于一定的阈值,就会触发熔断机制。熔断器有一个生命周期,周期过后熔断器器进入半开状态,允许放行一个试探请求;否则,不允许放行。2、Sentinel组件基础简介基于微服务的模式,服务和服务之间的稳定性变得越来越重要。Sentinel以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。Sentinel可以针对不同的调用关系,以不同的运行指标(如QPS、并发调用数、系统负载等)为基准,收集资源的路径,并将这些资源的调用路径以树状结构存储起来,用于根据调用路径对资源进行流量控制。流量整形策略直接拒绝模式是默认的流量控制方式,即请求超出任意规则的阈值后,新的请求就会被立即拒绝。启动预热模式:当流量激增的时候,控制流量通过的速率,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。匀速排队方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。熔断策略Sentinel本质上是基于熔断器模式,支持基于异常比率的熔断降级,在调用达到一定量级并且失败比率达到设定的阈值时自动进行熔断,此时所有对该资源的调用都会被阻塞,直到过了指定的时间窗口后才启发性地恢复。四、源代码地址GitHub·地址https://github.com/cicadasmile/husky-spring-cloudGitEE·地址https://gitee.com/cicadasmile/ 作者:架构月亮姨链接:https://juejin.im/post/5ef98cb95188252e734b45ea来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 【云栖号在线课堂】每天都有产品技术专家分享!课程地址:https://yqh.aliyun.com/live 立即加入社群,与专家面对面,及时了解课程最新动态!【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK 原文发布时间:2020-06-30本文作者:XXXX本文来自:“XXXX公众号”,了解相关信息可以关注“XXXX”

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

如何快速实现spring boot技术栈api文档的生成

作为开发,写接口文档一直是一个很头痛的问题,尤其在前后端分离大量盛行的当下,后端必须要为前端同事提供明确的入参出参文档,否则整个对接工作无法顺利进行,前后端的相爱相杀的大戏时常上演。笔者刚工作的那些年,swagger都还没有正式发布,对接前端和app端的文档全靠手写markdown完成。写接口文档的时间常常感jio比写代码耗费的时间还长。随着技术的进步和众多开源人的努力,近几年针对java开发的文档生成工具原来越多。新入行的开发人员再也不用去体会过去的那些辛酸的历程。在java文档生成的这个领域,swagger一直是一只领头羊。可能占据着90%的市场, 除此还有像 Spring REST Doc这些有名的工具也被大量的使用,但是这些工具在笔者看来使用比较蛮烦,侵入性高。今天笔者要给大家介绍和推荐一款本人开源的文档工具smart-doc,也会介绍如何使用这个工具来生成自己的文档。 一、当前市面文档工具存在的问题 下面来列举当前市场上主流文档工具的问题: 侵入性强,需要编写大量注解,代表工具如:swagger,还有一些公司自研的文档工具 强依赖性,如果项目不想使用该工具,业务代码无法编译通过。 代码解析能力弱,使用文档不齐全,主要代码为国内众多开源的相关工具。 众多基于注释分析工具无法分析jar包里面的注释(sources jar包),需要人工配置源码路径,无法满足devops构建场景。 无法支持多模块复杂项目代码分析。 二、smart-doc如何解决上述问题 通过分析源码注释自动生成API文档,不用编写任何注解,秉承注释即文档的原则,并且提供注释强制检查。 smart-doc开发了smart-doc-maven-plugin插件,项目仅仅依赖插件,剔除插件无修改项目不报任何编译错误。 smart-doc在国内经过上百家企业的使用,做了很多场景的分析,解析能力很强。 smart-doc-maven-plugin插件自动分析项目依赖完成对自发布jar包和第三方jar包源码的加载,不需要指定任何源码路径。 smart-doc-maven-plugin能够识别项目依赖,多模块maven项目不是问题。 smart-doc文档维护比较完善,码云上的wiki有16个页面介绍各种使用方式。 关于smart-doc 三、smar-doc的不足 smart-doc并非是完美的,仍然有很多不足。 界面支持不完善,没有发送请求的页面,无法满足小团队自测。 一些使用场景支持不完善,存在一些bug。 暂不支持其他框架文档的生成,如:dubbo等。 开源团队人员少,功能实现慢。 当前缺乏gradle插件支持。 四、spring boot集成smart-doc生成文档。 上面说了关于一起其它工具的问题,也介绍了smart-doc的优缺点,下面进入正题,如何快速使用smart-doc生成文档。 4.1 添加插件 在spring boot项目pom中添加smart-doc的maven插件 <plugin> <groupId>com.github.shalousun</groupId> <artifactId>smart-doc-maven-plugin</artifactId> <version>1.0.2</version> <configuration> <!--指定生成文档的使用的配置文件--> <configFile>./src/main/resources/smart-doc.json</configFile> <!--指定项目名称--> <projectName>测试</projectName> </configuration> <executions> <execution> <phase>compile</phase> <goals> <goal>html</goal> </goals> </execution> </executions> </plugin> 4.2 添加smart-doc.json配置文件 在4.1的代码片段中看到需要给插件指定一个生成文档的配置文件smart-doc.json。文件内容如下: { "serverUrl": "http://127.0.0.1",//服务器地址 "isStrict": false,//是否用严格模式,严格模式强制检查注释 "allInOne": true,//所有接口文档合并生成到一个文档 "outPath": "src/main/resources/static/doc",//文档的输出路径 "projectName": "smart-doc"//指定项目名称,用于显示在文档中 } 上面的几行配置中,实际上只有outPath值必须要填的,其他都是非必须。想了解更多详细配置请参考smart-doc插件使用 4.3 编写controller接口 @RestController @RequestMapping("/user") public class UserController { /** * 添加用户 * @param user * @return */ @PostMapping("/add") public User addUser(@RequestBody User user){ return user; } } 实体类: public class User { /** * 用户名 */ private String userName; /** * 昵称 */ private String nickName; /** * 用户地址 */ private String userAddress; /** * 用户年龄 */ private int userAge; /** * 手机号 */ private String phone; /** * 创建时间 */ private Long createTime; /** * ipv6 */ private String ipv6; /** * 固定电话 */ private String telephone; //省略get set } 4.4 运行插件生成文档 效果见4.5 4.5 用户信息操作接口 添加用户 URL:http://localhost:8080/user/add Type:POST Content-Type:application/json; charset=utf-8 Request-parameters: Parameter Type Description Required Since userName string 用户名 false - nickName string 昵称 false - userAddress string 用户地址 false - userAge int 用户年龄 false - phone string 手机号 false - createTime number 创建时间 false - ipv6 string ipv6 false - telephone string 固定电话 false - Request-example: { "userName":"鹏飞.贺", "nickName":"raymond.gutkowski", "userAddress":"Apt. 819 萧旁7699号, 章丘, 滇 852063", "userAge":41, "phone":"15018373016", "createTime":1569934393095, "ipv6":"9eb3:fada:ffd2:912e:6225:1062:a2d7:718f", "telephone":"15018373016" } Response-fields: Field Type Description Since userName string 用户名 - nickName string 昵称 - userAddress string 用户地址 - userAge int 用户年龄 - phone string 手机号 - createTime number 创建时间 - ipv6 string ipv6 - telephone string 固定电话 - Response-example: { "userName":"鹏飞.贺", "nickName":"raymond.gutkowski", "userAddress":"Apt. 819 萧旁7699号, 章丘, 滇 852063", "userAge":41, "phone":"15018373016", "createTime":1569934393095, "ipv6":"9eb3:fada:ffd2:912e:6225:1062:a2d7:718f", "telephone":"15018373016" } 总结 当前最新的smart-doc结合插件后,已经做到了非常易于使用,只需要引入插件和根据自己需求填充相关的配置即可,非常的轻量级。将smart-doc推荐给大家是为了帮助更多的同行能够快速的生成api文档,也是给一些正在自研的同行提供一些实现思路。想要参考贡献帮助smart-doc不断完善的开发者,我们也非常欢迎加入。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

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等操作系统。

用户登录
用户注册