辰迅云帮助中心

其他类

小编给大家分享一下CentOS桌面环境中网卡启动失败怎么办,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!我在最小化安装CentOS中网卡启动正常,但是当我们装了桌面版的CentOS后,发现不管使用哪种启动网卡的方式都会启动失败。截图如下:后来查阅报错原因,NetworkManager管理工具和/etc/sysconfig/network-scripts/ifcfg-ethx配置不同步造成的。使用下面两个命令可以解决上面网卡重启失败导致的问题:chkconfigNetworkManageroff //注释 关掉它,不让它开机自动启动service NetworkManager stop //停掉这个服务以上是“CentOS桌面环境中网卡启动失败怎么办”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注辰讯云资讯频道!...

这篇文章给大家分享的是有关centos如何查找已安装的jdk路径的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在可执行 java命令的情况下查找过程如下:执行which java[root@localhost ~]# which java/usr/bin/java执行ls -lrt /usr/bin/java[root@localhost ~]# ls -lrt /usr/bin/javalrwxrwxrwx. 1 root root 22 10月 10 08:06 /usr/bin/java -> /etc/alternatives/java执行ls -lrt /etc/alternatives/java[root@localhost ~]# ls -lrt /etc/alternatives/javalrwxrwxrwx. 1 root root 73 10月 10 08:06 /etc/alternatives/java -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.144-0.b01.el7_4.x86_64/jre/bin/java由上可知java的路径为: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.144-0.b01.el7_4.x86_64,进入该路径查看文件如下:[root@localhost ~]# cd /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.144-0.b01.el7_4.x86_64[root@localhost java-1.8.0-openjdk-1.8.0.144-0.b01.el7_4.x86_64]# ll总用量 4drwxr-xr-x. 2 root root 4096 10月 10 14:53 bindrwxr-xr-x. 3 root root 132 10月 10 14:53 includedrwxr-xr-x. 4 root root  28 10月 10 08:03 jredrwxr-xr-x. 3 root root 144 10月 10 14:53 libdrwxr-xr-x. 2 root root 204 10月 10 14:53 tapset[root@localhost java-1.8.0-openjdk-1.8.0.144-0.b01.el7_4.x86_64]#感谢各位的阅读!关于“centos如何查找已安装的jdk路径”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!...

这篇文章主要介绍了centos下怎么搭建SVN服务器和MySQL,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。搭建MySQL1、查看yum库中的mysqlyum list | grep mysql //查看yum库中的mysql2、选择需要的mysql进行安装yum install mysql mysql-server mysql-devel -y //安装mysql3、验证是否安装成功yum list installed | grep mysql //查看已安装的mysqlrpm -qi mysql-server //查看mysql详细信息4、启动mysql服务service mysqld start //启动mysql服务service mysqld stop //停止mysql服务service mysqld restart //重启mysql服务5、进入mysql,并修改密码mysql -u root //进入mysqlshow databases; //显示所有数据库use mysql; //使用名为“mysql”的数据库/* 注意:这里修改密码如果写的是password='123456'则改的密码不是123456,而是其他 */update user set password=password('123456') where user='root';//修改密码为123456select user,password from user; //查看修改后的密码FLUSH PRIVILEGES; //刷新user表,如果没有写这句那么就没有用6、退出并用刚修改过的密码重新登录quit; //退出mysql(exit;也可以退出)mysql -u root -p //使用密码登录mysql7、开放远程登录权限GRANT ALL PRIVILEGES ON *.* TO 'itoffice'@'%' IDENTIFIED BY 'itoffice' WITH GRANT OPTION; (第一个itoffice表示用户名,%表示所有的电脑都可以连接,也可以设置某个ip地址运行连接,第二个itoffice表示密码)。FLUSH PRIVILEGES; 8、开放防火墙3306端口或者关闭防火墙service iptables stop  //关闭防火墙/*  如果sysconfig下没有iptables文件  可以先随便写一句协议:iptables -P OUTPUT ACCEPT  然后保存:service iptables save  这样就会有iptables文件了 */vim /etc/sysconfig/iptables //编辑防火墙配置//在配置文件中加入-A INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT9、设置mysq开机启动chkconfig mysqld on10、因为是阿里云服务器,所以还要去阿里云上面给服务器添加3306的安全组,不然一样远程不过去 ;搭建SVN准备工作1、yum install subversion安装2、输入rpm -ql subversion查看安装位置,3、mkdir /svn建立目录4、svnadmin create /svn/test/ 新建一个测试仓库5、cd /svn/test/conf 进入test/conf目录6、vi svnserve.conf7、 vi passwd8、vi authz9、svnserve -d -r /svn 启动svn服务10、netstat -ntpl说明服务器启动了11、外网访问122.222.222.22(要安装telnet)要在windows机器上 dos 写telnet 122.222.222.22 3690如果连接不上,说明linux服务器的防火墙没有打开已经连上了。12、SVN目录树一般比较规范的SVN它会有三个目录,分别为:/svn/trunk: 主干/svn/branch: 个人或团队开发的分支/svn/tag: 标记版本,比如某个版本开发好了。现在我要创建三个这样的目录,然后我要导入到版本库中去,这里会用到的是import命令cd /svn  mkdir -p svn/{trunk,branch,tag}  svn import /svn/svn svn://192.168.200.200/test --username=admin --password=123456 -m "import"Username:user01 这个是svn系统设置的Password:123456 这个是svn系统设置的感谢你能够认真阅读完这篇文章,希望小编分享的“centos下怎么搭建SVN服务器和MySQL”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注辰讯云资讯频道,更多相关知识等着你来学习!...

这篇文章给大家分享的是有关centos6.5怎样通过yum安装nginx的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。linux安装nginx以及配置教程,供大家参考,具体内容如下以下是:centos6.5 通过yum安装nginx提示No package nginx available 需要先安装epe:yum install epel-release安装epel之后yum -y install nginx安装完成之后service nginx start 启动nginx在浏览器访问机器ip可以看到nginx的界面。如果访问不了,查看linux防火墙状态。增加80端口访问nginx启动之后,我们需要根据需要修改配置文件,可以先使用 ps-ef|grep nginx查看这里是nginx目前使用的配置文件worker_processes 一般设置为系统核数(查看系统几核more /proc/cpuinfo |grep "physical id"|grep "0"|wc -l)/etc/nginx/conf.d/里面是额外的配置文件。之后在这里面配置,比如一些静态资源的位置。比如我希望/data/html下所有文件都通过nginx负载均衡访问,简单修改如下配置即可:感谢各位的阅读!关于“centos6.5怎样通过yum安装nginx”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!...

这篇文章主要介绍了在CentOS中怎么搭建Git服务器,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。前言我们可以GitHub发布一些开源代码的公共仓库,但对于私密仓库就需要收费了。公司内部通常会搭建自己的Git服务器,我也通过在自己的服务器上搭建练习一下。开始前先说一下服务器信息,这里是阿里云的CentOS 6.5 64位操作系统。一 确认服务器是否安装Git[root@iZ25r8k6ifuZ git]# rpm -qa gitgit-1.7.1-3.el6_4.1.x86_64这里也已经安装过了,如果没有安装可以用yum install git 安装。二 创建git用户这里你可以选择新建一个用户来测试,也可以直接使用你的root进行以下操作。笔者也是看着资料一步一步来的,这里创建一个新用户teslachen进行操作。[root@iZ25r8k6ifuZ ~]# useradd tesla[root@iZ25r8k6ifuZ ~]# passwd tesla更改用户 tesla 的密码 。新的 密码:无效的密码: 它没有包含足够的不同字符无效的密码: 过于简单重新输入新的 密码:passwd: 所有的身份验证令牌已经成功更新。注1:创建用户权限不够请加上sudo;注2:设置用户密码太过简单的话会有提示,但依旧可以设置成功。三 生成ssh公钥许多 Git 服务器都使用 SSH 公钥进行认证。 为了向 Git 服务器提供 SSH 公钥,如果某系统用户尚未拥有密钥,必须事先为其生成一份。linux 可以在本机运行ssh-keygen -t rsa生成密钥,把.pub文件拷到服务器上。[root@iZ25r8k6ifuZ ~]# su tesla[tesla@iZ25r8k6ifuZ root]$ cd ~ [tesla@iZ25r8k6ifuZ ~]$ mkdir .ssh [tesla@iZ25r8k6ifuZ ~]$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/tesla/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again:Your identification has been saved in /home/tesla/.ssh/id_rsa. Your public key has been saved in /home/tesla/.ssh/id_rsa.pub. The key fingerprint is:13:bf:75:ba:67:7f:0e:a0:47:7a:fe:25:bc:81:85:c3 tesla@iZ25r8k6ifuZ The key's randomart image is: +--[ RSA 2048]----+ |     | |     | |  .  | |   o . . | |  S . E o | |   . O | |   + = = .| |   + .o.| |   o+oo+| +-----------------+ [tesla@iZ25r8k6ifuZ ~]$ cd .ssh/ [tesla@iZ25r8k6ifuZ .ssh]$ cat id_rsa.pub >> ~/.ssh/authorized_keys exit四 添加tesla到sudoers文件tesla用户现在对一些文件夹没有操作权限,修改/etc/sudoers文件来改变他的权限。最高管理员用户用下面命令打开。[root@iZ25r8k6ifuZ ~]# visudo然后我们在vim中找到下面这行root ALL=(ALL) ALL按i键开始插入,回车一下在下面一行加上tesla ALL=(ALL) ALL接着按下esc键,输入 :wq ,回车保存退出五 创建Git代码仓库[root@iZ25r8k6ifuZ ~]# mkdir /teslaRepo[root@iZ25r8k6ifuZ ~]# cd /teslaRepo/[root@iZ25r8k6ifuZ teslaRepo]# sudo mkdir teslaProject.git[root@iZ25r8k6ifuZ teslaRepo]# chown tesla:tesla /teslaRepo/[root@iZ25r8k6ifuZ teslaRepo]# chown -R tesla:git /teslaRepo/[root@iZ25r8k6ifuZ teslaRepo]# cd teslaProject.git/[root@iZ25r8k6ifuZ teslaProject.git]# sudo git --bare initInitialized empty Git repository in /teslaRepo/teslaProject.git/这样一个叫teslaProject得Git仓库就创建好了六 本地测试使用你可以直接在服务器上进行本地测试,也可以直接用你的电脑来测试。下面我是使用自己的MBP来进行的测试。localhost:~ okay$ cd Desktop/git/localhost:git okay$ mkdir teslaRepolocalhost:git okay$ cd teslaRepo/localhost:teslaRepo okay$ git init Initialized empty Git repository in /Users/okay/Desktop/git/teslaRepo/.git/localhost:teslaRepo okay$ git remote add origin tesla@123.57.159.74:/teslaRepo/teslaProject.git上面的命令在本地创建了一个文件夹并添加了服务器上的远程仓库localhost:teslaRepo okay$ touch a.txt localhost:teslaRepo okay$ git add a.txt localhost:teslaRepo okay$ git commit -m "init commit"[master (root-commit) d14cd3b] init commit 1 file changed, 0 insertions(+), 0 deletions(-)  create mode 100644 a.txt上面的命令在本地创建了一个a.txt并在本地提交了一次localhost:teslaRepo okay$ git push origin mastertesla@123.57.159.74's password:Counting objects: 3, done.Writing objects: 100% (3/3), 202 bytes | 0 bytes/s, done.Total 3 (delta 0), reused 0 (delta 0)To tesla@123.57.159.74:/teslaRepo/teslaProject.git * [new branch]  master -> master上面的命令将本地代码push到远程服务器上去了,下面我们在本地clone一次看下是否正确七 本地clonelocalhost:git okay$ mkdir tttlocalhost:git okay$ cd tttlocalhost:ttt okay$ git clone tesla@123.57.159.74:/teslaRepo/teslaProject.git Cloning into 'teslaProject'... tesla@123.57.159.74's password: remote: Counting objects: 3, done. remote: Total 3 (delta 0), reused 0 (delta 0) Receiving objects: 100% (3/3), done. Checking connectivity... done.clone完成,让我们看一下文件夹目录之前push到服务器上的a.txt文件已经被clone下来------------分割线-------------   1. 查看系统用户组-d:指定字段的分隔符,默认的字段分隔符为“TAB”; -f:显示指定字段的内容;cut -d: -f1 /etc/group2. 查看系统用户cut -d: -f1 /etc/passwd3. clone仓库git clone git@your_gitServer_ip:/home/gitrepo/sample.git4. push已有仓库// 以master分支示范git checkout master git remote rm origin git remote add origin git@your_gitServer_ip:/home/gitrepo/sample.git git push -u origin master感谢你能够认真阅读完这篇文章,希望小编分享的“在CentOS中怎么搭建Git服务器”这篇文章对大家有帮助,同时也希望大家多多支持辰讯云,关注辰讯云资讯频道,更多相关知识等着你来学习!...

Laravel中处理OPTIONS请求的原理是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1. 问题描述Laravel处理OPTIONS方式请求的机制是个谜。假设我们请求的URL是http://localhost:8080/api/test,请求方式是OPTIONS。如果请求的URL不存在相关的其它方式(如GET或POST)的请求,则会返回404 NOT FOUND的错误。如果存在相同URL的请求,会返回一个状态码为200的成功响应,但没有任何额外内容。举例而言,在路由文件routes/api.php中如果存在下面的定义,则以OPTIONS方式调用/api/test请求时,返回状态码为200的成功响应。Route::get('/test', 'TestController@test');但同时通过分析可以发现,这个OPTIONS请求不会进到此api路由文件的生命周期内,至少该GET请求所在路由文件api所绑定的中间件是没有进入的。此时如果手动添加一个OPTIONS请求,比如:Route::get('/test', 'TestController@test'); Route::options('/test', function(Request $request) {     return response('abc'); });则至少会进入该GET请求所在路由文件api绑定的中间件,可以在相关handle函数中捕获到这个请求。2. 分析源码通过仔细查看Laravel的源码,发现了一些端倪。在文件vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php的第159行左右,源码内容如下:        $routes = $this->get($request->getMethod());         // First, we will see if we can find a matching route for this current request        // method. If we can, great, we can just return it so that it can be called        // by the consumer. Otherwise we will check for routes with another verb.        $route = $this->matchAgainstRoutes($routes, $request);         if (! is_null($route)) {             return $route->bind($request);         }         // If no route was found we will now check if a matching route is specified by        // another HTTP verb. If it is we will need to throw a MethodNotAllowed and        // inform the user agent of which HTTP verb it should use for this route.        $others = $this->checkForAlternateVerbs($request);         if (count($others) > 0) {             return $this->getRouteForMethods($request, $others);         }         throw new NotFoundHttpException;这里的逻辑是:1. 首先根据当前HTTP方法(GET/POST/PUT/...)查找是否有匹配的路由,如果有(if(! is_null($route))条件成立),非常好,绑定后直接返回,继续此后的调用流程即可;2. 否则,根据$request的路由找到可能匹配的HTTP方法(即URL匹配,但是HTTP请求方式为其它品种的),如果count($others) > 0)条件成立,则继续进入$this->getRouteForMethods($request, $others);方法;3. 否则抛出NotFoundHttpException,即上述说到的404 NOT FOUND错误。倘若走的是第2步,则跳转文件的234行,可看到函数逻辑为:    protected function getRouteForMethods($request, array $methods)    {         if ($request->method() == 'OPTIONS') {             return (new Route('OPTIONS', $request->path(), function () use ($methods) {                 return new Response('', 200, ['Allow' => implode(',', $methods)]);             }))->bind($request);         }         $this->methodNotAllowed($methods);     }判断如果请求方式是OPTIONS,则返回状态码为200的正确响应(但是没有添加任何header信息),否则返回一个methodNotAllowed状态码为405的错误(即请求方式不允许的情况)。此处Laravel针对OPTIONS方式的HTTP请求处理方式已经固定了,这样就有点头疼,不知道在哪里添加代码针对OPTIONS请求的header进行处理。最笨的方法是对跨域请求的每一个GET或POST请求都撰写一个同名的OPTIONS类型的路由。3. 解决办法解决方案有两种,一种是添加中间件,一种是使用通配路由匹配方案。总体思想都是在系统处理OPTIONS请求的过程中添加相关header信息。3.1 中间件方案在文件app/Http/Kernel.php中,有两处可以定义中间件。第一处是总中间件$middleware,任何请求都会通过这里;第二处是群组中间件middlewareGroups,只有路由匹配上对应群组模式的才会通过这部分。这是总中间件$middleware的定义代码:    protected $middleware = [         \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,        \App\Http\Middleware\TrimStrings::class,        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,        \App\Http\Middleware\TrustProxies::class,    ];这是群组中间件$middlewareGroups的定义代码:    /**     * The application's route middleware groups.     *     * @var array     */    protected $middlewareGroups = [         'web' => [             \App\Http\Middleware\EncryptCookies::class,             \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,             \Illuminate\Session\Middleware\StartSession::class,             // \Illuminate\Session\Middleware\AuthenticateSession::class,            \Illuminate\View\Middleware\ShareErrorsFromSession::class,             \App\Http\Middleware\VerifyCsrfToken::class,             \Illuminate\Routing\Middleware\SubstituteBindings::class,         ],         'api' => [             'throttle:60,1',             'bindings',             \Illuminate\Session\Middleware\StartSession::class,         ],     ];由于群组路由中间件是在路由匹配过程之后才进入,因此之前实验中提及的OPTIONS请求尚未通过此处中间件的handle函数,就已经返回了。因此我们添加的中间件,需要添加到$middleware数组中,不能添加到api群组路由中间件中。在app/Http/Middleware文件夹下新建PreflightResponse.php文件:<?phpnamespace App\Http\Middleware;use Closure;class PreflightResponse{     /**     * Handle an incoming request.     *     * @param  \Illuminate\Http\Request  $request     * @param  \Closure  $next     * @param  string|null  $guard     * @return mixed     */    public function handle($request, Closure $next, $guard = null)    {         if($request->getMethod() === 'OPTIONS'){             $origin = $request->header('ORIGIN', '*');             header("Access-Control-Allow-Origin: $origin");             header("Access-Control-Allow-Credentials: true");             header('Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE');             header('Access-Control-Allow-Headers: Origin, Access-Control-Request-Headers, SERVER_NAME, Access-Control-Allow-Headers, cache-control, token, X-Requested-With, Content-Type, Accept, Connection, User-Agent, Cookie, X-XSRF-TOKEN');         }         return $next($request);     } }其中这里针对OPTIONS请求的处理内容是添加多个header内容,可根据实际需要修改相关处理逻辑:$origin = $request->header('ORIGIN', '*'); header("Access-Control-Allow-Origin: $origin"); header("Access-Control-Allow-Credentials: true"); header('Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE'); header('Access-Control-Allow-Headers: Origin, Access-Control-Request-Headers, SERVER_NAME, Access-Control-Allow-Headers, cache-control, token, X-Requested-With, Content-Type, Accept, Connection, User-Agent, Cookie, X-XSRF-TOKEN');至此,所有OPTIONS方式的HTTP请求都得到了相关处理。3.2 通配路由匹配方案如果不使用中间件,查询Laravel官方文档Routing,可知如何在路由中使用正则表达式进行模式匹配。Route::get('user/{id}/{name}', function ($id, $name) {     //})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);类似的,可以撰写针对OPTIONS类型请求的泛化处理路由条件:Route::options('/{all}', function(Request $request) {      return response('options here!'); })->where(['all' => '([a-zA-Z0-9-]|/)+']);*注:这里正则表达式中不能使用符号*因此,针对跨域问题,对于OPTIONS方式的请求可以撰写如下路由响应:Route::options('/{all}', function(Request $request) {     $origin = $request->header('ORIGIN', '*');     header("Access-Control-Allow-Origin: $origin");     header("Access-Control-Allow-Credentials: true");     header('Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE');     header('Access-Control-Allow-Headers: Origin, Access-Control-Request-Headers, SERVER_NAME, Access-Control-Allow-Headers, cache-control, token, X-Requested-With, Content-Type, Accept, Connection, User-Agent, Cookie'); })->where(['all' => '([a-zA-Z0-9-]|/)+']);关于Laravel中处理OPTIONS请求的原理是什么问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注辰讯云资讯频道了解更多相关知识。...

Android中View绘制流程的原理是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。setContentView流程setContentView整个过程主要是如何把Activity的布局文件或者java的View添加至窗口里,重点概括为:创建一个DecorView的对象mDecor,该mDecor对象将作为整个应用窗口的根视图。依据Feature等style theme创建不同的窗口修饰布局文件,并且通过findViewById获取Activity布局文件该存放的地方(窗口修饰布局文件中id为content的FrameLayout)。将Activity的布局文件添加至id为content的FrameLayout内。当setContentView设置显示OK以后会回调Activity的onContentChanged方法。Activity的各种View的findViewById()方法等都可以放到该方法中,系统会帮忙回调。android的View绘制view绘制主要包括三个方面:measure 测量组件本身的大小layout 确定组件在视图中的位置draw 根据位置和大小,将组件画出来视图绘制的起点在ViewRootImpl类的performTraversals()方法,该方法完成的工作主要是: 根据之前的状态,判定是否重新计算测试视图大小(measure)、是佛重新放置视图位置(layout)和是否重新重绘视图(draw) ,部分源码如下:private void performTraversals() {         ......        //最外层的根视图的widthMeasureSpec和heightMeasureSpec由来        //lp.width和lp.height在创建ViewGroup实例时等于MATCH_PARENT        int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);        int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);         ......         mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);         ......         mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());         ......         mView.draw(canvas);         ......     }measure计算视图大小几乎所有的组件都是继承View类的,而关于view的测量工作,日常开发用得多的方法就是measure和onMeasure两个方法,measure不可重写,当我们自定义时主要重写onMeasure方法即可,在方法内部我们必须完成组件的mMeasuredWidth和mMeasuredHeight实际尺寸测量,而这个尺寸是需要父视图和子视图共同决定的measure流程从根视图measure遍历整个view树结构,如下:这里写图片描述还要注意视图尺寸MeasureSpec是一个组合尺寸,它是一个32位bit值,高两位是尺寸模式specMode,低30位是尺寸大小值,我们可以利用提供的原声库方法很方便的进行尺寸组合和拆解:specMode有三种: MeasureSpec.EXACTLY表示确定大小, MeasureSpec.AT_MOST表示最大大小, MeasureSpec.UNSPECIFIED不确定int measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);    //合成int specMode = MeasureSpec.getMode(measureSpec);                                   //拆解int specSize = MeasureSpec.getSize(measureSpec);而在视图测量meause中,父组件传给子组件的一般都是一个组合尺寸,我们可以拿出具体尺寸然后根据其他条件产生一个新的尺寸值,将这个值用setMeasuredDimension设置mMeasuredWidth和mMeasuredHeight具体尺寸,完成测量;measure原理总结MeasureSpec(View的内部类)测量规格为int型,值由高2位规格模式specMode和低30位具体尺寸specSize组成。其中specMode只有三种值:MeasureSpec.EXACTLY //确定模式,父View希望子View的大小是确定的,由specSize决定;MeasureSpec.AT_MOST //最多模式,父View希望子View的大小最多是specSize指定的值;MeasureSpec.UNSPECIFIED //未指定模式,父View完全依据子View的设计值来决定;View的measure方法是final的,不允许重载,View子类只能重载onMeasure来完成自己的测量逻辑。最顶层DecorView测量时的MeasureSpec是由ViewRootImpl中getRootMeasureSpec方法确定的(LayoutParams宽高参数均为MATCH_PARENT,specMode是EXACTLY,specSize为物理屏幕大小)。ViewGroup类提供了measureChild,measureChild和measureChildWithMargins方法,简化了父子View的尺寸计算。只要是ViewGroup的子类就必须要求LayoutParams继承子MarginLayoutParams,否则无法使用layout_margin参数。View的布局大小由父View和子View共同决定。使用View的getMeasuredWidth()和getMeasuredHeight()方法来获取View测量的宽高,必须保证这两个方法在onMeasure流程之后被调用才能返回有效值。layout视图位置确定layout的流程主要也是遍历整个view树结构,调用view.layout(int l, int t, int r, int b)确定好view的具体坐标位置,流程图如下这里写图片描述当我们自定义一个组件时,通常时重写onLayout方法,里面实现好自己的逻辑,最后在调用layout方法完成视图位置确定,如果自定义组件时一个ViewGroup的话,还需要我们去遍历每一个child确定尺寸layout原理总结整个layout过程比较容易理解,从上面分析可以看出layout也是从顶层父View向子View的递归调用view.layout方法的过程,即父View根据上一步measure子View所得到的布局大小和布局参数,将子View放在合适的位置上。具体layout核心主要有以下几点:View.layout方法可被重载,ViewGroup.layout为final的不可重载,ViewGroup.onLayout为abstract的,子类必须重载实现自己的位置逻辑。measure操作完成后得到的是对每个View经测量过的measuredWidth和measuredHeight,layout操作完成之后得到的是对每个View进行位置分配后的mLeft、mTop、mRight、mBottom,这些值都是相对于父View来说的。凡是layout_XXX的布局属性基本都针对的是包含子View的ViewGroup的,当对一个没有父容器的View设置相关layout_XXX属性是没有任何意义的(前面《Android应用setContentView与LayoutInflater加载解析机制源码分析》也有提到过)。使用View的getWidth()和getHeight()方法来获取View测量的宽高,必须保证这两个方法在onLayout流程之后被调用才能返回有效值。draw绘制完成measure和Layout后,ViewRootImpl中的代码会创建一个Canvas对象,然后调用View的draw()方法来执行具体的绘制工。所以又回归到了ViewGroup与View的树状递归draw过程先来看下View树的递归draw流程图,如下:这里写图片描述draw原理总结可以看见,绘制过程就是把View对象绘制到屏幕上,整个draw过程需要注意如下细节:如果该View是一个ViewGroup,则需要递归绘制其所包含的所有子View。View默认不会绘制任何内容,真正的绘制都需要自己在子类中实现。View的绘制是借助onDraw方法传入的Canvas类来进行的。区分View动画和ViewGroup布局动画,前者指的是View自身的动画,可以通过setAnimation添加,后者是专门针对ViewGroup显示内部子视图时设置的动画,可以在xml布局文件中对ViewGroup设置layoutAnimation属性(譬如对LinearLayout设置子View在显示时出现逐行、随机、下等显示等不同动画效果)。在获取画布剪切区(每个View的draw中传入的Canvas)时会自动处理掉padding,子View获取Canvas不用关注这些逻辑,只用关心如何绘制即可。默认情况下子View的ViewGroup.drawChild绘制顺序和子View被添加的顺序一致,但是你也可以重载ViewGroup.getChildDrawingOrder()方法提供不同顺序。view提供的API控制视图的方法invalidate和postInvalidate方法源码分析请求重新绘制视图,调用drawinvalidate在主线程调用postInvalidate是在非主线程调用View的requestLayout方法requestLayout()方法会调用measure过程和layout过程,不会调用draw过程,也不会重新绘制任何View包括该调用者本身。看完上述内容,你们掌握Android中View绘制流程的原理是什么的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注辰讯云资讯频道,感谢各位的阅读!...

今天就跟大家聊聊有关Redis主从复制的原理是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。主从复制的作用为数据提供多个副本,实现高可用实现读写分离(主节点负责写数据,从节点负责读数据,主节点定期把数据同步到从节点保证数据的一致性)主从复制的方式命令slaveof。优点:无需重启。缺点:不便于管理// 命令行使用slaveof ip port // 使用命令后自身数据会被清空,但取消slave只是停止复制,并不清空修改配置。优点:统一配置。缺点:需要重启// 配置文件中配置slaveof ip portslave-read-only yes //只允许从节点进行读操作全量复制用于初次复制或其它无法进行部分复制的情况,将主节点中的所有数据都发送给从节点,是一个非常重型的操作,当数据量较大时,会对主从节点和网络造成很大的开销全量复制过程:Redis内部会发出一个同步命令,刚开始是Psync命令,Psync ? -1表示要求master主机同步数据主机会向从机发送run_id和offset,因为slave并没有对应的 offset,所以是全量复制从机slave会保存主机master的基本信息主节点收到全量复制的命令后,执行bgsave(异步执行),在后台生成RDB文件(快照),并使用一个缓冲区(称为复制缓冲区)记录从现在开始执行的所有写命令主机发送RDB文件给从机发送缓冲区数据刷新旧的数据。从节点在载入主节点的数据之前要先将老数据清除加载RDB文件将数据库状态更新至主节点执行bgsave时的数据库状态和缓冲区数据的加载。全量复制开销主节点需要bgsaveRDB文件网络传输占用网络io从节点要清空数据从节点加载RDB全量复制会触发从节点AOF重写部分复制部分复制是Redis 2.8以后出现的,用于处理在主从复制中因网络闪断等原因造成的数据丢失场景,当从节点再次连上主节点后,如果条件允许,主节点会补发丢失数据给从节点。因为补发的数据远远小于全量数据,可以有效避免全量复制的过高开销,需要注意的是,如果网络中断时间过长,造成主节点没有能够完整地保存中断期间执行的写命令,则无法进行部分复制,仍使用全量复制部分复制过程:如果网络抖动(连接断开 connection lost)主机master 还是会写 repl_back_buffer(复制缓冲区)从机slave 会继续尝试连接主机从机slave 会把自己当前 run_id 和偏移量传输给主机 master,并且执行 pysnc 命令同步如果master发现你的偏移量是在缓冲区的范围内,就会返回 continue命令同步了offset的部分数据,所以部分复制的基础就是偏移量 offset。服务器运行ID(run_id):每个Redis节点(无论主从),在启动时都会自动生成一个随机ID(每次启动都不一样),由40个随机的十六进制字符组成;run_id用来唯一识别一个Redis节点。 通过info server命令,可以查看节点的run_id。开发运维常见的问题读写分离复制数据存在延迟(如果从节点发生阻塞)从节点可能发生故障主从配置不一致例如maxmemory不一致,可能会造成丢失数据例如数据结构优化参数不一致:造成主从内存不一致规避全量复制第一次全量复制不可避免,所以分片的maxmemory减小,同时选择在低峰(夜间)时,做全量复制。复制积压缓冲区不足 增大复制缓冲区配置rel_backlog_size例如:如果网络中断的平均时间是60s,而主节点平均每秒产生的写命令(特定协议格式)所占的字节数为100KB,则复制积压缓冲区的平均需求为6MB,保险起见,可以设置为12MB,来保证绝大多数断线情况都可以使用部分复制。复制风暴 master节点重启,master节点生成一份rdb文件,但是要给所有从节点发送rdb文件。对cpu,内存,带宽都造成很大的压力看完上述内容,你们对Redis主从复制的原理是什么有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注辰讯云资讯频道,感谢大家的支持。...

JDK动态代理的原理是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。JDK动态代理使用与原理底层解析java对设计模式--代理模式的实现,只能针对接口进行代理。代理模式:提供一个代理对象来持有目标对象的引用,通过对代理对象的操作可以达到操作目标对象的目的。使用代理模式主要是使用者不想或者不能直接操作目标对象,需要一个代理的中间对象来维持联系。例如Mybatis中Mapper接口并没有实现类,因此使用者不能直接操作实现类,所以会产生一个代理Mapper。又例如Spring AOP中的Bean,使用者想对Bean的使用进行增强或者其他处理,于是Spring需要返回一个的代理Bean来完成目的。一接口:public interface ITodo {     void doString(String desc); }一实现:public class Todo implements ITodo {     @Override    public void doString(String desc) {         System.out.println("doString: " + desc);     } }目标,对接口的原有方法进行增强。实现方式:JDK动态代理一代理工具类:public class ProxyInstance implements InvocationHandler {     // 代理目标,即被代理类    private Object target;     // 代理类持有被代理类     public ProxyInstance(Object target) {         this.target = target;     }     public <T> T getProxy(){         // 获取实例方式,这里使用newProxyInstance        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);     }     // 这里为代理的处理流程    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {         System.out.println("proxy before");         Object obj=method.invoke(target,args);         System.out.println("proxy after");         return obj;     } }测试类:public class Test {    public static void main(String[] args) {         // 开启保存代理中生成文件的代码        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");         ITodo todo = new ProxyInstance(new Todo()).getProxy();         todo.doString("------ nothing-------- ");     } }控制台:proxy before doString: ------ nothing-------- proxy after通过控制台就可以看到接口原有的方法被增强了,方法执行之前和执行之后执行其他代码。这就是JDK的动态代理功能。JDK动态代理的使用组件:一接口、一实现、一代理工具类,并且需要遵循以下规则:代理工具类持有目标类作为参数传入代理工具类需要实现接口InvocationHandler代理类需要使用Proxy的构造方法获取实例一般使用newProxyInstance定义代理处理逻辑用于通过反射生成代理类的方法因此只能代理接口中已定义的方法接口的所有方法都会被重写为final类型用于加载新生成的代理类$Proxy{n}参数1: 类加载器参数2: 接口Class数组参数3: InvocationHandler接口实现类构造参数为被代理类实现的接口代理类调用的对象是Proxy类产生的实例,与被代理类不是一个对象每次调用都需要通过反射来调用代理工具类需要重写invoke方法public Object invoke(Object proxy, Method method, Object[] args)proxy为JDK生成的代理对象$Proxy{n}对象,因此是动态的,只存在于内存中Method为JDK例如反射获取的调用方法args为调用方法的参数因为该类是生成的,所有需要类加载器从新加载底层原理分析对上面的示例,查看其生成的代理类源码如下package com.sun.proxy;import cn.tinyice.demo.proxy.jdk.ITodo;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;// 代理对象集成java.lang.reflect.Proxy并实现了被代理对象的父接口// 这里调整了方法位置,便于分析public final class $Proxy0 extends Proxy implements ITodo {     private static Method m1;     private static Method m2;     private static Method m3;     private static Method m0;    static {         // 需要对接口的equals、toString、hashCode和 目标方法进行重写,因此先获取原方法的运行时表示java.lang.reflect.Method        try {             m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));             m2 = Class.forName("java.lang.Object").getMethod("toString");             m3 = Class.forName("cn.tinyice.demo.proxy.jdk.ITodo").getMethod("doString", Class.forName("java.lang.String"));             m0 = Class.forName("java.lang.Object").getMethod("hashCode");         } catch (NoSuchMethodException var2) {             throw new NoSuchMethodError(var2.getMessage());         } catch (ClassNotFoundException var3) {             throw new NoClassDefFoundError(var3.getMessage());         }     }     // 构造器入参:InvocationHandler实例即代理类实例    public $Proxy0(InvocationHandler var1) throws  {         //  判断InvocationHandler不为空,然后赋给变量h        super(var1);     }       // ----------------------------------------- 代理主要关注点: 目标方法 重写 ------------------------    public final void doString(String var1) throws  {         try {             //  super.h=InvocationHandler实例,调用其invoke方法,该方法为用户重写的方法           // 三个参数来源确定: proxy=this,method = target的method,args=参数的Object数组(发生类型转换)            super.h.invoke(this, m3, new Object[]{var1});         } catch (RuntimeException | Error var3) {             throw var3;         } catch (Throwable var4) {             throw new UndeclaredThrowableException(var4);         }     }     // ----- equals、toString、hashCode 重写,实质调用 InvocationHandler的对应方法-------    public final boolean equals(Object var1) throws  {         try {             return (Boolean)super.h.invoke(this, m1, new Object[]{var1});         } catch (RuntimeException | Error var3) {             throw var3;         } catch (Throwable var4) {             throw new UndeclaredThrowableException(var4);         }     }     public final String toString() throws  {         try {             return (String)super.h.invoke(this, m2, (Object[])null);         } catch (RuntimeException | Error var2) {             throw var2;         } catch (Throwable var3) {             throw new UndeclaredThrowableException(var3);         }     }     public final int hashCode() throws  {         try {             return (Integer)super.h.invoke(this, m0, (Object[])null);         } catch (RuntimeException | Error var2) {             throw var2;         } catch (Throwable var3) {             throw new UndeclaredThrowableException(var3);         }     } }源码部分主要分为四部分代理类定义:新生成的代理类定义为:public final class $Proxy0 extends Proxy implements ITodo {...},就是重新生成一个新的接口实现类,对原有实现类进行功能复制、增强。静态块初始化equals、hashCode、toString和原有实现类的方法equals、hashCode、toString这三个方法是Object方法,主要是验证Java对象的唯一性,与原来的实现类已经不是一个内存地址了以及其他操作。doString是原有实现类的方法构造方法传入InvocationHandlerInvocationHandler就是使用者编写的代码,这一步就是切入重写静态块中定义的所有方法所有被重写的方法都变为了final类型。所有的方法都调用了InvocationHandler的invoke方法。因此这个invoke方法就是增强的核心方法。了解以上内容基本可以知道JDK动态代理的底层原理了。一句话:重写方法调用自定义的invoke来实现增强源码生成流程调用入口:获取代理类public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { ... }核心代吗Class<?> cl = getProxyClass0(loader, intfs);↓proxyClassCache.get(loader, interfaces)proxyClassCache在Proxy类中静态定义private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());proxyClassCache说明:WeakCache实例,一个弱引用缓存对象。存储结构如下,是 K,P,V三个对象存储ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map = new ConcurrentHashMap<>();该对象需要2个工厂类,一个用于生成subKey,一个用于生成valueKeyFactory、ProxyClassFactory 均为BiFunction<ClassLoader, Class<?>[], Object>,具有apply方法获取时和常规缓存使用方式一致,先通过key从缓存Map中获取,获取不到就去生成ConcurrentMap<Object, Supplier<V>。首次使用必是生成。Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); // 这里生成subKey用于缓存的keyfactory = new Factory(key, parameter, subKey, valuesMap); // 这个工厂是实现Supplier<V>Factory的get实现中调用valueFactory的apply即ProxyClassFactory // //#apply,并最终返回了valuevalue = Objects.requireNonNull(valueFactory.apply(key, parameter));subkey只是中间的关联变量,不需要关注,只需要关注value也就是代理类的生成。生成入口ProxyClassFactory#apply(ClassLoader loader, Class<?>[] interfaces)所有代理类的字节码定义都在该方法中:主要如下包名称确定:String proxyName = proxyPkg + proxyClassNamePrefix + num; // com.sun.proxy.+$Proxy+num --->com.sun.proxy.$Proxy0proxyPkg在接口的访问修饰符是public时=“com.sun.proxy“,否则=被代理类的包名proxyClassNamePrefix=”$Proxy“num为原子递增AtomicLong,与生成代理类的个数相关类字节码生成:接口访问修饰符 int accessFlags = Modifier.PUBLIC | Modifier.FINAL 即 public final非public接口会重写为final所有方法都是 public final类字节码文件生成:byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);类字节码加载到JVM:defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);此时新生成的代理类已经加载到JVM中去了类字节码文件生成代理字节码生成工具类 :ProxyGenerator// 是否生成文件属性读取private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {     // 构建对象    ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);     // 生成字节码    final byte[] var4 = var3.generateClassFile();     // 是否生成文件    if (saveGeneratedFiles) {         // 沙箱安全权限提升操作        AccessController.doPrivileged(new PrivilegedAction<Void>() {             public Void run() {                 try {                     int var1 = var0.lastIndexOf(46);                     Path var2;                     if (var1 > 0) {                         Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));                         Files.createDirectories(var3);                         var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");                     } else {                         var2 = Paths.get(var0 + ".class");                     }                     Files.write(var2, var4, new OpenOption[0]);                     return null;                 } catch (IOException var4x) {                     throw new InternalError("I/O exception saving generated file: " + var4x);                 }             }         });     }     return var4; } 字节码生成,忽略部分代码private byte[] generateClassFile() {     // equals、toString、hashCode 重写    this.addProxyMethod(hashCodeMethod, Object.class);     this.addProxyMethod(equalsMethod, Object.class);     this.addProxyMethod(toStringMethod, Object.class);     // 接口所有方法重写    Class[] var1 = this.interfaces;     int var2 = var1.length;     int var3;     Class var4;     for(var3 = 0; var3 < var2; ++var3) {         var4 = var1[var3];         Method[] var5 = var4.getMethods();         int var6 = var5.length;         for(int var7 = 0; var7 < var6; ++var7) {             Method var8 = var5[var7];             this.addProxyMethod(var8, var4);         }     }    // ... ignore ...}关于JDK动态代理的原理是什么问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注辰讯云资讯频道了解更多相关知识。...

如何使用私钥登录Linux系统,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Linux 系统系统如何使用私钥登录?Linux服务器每次都要输入负责的密码,为了方便、安全登录Linux服务器,使用私钥公钥来登录。生成ssh公钥密钥对:#ssh-keygen -t rsa-t? rsa? ? 是指采用rsa加密方式的公钥/私钥对。-b? ? ? ? ? ?是指公钥/私钥对的长度,一般为1024,2048。默认为2048字节。进入/root/.ssh目录下:# cat id_rsa.pub >> authorized_keys# chmod 600 authorized_keys下载私钥 id_rsa,这样,便可以通过私钥来免密登录服务器了!PS:配置文件/etc/ssh/sshd_config在测试中,#PasswordAuthentication yes#PermitEmptyPasswords no没有注释掉#,也能通过私钥登录。总结:在配置过程中,忘记cat id_rsa.pub >> authorized_keys,导致下载私钥之后也不能登录服务器。看完上述内容,你们掌握如何使用私钥登录Linux系统的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注辰讯云资讯频道,感谢各位的阅读!...