Binder算是android里面比较难懂的部分了,但是非常重要,基本上,当我们深入到进程交互的阶段,Binder都是一个绕不开的槛,所以我也希望帮助大家更浅显地了解到这个知识点。笔者想通过3篇博文简单介绍Binder,也仅仅是Java层,希望能够帮助到想了解Binder基本知识的开发者。

为什么需要Binder?

在提及Binder之前,我们先看看我们平时开发的app的状况。每个app就像孤岛一样,生活在系统分配给自己的虚拟机和内存空间,好处是安全,各个app不会互相影响到对方,IE一个网页的崩溃却会导致整个IE应用程序死亡(举个小栗子,IE不属于跨进程)。在这种情况下,必须有一种机制,提供安全高效的通信的功能,Binder就为此而生。所以,Binder是Android系统的一种IPC(进程间通信)方式。ActivityManagerService、WinderManagerService等系统服务的背后都是Binder。

为什么选择Binder?

以前学过Linux的朋友都知道,Linux本身就提供了很多种跨进程通信的方式,如

  • Signals 信号量
  • Pipes 管道
  • Socket 套接字
  • Message Queue 消息队列
  • Shared Memory 共享内存

Android继承于Linux,想必更懂上面跨进程的机制(程序员又不傻,有现成好用的干嘛不复用呢),既然Android选择了Binder,想必是考虑到手机这一种独特的平台,需要适用一种更高效(手机内存省着用),更安全(防止应用被攻击、篡改)的烦方法。其实一种技术的运用,往往有更多的综合考量。有可能是那个年代,没有比这个技术更牛叉的了;有可能,是各家公司斗争协调出来的结果。

Binder 结构图

先通过两张Binder通用图介绍Binder是如何起作用的:

image

要运作Binder,需要4个角色通力合作:

  • 客户端:获取服务端在Binder驱动中对应的引用,然后调用它的transact方法即可向服务端发送消息。
  • 服务端:指Binder实现类所在的进程,该对象一旦创建,内部则会启动一个隐藏线程,会接收客户端发送的数据,然后执行Binder对象中的onTransact()函数。
  • Binder驱动:当服务端Binder对象被创建时,会在Binder驱动中创建一个mRemote对象。
  • Service Manager:作用相当于DNS,就想平时我们通过网址,然后DNS帮助我们找到对应的IP地址一样,我们在Binder服务端创建的Binder,会注册到Service Manager,同理,当客户端需要该Binder的时候,也会去Service Manager查找。

所以以上4者的运作基本上是:

  1. 服务端创建对应Binder实例对象,然后开启隐藏Binder线程,接收来自客户端的请求,同时,将自身的Binder注册到Service Manager,在Binder驱动创建mRemote对象。
  2. 客户端想和服务端通信,通过Service Manager查找到服务端的Binder,然后Binder驱动将对应的mRemote对象返回
  3. 至此,整个通信连接建立完毕

image

在建立完毕通信之后,客户端可以通过获取到的mRemote对象发生消息给远程服务端了,客户端通过调用transact()方法,将要请求的内容发送到服务段,然后挂起自己当前的线程,等待回复,服务端收到数据后在自己的onTransact()方法进行处理,然后将对应的结果返回给客户端,客户端收到数据,重新拉起线程,至此进程间交互数据完毕。

Binder 实战演练

下面通过实战,展示Binder如何成功实现跨进程通信,功能很简单,我们在服务端创建Binder,然后提供查询游戏价格的功能,然后客户端发起远程调用进行查询。

服务端代码

自定义Binder,需要在Service里面提供服务,我们先创建Service,然后在里面创建Binder

public class GameService extends Service {private Binder mBinder = new Binder() {};@Nullable@Overridepublic IBinder onBind(Intent intent) {return mBinder;}
}

注意onBind()方法,这里return的是我们在Service创建的Binder对象,客户端接受到的对象就是他。Binder对象里面,我们需要重载几个方法,分别是onTransact(),getGamePrice()方法。

  • onTransact() 方法是客户端发起调用后,服务端Binder所在进程接收到客户端发送的数据,通过这个方法去处理,根据响应码分发给具体的不同的方法去处理。
  • getGamePrice()方法 是自定义方法,用于接收客户端传送过来的游戏名去查询对应的价格
    private Binder mBinder = new Binder() {@Overrideprotected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {if (code == 1) {String _arg0;_arg0 = data.readString();int _result = getGamePrice(_arg0);reply.writeInt(_result);return true;}return super.onTransact(code, data, reply, flags);}public int getGamePrice(String name) {int price = -1;if ("逃生2".equals(name)) {price = 88;} else if ("饥荒".equals(name)) {price = 24;}return price;}};

这里为了方便起见,code(响应码)直接判断是否为1,是的话就取第一个数据,然后调用getGamePrice()方法查询价格,得到结果后通过reply封装结果,然后return true,表面成功接收并处理了结果。后面客户端会通过这个reply 去获取结果.

当然,别忘记了,设置Service,笔者在开发的时候将服务端和客户端写在同一个应用里面,所以需要主动将其中一个所在的进程改掉,这里直接将Service放到另一个进程,然后添加对应的隐式action

        <serviceandroid:name="com.smartwork.bindertest.GameService"android:process=":remote"><intent-filter><action android:name="android.intent.action.bind.gameservice" /></intent-filter></service>

客户端代码

客户端要做的只有两步:
1.绑定服务
2.发起请求

我们先看第一步,绑定,这里我们在button的onClick()事件里面进行处理

        mButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {String action = "android.intent.action.bind.gameservice";Intent intent = new Intent(action);intent.setPackage("com.smartwork.bindertest");bindService(intent, mServiceConnection, BIND_AUTO_CREATE);}});

注意 Android 5.0一出来后,其中有个特性就是校验 Intent,如果发现这个intent compponent==null 而且 package ==null 而且版本大于等于5.0 ,会抛出Service Intent must be explitict的异常,也就是说从Lollipop开始,service服务必须指定具体Component或者package启动。

private void validateServiceIntent(Intent service) {if (service.getComponent() == null && service.getPackage() == null) {if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {IllegalArgumentException ex = new IllegalArgumentException("Service Intent must be explicit: " + service);throw ex;} else {Log.w(TAG, "Implicit intents with startService are not safe: " + service+ " " + Debug.getCallers(2, 3));}}}

继续回到上面的方法,其中最重要的方法是bindService(),第二个参数是ServiceConnection对象,这个方法接收绑定成功和断开的回调。

    private IBinder mRemote = null;private ServiceConnection mServiceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mRemote = service;Toast.makeText(MainActivity.this, "绑定成功", Toast.LENGTH_SHORT).show();}@Overridepublic void onServiceDisconnected(ComponentName name) {mRemote = null;Toast.makeText(MainActivity.this, "远程服务链接已断", Toast.LENGTH_SHORT).show();}};

拿到这个service是属于IBinder接口,也就是之前我们在服务端onBind()方法返回的Binder对象,之后我们就可以利用这个mRemote进行查询操作。

简单一点,直接在一个button里面写onClick()查询游戏价格:

        mPriceButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {String gameName = "逃生2";int price = -1;try {price = getPrice(gameName);} catch (RemoteException e) {e.printStackTrace();}Toast.makeText(MainActivity.this, gameName + "  price is  : " + price, Toast.LENGTH_SHORT).show();}});

最近逃生2很火啊,查查多少钱来着。发送请求需要封装一下数据,抽了个方法另外去实现。

    private int getPrice(String name) throws RemoteException {android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();int _result;try {_data.writeString(name);mRemote.transact(1, _data, _reply, 0);_result = _reply.readInt();} finally {_reply.recycle();_data.recycle();}return _result;}

mRemote.transact(1, _data, _reply, 0)这个语句最重要,传递的分别是响应码,封装好发过去的数据包(装上我们要查询的游戏名),需要接收的数据包,flags(flags:0:normal调用,同步方式,1:异步调用,发送数据结束后不等待调用结果返回)。当执行到这个方法之后,当前的线程会被挂起,然后跳到服务端所在的线程进行处理,得到结果后,当前线程才会重新被唤醒,然后_reply得到数据。

至此整个跨进程交互通过Binder得到了实现。

!!!
需要强调的是,在客户端远程调用服务的时候,这个时候客户端当前线程会被挂起,被调用的方法运行在服务端的Binder线程里面,如果该方法是耗时方法,而且当前线程属于UI线程,很可能会出现ANR的问题,所以需要注意这个远程调用,如果不明确,尽量避免在UI线程发起调用。另外onServiceConnected和onService也是运行在UI线程里面,需要注意避免耗时操作。

还需要注意一点,在Binder传输数据的时候,经历过序列化和反序列化,简单一点就是,就算你两个传递过去给服务端都是同一个对象,服务端都会认为是两个不同的对象,只是里面的数据一样而已。这也很好理解,客户端和服务端处于不同的进程,你发过去的对象必须经过序列化和反序列化,所以对于服务端,每次都感觉接收到新的对象。如果想解决这个问题:
请看XXX

好的,上面就是Binder最简单的用法了,基本上也能完成老大交代下来的工作了,但是辛(苦)勤(逼)的程序员是不会就这样就满足的。如果你不满足上面简单的实现,想深入了解怎样可以优化整个流程或者深入到源码理解具体的内部实现,请继续。。。

首先你要知道,我骗了你。(不要打我,不要打我脸/(ㄒoㄒ)/~~)。其实上面的例子中,客户端获取到的并不是Binder实现类对象,而是Binder的一个代理。意思就是,在跨进程访问中,获取到的IBinder接口的对象,一般是实现类的代理类,并不是本体,相对的,如果是在同一个进程请求,那么获取到的IBinder接口的对象,就是对应Binder的实现类。

image

基本上就是这样,而这个获取IBinder具体对象的逻辑发生在Native层,所以暂时不建议深追,先把java层的东西记住就好:其实也很好理解,当发现是同一个进程访问的时候,系统会直接返回这个Binder实现类,这样之后调用的方法就不用再经过跨进程IPC一系列的步骤,简单的应用类方法调用就是了,当发现是跨进程访问的时候,发给客户端就是一个Binder的代理类;发给客户端就是一个Binder的代理类;发给客户端就是一个Binder的代理类。OK重要的事情说了3遍。

好的,下面我们来看看具体可以怎么优化,

  1. 在客户端我们知道,每次发送过去最重要的数据就是状态码和Parcel的数据包,我们可以直接抽象出一个代理类,包裹这个IBinder接口,然后以调用类的方法的形式进行访问,
  2. 然后将我们想要的查询游戏价格的方法以接口的形式让这个代理类去实现
  3. 每个方法对应一个响应码,以常量形式出现
public interface GameInterface {public static final int GET_PRICE_CODE = 1;   //响应码int getPrice(String name) throws RemoteException;
}
public class GameBinderProxy implements GameInterface {private IBinder mRemote;GameBinderProxy(IBinder binder) {mRemote = binder;}@Overridepublic int getPrice(String name) throws RemoteException {android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();int _result;try {_data.writeString(name);mRemote.transact(GET_PRICE_CODE, _data, _reply, 0);_result = _reply.readInt();} finally {_reply.recycle();_data.recycle();}return _result;}
}

这个构造方法还是在我们onServiceConnected()处调用:

        @Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mRemote = new GameBinderProxy(service);Toast.makeText(MainActivity.this, "绑定成功", Toast.LENGTH_SHORT).show();}

相对的服务端也进行优化:

public class GameBinderNative extends Binder implements GameInterface {@Overridepublic int getPrice(String name) throws RemoteException {int price = -1;if ("逃生2".equals(name)) {price = 88;} else if ("饥荒".equals(name)) {price = 24;}return price;}@Overrideprotected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {if (code == GET_PRICE_CODE) {String _arg0;_arg0 = data.readString();int _result = getPrice(_arg0);reply.writeInt(_result);return true;}return super.onTransact(code, data, reply, flags);}
}
public class GameService extends Service {private Binder mBinder = new GameBinderNative();@Nullable@Overridepublic IBinder onBind(Intent intent) {return mBinder;}
}

OK ,这就很舒服,整个代码块干净了不少,其实优秀到七七八八了,要是硬要挑一下骨头的话,我们可以对客户端这个代理类再动动手脚,如果是跨进程访问的,就用代理包装一下BinderProxy,如果是同一个进程访问直接返回就可以了:

    //这里返回的是GameInterface接口public static GameInterface asInterface(android.os.IBinder obj) {if (obj == null) {return null;}if (obj instanceof Binder) {Log.d("chenjiahui", "asInterface: GameBinderNative  :  obj instanceof Binder");return (GameInterface) obj;} else {Log.d("chenjiahui", "asInterface: GameBinderNative  :  obj instanceof GameBinderProxy");return new GameBinderProxy(obj);}}

客户端

        public void onServiceConnected(ComponentName name, IBinder service) {mRemote = GameBinderNative.asInterface(service);Toast.makeText(MainActivity.this, "绑定成功", Toast.LENGTH_SHORT).show();}

重要的事情说三篇,onServiceConnected回调返回的IBinder service对象,如果是跨进程访问的返回的是BinderProxy(Binder的代理类),同一进程访问返回的是Binder;如果是跨进程访问的返回的是BinderProxy(Binder的代理类),同一进程访问返回的是Binder;如果是跨进程访问的返回的是BinderProxy(Binder的代理类),同一进程访问返回的是Binder。

OK,到这里,整篇文章差不多要结束了,因为我刚才教你的优化方法,就是AIDL。

AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言。

这个是官方的说辞,以我的理解就是,帮助开发者更有效率地去实现这个Binder,因为用了AIDL之后生成了专门跨进程通信的模板,免除了一大堆统一的代码,用了AIDL之后,在服务端,关注具体跨进程方法的实现就可以,客户端更是不用写任何额外的代码,因为全部自动生成了。

AIDL 实操

我们试试打开Android Studio,然后新建一个aidl文件
image

interface IGameService {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString);int getPrice(String name);
}

好的,还是我们查询游戏价格的方法getPrice(),上面还有一个方法basicTypes(),没啥用,看google注释就是告诉我们aidl可以传的基础类型有哪些,当然还可以传parcelable的对象,这个放到第3篇文章讲吧(因为别的文章都说了很多了,看两三篇博文一下子就懂了)

写完这个IGameService接口后,我们clean 一下项目,打开目录看看有什么东西:
app/build/generated/source/aidl/debug or release / 包名 / IGameService

image

我把IGameService的代码抽出来先看个大概:

public interface IGameService extends android.os.IInterface
{public static abstract class Stub extends android.os.Binder implements com.smartwork.bindertest.IGameService{public Stub(){this.attachInterface(this, DESCRIPTOR);}public static com.smartwork.bindertest.IGameService asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.smartwork.bindertest.IGameService))) {return ((com.smartwork.bindertest.IGameService)iin);}return new com.smartwork.bindertest.IGameService.Stub.Proxy(obj);}@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{switch (code){case TRANSACTION_getPrice:{//省略了代码,就是我们之前写的那个!!!}}return super.onTransact(code, data, reply, flags);}private static class Proxy implements com.smartwork.bindertest.IGameService{private android.os.IBinder mRemote;Proxy(android.os.IBinder remote){mRemote = remote;}@Override public android.os.IBinder asBinder(){return mRemote;}public java.lang.String getInterfaceDescriptor(){return DESCRIPTOR;}@Override public int getPrice(java.lang.String name) throws android.os.RemoteException{//省略了代码,就是我们之前写的那个!!!}}static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);static final int TRANSACTION_getPrice = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);}public int getPrice(java.lang.String name) throws android.os.RemoteException;
}
  • 先简单说下三者的结构,是一个interface接口,里面有一个抽象类Stub(这个Stub是交给服务端去具体实现的),然后抽象类Stub里面有一个内部类Proxy(听名字就知道是给Stub做代理的)
  • 这3者对应之前我们优化的过程,对比着看,其实是一样的,只是google将他们三个放在一起了,刚看这个生产的java感觉特别乱,但是你跟之前的优化过程对比一看就会立马清晰很多了。
  • 当然了,生成的这个java和我们之前优化的有点不同,就是多了android.os.IInterface这个接口,所以Stub里面的asInterface方法(也就是我之前说的那个,同一个进程Binder直接返回,不然就用代理类封装的方法)也有点不一样。
  • asInterface是一个static方法,提供客户端调用,然后通过queryLocalInterface()这个方法判断是否同一个进程,因为假如是服务端所在的进程请求,获得的是Binder实现类,初始化的时候Stub()会调用attachInterface(),其实就是自己把自己存起来了,后面如果queryLocalInterface()的话就能返回到对象。但是跨进程访问,返回的是BinderProxy,这个时候queryLocalInterface()只能是null了。
    public IInterface queryLocalInterface(String descriptor) {return null;}
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 高效能人士的七个习惯----再看一遍,新年再次实践,2016年宣言

    《高效能人士的七个习惯》是由著名领导力大师、人际关系专家史蒂芬柯维博士开发的享誉全球的版权课程。习惯一 积极主动培训收益自我意识、想象力、良知、独立意志是人类的四大天赋,也是职场人士天然具备的重要资源。但是,只有通过运用高效能的思维框架(例如区分关注圈与影…...

    2024/4/28 12:56:57
  2. 南航计网课设——基于Hadoop的网络爬虫技术

    作者:shmily 文章目录实验概述环境搭建分布式网络爬虫的工作原理分布式爬虫系统的结构设计网络爬虫倒排索引+中文分词用户搜索模拟心得体会 实验概述 本实验使用java语言编程,实现了利用分布式爬虫对CSDN社区(http://www.csdn.com)的爬取和搜索。 实现搜索引擎的思路大致分…...

    2024/4/28 3:57:31
  3. delphi7从入门到精通之四

    Delphi 编辑器 在表面上,对IDE的第7个版本来说Delphi的编辑器看来似乎没有改变许多。 然而,在幕后,它是一个全新的工具。 除了用它来处理Object Pascal 语言(或者Delphi语言,Borland现在喜欢如此称呼它)的文件之外,你现在能使用它来处理其它用于Delphi开发(诸如SQL,XML,…...

    2024/4/28 7:00:22
  4. Android进程通信之 Binder 机制浅析

    IBinderBinder 继承自 IBinder,所以我们先来了解下它。IBinder 是一个接口,它代表了一种跨进程传输的能力。只要实现了这个接口,就能将这个对象进行跨进程传递。IBinder 是高性能、轻量级远程调用机制的核心部分,它定义了远程操作对象的基本接口。这些方法中最关键的一个是…...

    2024/4/20 5:58:06
  5. ActivityGroup详解

    本文转载自http://blog.csdn.net/caowenbin/article/details/5876019 此前,我们对Activity进行了一些学习,在Android中,还提供了一个ActivityGroup类,该类是Activity的容器,可以包含多个嵌套进来的Activitys,我们接下来依然采用源码分析的方式来了解该类的内部实现。 首先…...

    2024/4/28 4:21:06
  6. 读《高效能人士七个习惯》总结

    高效能人士的七个习惯 之个人领域的成功: 1、积极主动:自由选择回应,不受外界干扰。 2、以终为始:即自我领导;先构思、认清目标再执行。 3、要事优先:即自我管理;将事务排好优先级,把时间花在重要但不紧迫的事上。 高效能人士的七个习惯 之公共领域的成功: 1、双赢思维…...

    2024/4/28 17:58:03
  7. html的button的onserverclick事件不管用

    将<input type="button" />换成<input type="submit" />就ok了。...

    2024/4/28 22:41:19
  8. Python爬虫基础知识及前期准备

    学习爬虫有一小段时间了,于是决定把自己学爬虫时所学的,写过的代码以及看过的文档记录下来,权当小结。第一次写这些,如果有错误,请多指教。首先我们需要了解一下什么是爬虫。根据百度百科上给出的定义,” 网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常…...

    2024/4/28 5:09:03
  9. ActivityGroup---activity的管理器

    通过名字,就应该知道ActivityGroup是一个Activity的管理器,对于一组Activity的管理非常方面。下面是实例代码: ActivityGroupTest.java[java] viewplain copypackage app.imo; import android.app.ActivityGroup; import android.content.Intent; import android.os.Bu…...

    2024/4/28 5:23:27
  10. [Innost]Android深入浅出之Binder机制

    ZZ FROM:http://www.cnblogs.com/innost/archive/2011/01/09/1931456.html================================================================Android深入浅出之Binder机制 一 说明Android系统最常见也是初学者最难搞明白的就是Binder了,很多很多的Service就是通过Binder机制…...

    2024/4/28 4:16:48
  11. 爬虫课程一(爬虫的概念与HTTP的复习)

    目前在学习爬虫的课程以下小坐总结:第一天主要看了以写爬虫的原理以及爬虫数据的抓取一1.1:为什么学习爬虫最主要的是在目前看来,爬虫工程师属于紧缺型人才,并且薪资待遇普遍较高1,学习爬虫,可以私人定制一个搜索引擎。2,大数据时代,要进行数据分析,首先要有数据源3,…...

    2024/4/28 10:48:42
  12. 《高效能人士7个习惯》读书心得

    个人成长篇-----------构建自主的独立的人格1.打破旧的思维惯性的旧模式,将原有刺激→反应旧习惯模式,改为由刺激→自我选择习惯模式(自我意识、想象力、良知、独立意志)2.积极主动,随时培养自己随时具备选择的能力,养成积极主动习惯。习惯改变由三者的交集形成(技能、愿…...

    2024/4/27 23:51:08
  13. Spark SQL:从入门到精通(二)[IDEA开发Spark SQL]

    创建DataFrame/DataSet Spark会根据文件信息尝试着去推断DataFrame/DataSet的Schema,当然我们也可以手动指定,手动指定的方式有以下几种: 第1种:指定列名添加Schema 第2种:通过StructType指定Schema 第3种:编写样例类,利用反射机制推断Schema 指定列名添加Schema packag…...

    2024/4/17 4:25:48
  14. 从源码角度分析Android中的Binder机制的前因后果

    前面我也讲述过一篇文章《带你从零学习linux下的socket编程》,主要是从进程通信的角度开篇然后延伸到linux中的socket的开发。本篇文章依然是从进程通信的角度去分析下Android中的进程通信机制。为什么在Android中使用binder通信机制?众所周知linux中的进程通信有很多种方式,…...

    2024/4/19 23:52:40
  15. ActivityGroup相关--getLocalActivityManager() 【转载】

    ActivityGroup简介 1.ActivityGroup的核心就是继承了该类,能够通过getLocalActivityManager()得到一个LocalActivityManager如,LocalActivityManager am= getLocalActivityManager(); 2.然后通过LocalActivityManager通过startActivity(String id, Intent intent),可以与指定…...

    2024/4/28 18:34:43
  16. 高效能人士的七个习惯——习惯一:积极主动

    我以前所理解积极主动是,做事的时候表现的非常积极,主动去做一些事情而不是等着领导分配任务才去开始。这是比较狭隘的一种理解。积极主动不仅仅指行事态度,还意味着人一定要为自己的人生负责。它强调的是:个人行为取决于自身的抉择,而不是外在的环境。一种不愿意承担责任…...

    2024/4/17 4:26:00
  17. 爬虫及相关概念的简述

    爬虫及相关概念的简述 什么是爬虫?网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。爬虫应用的一些例子搜索引擎 : 当你在百度/谷歌中输入关键字搜索的时候,会跳出一些相关…...

    2024/4/18 7:20:59
  18. form中button提交表单

    发现:springmvc 项目,js校验不通过,return后,表单依然可以提交。原因:form表单下的按钮在没有指定type类型的时候,如果我们同时给其添加了点击事件的话。会发现我们在点击的时候回默认的把表单也给提交了 https://www.w3.org/TR/2011/WD-html5-20110525/the-button-eleme…...

    2024/4/21 0:47:45
  19. Elasticsearch教程-从入门到精通

    各位运维同行朋友们,大家好,非常高兴能有这么个机会与大家一起交流一些技术问题。此前的各位分享达人们在技术领域或管理领域均有十分精彩的分享,他们带给我们的是多个领域中研究或实践的最前沿知识。这使我本人获益良多,首先要郑重感谢他们。开始之前,本人首先做一下自我…...

    2024/4/20 17:20:18
  20. 网站开发进阶(四十四)input type="submit" 和"button"的区别

    网站开发进阶(四十四)input type=”submit” 和”button”的区别在一个页面上画一个按钮,有四种办法:这就是一个按钮。如果你不写javascript 的话,按下去什么也不会发生。这样的按钮用户点击之后会自动提交 form,除非你写了javascript 阻止它。这个按钮放在 form 中也会点…...

    2024/4/17 4:26:06

最新文章

  1. SpringMVC进阶(过滤器解决中文乱码,处理json以及文件上传下载)

    文章目录 1.中文乱码处理1.引出问题1.恢复原来取消掉的属性绑定2.启动服务器&#xff0c;引出问题 2.自定义中文乱码过滤器1.MyCharacterFilter.java2.web.xml配置过滤器&#xff08;这个解决乱码的过滤器放到最前面&#xff09;3.结果展示 3.使用Spring过滤器处理&#xff08;…...

    2024/4/28 23:16:16
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 利用Sentinel解决雪崩问题(一)

    1、解决雪崩问题的常见方式有四种: 超时处理:设定超时时间&#xff0c;请求超过一定时间没有响应就返回错误信息&#xff0c;不会无休止等待;舱壁模式:限定每个业务能使用的线程数&#xff0c;避免耗尽整个tomcat的资源&#xff0c;因此也叫线程隔离;熔断降级:由断路器统计业务…...

    2024/4/24 3:11:43
  4. 【Godot4自学手册】第三十五节摇杆控制开门

    本节主要实现&#xff0c;在地宫墙壁上安装一扇门&#xff0c;在核实安装一个开门的摇杆&#xff0c;攻击摇杆&#xff0c;打开这扇门&#xff0c;但是只能攻击一次&#xff0c;效果如下&#xff1a; 一、添加完善节点 切换到underground场景&#xff0c;先将TileMap修改一下…...

    2024/4/26 19:55:01
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/28 13:52:11
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/28 3:28:32
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/26 23:05:52
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/28 13:51:37
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/28 15:57:13
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/28 1:22:35
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/25 18:39:14
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/26 23:04:58
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/26 19:46:12
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/27 11:43:08
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/27 8:32:30
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57