• 关于 如果实现类的自动加载 的搜索结果

回答

引用来自“罗格林”的评论 lombok和ActFramework都需要对字节码进行增强.不过字节码增强的时间是不同的.Lombok在编译时增强.ActFramework在加载类的时候增强.  上面的错误产生的原因是由于ActFramework直接调用ECJ在内存中编译源码,没有给Lombok提供增强字节码的机会(如果Lombok提供API的话也许以后可以写一个插件?),所以是找不到getAccessType()方法的. Act在一定层度上实现了Lombok的特性.比如如果PlanAccessEnum实现SimpleBean接口,Act会自动生成Getter/Setter方法.不过accessType一定要申明成public才行. lombok和ActFramework都需要对字节码进行增强.不过字节码增强的时间是不同的.Lombok在编译时增强.ActFramework在加载类的时候增强.    上面的错误产生的原因是由于ActFramework直接调用ECJ在内存中编译源码,没有给Lombok提供增强字节码的机会(如果Lombok提供API的话也许以后可以写一个插件?),所以是找不到getAccessType()方法的.   Act在一定层度上实现了Lombok的特性.比如如果PlanAccessEnum实现SimpleBean接口,Act会自动生成Getter/Setter方法.不过accessType一定要申明成public才行. 引用来自“罗格林”的评论 lombok和ActFramework都需要对字节码进行增强.不过字节码增强的时间是不同的.Lombok在编译时增强.ActFramework在加载类的时候增强.  上面的错误产生的原因是由于ActFramework直接调用ECJ在内存中编译源码,没有给Lombok提供增强字节码的机会(如果Lombok提供API的话也许以后可以写一个插件?),所以是找不到getAccessType()方法的. Act在一定层度上实现了Lombok的特性.比如如果PlanAccessEnum实现SimpleBean接口,Act会自动生成Getter/Setter方法.不过accessType一定要申明成public才行. 引用来自“罗格林”的评论 lombok和ActFramework都需要对字节码进行增强.不过字节码增强的时间是不同的.Lombok在编译时增强.ActFramework在加载类的时候增强.  上面的错误产生的原因是由于ActFramework直接调用ECJ在内存中编译源码,没有给Lombok提供增强字节码的机会(如果Lombok提供API的话也许以后可以写一个插件?),所以是找不到getAccessType()方法的. Act在一定层度上实现了Lombok的特性.比如如果PlanAccessEnum实现SimpleBean接口,Act会自动生成Getter/Setter方法.不过accessType一定要申明成public才行.

爱吃鱼的程序员 2020-06-08 16:18:03 0 浏览量 回答数 0

回答

这个类实现了 DisposableBean 接口 如果它作为 Spring 的一个 Bean 被加载的话 当 Spring 容器 shutdown 的时候也就自动销毁了 如果是手动new 初始化的 就需要手动shutdown

a123456678 2019-12-02 02:14:34 0 浏览量 回答数 0

回答

先回答你的问题:用户点击了home键,过了一会儿后,再次点击app返回,那么我的图片加载线程与后台访问线程会发生什么事情,貌似图片是加载不出来的,这是为什么,如何解决?点击 home 键后,后台加载图片就停止了,如果你没有实现苹果提供的几个方法,重新进入应用是不会自动开始的,你要自己实现相关的方法。具体见下文。下文提到了 iOS 的应用里的几种状态:active: 应用在前台正常运行background: 应用在后台,并且在执行代码。inactive: 这个状态是应用从一个状态向另一个状态的过渡suspended: 应用在后台,但不执行代码。应用留在内存里,但随时可能被系统清除。进入这个状态系统不会通知应用。应用根据执行的任务不同分为两类:需要执行特殊的后台任务(播放音频、定位等)应用允许后台运行,这些应用在用户按下 Home 键后会进入 background 状态继续运行。其它应用在按下 Home 键后短暂地进入 inactive 状态,然后紧接着就进入 background 状态。这时候系统会通知你,并且有几秒钟时间来做 clean-up。然后应用就会进入 suspended 状态。当再次进入你的应用的时候(进入 active 状态),取决于你的应用之前的状态,如果之前是 background 状态,你将有机会重新启动在进入 background 状态时被暂停的任务,其它情况下均相当于重新启动应用。我假设你的应用是第二种,你需要做的就是在从 active 进入 background 状态时保存数据,记录下应用状态信息,并且释放尽可能多的空间;在从 background 进入 active 的时候接着执行之前的任务。有两种方式:实现回调函数应用在状态之间转换的时候,会自动调用几个相关的方法,你可以在这些方法里做数据保存之类的事情,这些方法包括:applicationWillResignActive:(这个方法在应用即将进入 background 状态时被调用)、applicationDidEnterBackground:(这个方法在应用进入 background 状态后被调用,这个状态下应用会随时进入 suspended 状态)、applicationWillEnterForeground:(这个方法在从 background 进入 active 状态时被调用)。applicationDidEnterBackground: 这个方法是你需要的方法,需要注意的是系统只提供大约 5 秒的时间让你完成工作,超时的话这个方法会被系统强制返回,如果需要更多的处理时间,可以调用 beginBackgroundTaskWithExpirationHandler: 这个方法来申请更多的运行时间,它会在后台线程执行,这个方法也只有有限的时间处理清理工作。详细用法看文档吧。监听通知应用在状态之间转换的时候,会发送通知,你可以在相关的类里面注册监听这几个通知来做上面说的那些事情。

a123456678 2019-12-02 03:13:14 0 浏览量 回答数 0

新用户福利专场,云服务器ECS低至96.9元/年

新用户福利专场,云服务器ECS低至96.9元/年

回答

UIView控件只是一个矩形的空白区域,并没有任何内容。iOS应用的其他UI控件都继承了UIView,这些UI控件都是在UIView提供的空白区域上绘制外观。 基于UI控件的实现原理,开发者完全可以开发出项目定制的控件——当iOS系统提供的UI控件不足以满足项目需要时,开发者可以通过继承UIView来派生自定义控件。 当开发者打算派生自己的UI控件时,首先定义一个继承View基类的子类,然后重写View类的一个或多个方法,通常可以被用户重写的方法如下。 Ø initWithFrame::前面已经见到,程序创建UI控件时常常会调用该方法执行初始化,因此,如果你需要对UI控件执行一些额外的初始化,即可通过重写该方法来实现。 Ø initWithCoder::程序通过在nib文件中加载完该控件后会自动调用该方法。因此,如果程序需要在nib文件中加载该控件后执行自定义初始化,则可通过重写该方法来实现。 Ø drawRect::如果程序需要自行绘制该控件的内容,则可通过重写该方法来实现。 Ø layoutSubviews:如果程序需要对该控件所包含的子控件布局进行更精确的控制,可通过重写该方法来实现。 Ø didAddSubview::当该控件添加子控件完成时,将会激发该方法。 Ø willRemoveSubview::当该控件将要删除子控件时,将会激发该方法。 Ø willMoveToSuperview::当该控件将要添加到其父控件中时,将会激发该方法。 Ø didMoveToSuperview:当把该控件添加到父控件完成时,将会激发该方法。 Ø willMoveToWindow: :当该控件将要添加到窗口中时,将会激发该方法。 Ø didMoveToWindow:当把该控件添加到窗口完成时,将会激发该方法。 Ø touchesBegan:withEvent::当用户手指开始触碰该控件时,将会激发该方法。 Ø touchesMoved:withEvent::当用户手指在该控件上移动时,将会激发该方法。 Ø touchesEnded:withEvent::当用户手指结束触碰该控件时,将会激发该方法。 Ø touchesCancelled:withEvent::用户取消触碰该控件时,将会激发该方法。 当需要开发自定义View时,开发者并不需要重写上面列出的所有方法,而是根据业务需要重写上面的部分方法。例如,下面的跟随手指运动的小球示例程序就只重写drawRect:方法。 实例:跟随手指运动的小球 为了实现一个跟随手指运动的小球示例,我们考虑开发自定义的UI控件,这个UI控件将会在指定位置绘制一个小球,这个位置可以动态改变。当用户通过手指在屏幕上拖动时,程序监听到这个手指动作,并把手指动作的位置传入自定义UI控件,然后通知该控件重绘即可。 首先创建一个Single View Application,然后通过该应用的项目导航面板打开Main.storyboard文件,选中Dock区内唯一场景内的View Controller节点,或选中界面布局文件中的根UI控件:UIView(也就是界面中大块的、右上角有个电池图标的白色矩形区域),然后按下键盘上的command+option+3快捷键,打开Xcode的身份检查器,通过身份检查器可以看到该界面布局文件的根UI控件的实现类是UIView,如图9.38所示。 该应用并不打算使用默认的UIView作为根控件,因此将图9.38所示对话框中Class文本框内的实现类改为FKCustomView,这表明程序将使用FKCustomView作为界面设计的根控件。 接下来程序需要开发自定义的FKCustomView类,其步骤如下。 ①用鼠标右键单击项目文件夹,然后单击“New File”菜单项,Xcode弹出如图9.39所示的对话框。

杨冬芳 2019-12-02 03:01:21 0 浏览量 回答数 0

问题

Java基础

游客pklijor6gytpx 2019-12-01 22:02:53 69 浏览量 回答数 1

回答

一、 Afinal官方介绍:Afinal是一个Android的ioc,orm框架,内置了四大模块功能:FinalAcitivity,FinalBitmap,FinalDb,FinalHttp。通过finalActivity,我们可以通过注解的方式进行绑定ui和事件。通过finalBitmap,我们可以方便的加载bitmap图片,而无需考虑oom等问题。通过finalDB模块,我们一行代码就可以对android的sqlite数据库进行增删改查。通过FinalHttp模块,我们可以以ajax形式请求http数据。详情请通过以下网址查看。Afinal 是一个android的sqlite orm 和 ioc 框架。同时封装了android中的http框架,使其更加简单易用;使用finalBitmap,无需考虑bitmap在android中加载的时候oom的问题和快速滑动的时候图片加载位置错位等问题。Afinal的宗旨是简洁,快速。约定大于配置的方式。尽量一行代码完成所有事情。项目地址:https://github.com/yangfuhai/afinal功能:一个android的ioc,orm框架,内置了四大模块功能:FinalAcitivity,FinalBitmap,FinalDb,FinalHttp。通过finalActivity,我们可以通过注解的方式进行绑定ui和事件。通过finalBitmap,我们可以方便的加载bitmap图片,而无需考虑oom等问题。通过finalDB模块,我们一行代码就可以对android的sqlite数据库进行增删改查。通过FinalHttp模块,我们可以以ajax形式请求http数据。优点:功能比较全面,文档完善,代码效率比较高。缺点:没有项目demo,框架的时间比较久,代码冗余比较多(这也是无可避免的),文档比较老跟不上代码更新进度。(这个评价是其他高人评的,他自己也有写了框架。我个人觉得以前Afinal算是经典了 用的人多)。二、 xUtilsGit地址:https://github.com/wyouflf/xUtilsxUtils:可以说是Afinal的升级版。xUtils 包含了很多实用的android工具。xUtils 支持大文件上传,更全面的http请求协议支持(10种谓词),拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响...xUitls 最低兼容android 2.2 (api level 8)三、 ThinkAndroid项目地址:https://github.com/white-cat/ThinkAndroid官方介绍:ThinkAndroid是一个免费的开源的、简易的、遵循Apache2开源协议发布的Android开发框架,其开发宗旨是简单、快速的进行Android应用程序的开发,包含Android mvc、简易sqlite orm、ioc模块、封装Android httpclitent的http模块,具有快速构建文件缓存功能,无需考虑缓存文件的格式,都可以非常轻松的实现缓存,它还基于文件缓存模块实现了图片缓存功能,在android中加载的图片的时候,对oom的问题,和对加载图片错位的问题都轻易解决。他还包括了一个手机开发中经常应用的实用工具类,如日志管理,配置文件管理,android下载器模块,网络切换检测等等工具优点:功能看起来比较完善。个人觉得名字起的好。缺点:从2013年就停止维护了,没有项目文档。四、 LoonAndroid官方介绍:如果你想看ui方面的东西,这里没有,想要看牛逼的效果这里也没有。这只是纯实现功能的框架,它的目标是节省代码量,降低耦合,让代码层次看起来更清晰。整个框架一部分是网上的,一部分是我改的,为了适应我的编码习惯,还有一部分像orm完全是网上的组件。在此感谢那些朋友们。 整个框架式的初衷是为了偷懒,之前都是一个功能一个jar,做项目的时候拉进去,这样对于我来说依然还是比较麻烦。最后就导致我把所有的jar做成了一个工具集合包。 有很多框架都含有这个工具集合里的功能,这些不一定都好用,因为这是根据我个人使用喜欢来实现的,如果你们有自己的想法,可以自己把架包解压了以后,源码拉出来改动下。 目前很多框架都用到了注解,除了androidannotations没有入侵我们应用的代码以外,其他的基本上都有,要么是必须继承框架里面的activity,要么是必须在activity的oncreat里面调用某个方法。 整个框架式不同于androidannotations,Roboguice等ioc框架,这是一个类似spring的实现方式。在整应用的生命周期中找到切入点,然后对activity的生命周期进行拦截,然后插入自己的功能。开源地址:https://github.com/gdpancheng/LoonAndroid功能:1自动注入框架(只需要继承框架内的application既可)2图片加载框架(多重缓存,自动回收,最大限度保证内存的安全性)3网络请求模块(继承了基本上现在所有的http请求)4 eventbus(集成一个开源的框架)5验证框架(集成开源框架)6 json解析(支持解析成集合或者对象)7 数据库(不知道是哪位写的 忘记了)8 多线程断点下载(自动判断是否支持多线程,判断是否是重定向)9 自动更新模块10 一系列工具类有点:功能多缺点:文档方面五、 KJFrameForAndroid项目地址:https://github.com/kymjs/KJFrameForAndroid官方介绍:KJFrameForAndroid 又叫KJLibrary,是一个android的orm 和 ioc 框架。同时封装了android中的Bitmap与Http操作的框架,使其更加简单易用;KJFrameForAndroid的设计思想是通过封装Android原生SDK中复杂的复杂操作而达到简化Android应用级开发,最终实现快速而又安全的开发APP。我们提倡用最少的代码,完成最多的操作,用最高的效率,完成最复杂的功能。功能:一个android的orm 和 ioc 框架。同时封装了android中的Bitmap与Http操作的框架,使其更加简单易用; KJFrameForAndroid开发框架的设计思想是通过封装Android原生SDK中复杂的复杂操作而达到简化Android应用级开发,最终实现快速而又安全的开发APP。总共分为五大模块:UILibrary,UtilsLibrary,HttpLibrary,BitmapLibrary,DBLibrary。优点:功能比较全面,代码效率很高,文档完善,有项目demo,出来的比较晚借鉴了很多大型框架经验。缺点:项目文档是html页面,查看起来很不方便,项目交流平台没多少人说话(难道大神都是不说话的?)(这两个评价是KJFrameForAndroid的作者对自己的评价,个人觉得作者是个天才。他的评价可能刚写完网上发布后写的。我在给他更新评价。因为现在已经过去了几个月一直在时不时更新。功能很全,项目文档也很全面,而且代码里注释最多 这方面这个很难得。交流平台人很多挺热闹,作者希望更热闹这样框架越来越完善。对于初学者希望看到Demo更完善)六、 dhroid官方介绍:dhroid 是基于android 平台, 极速开发框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展.使你更快,更好的开发商业级别应用开源地址: http://git.oschina.net/tengzhinei/dhroid功能:1.Ioc容器: (用过spring的都知道)视图注入,对象注入,接口注入,解决类依赖关系2.Eventbus: android平台事件总线框架,独创延时事件,事件管理轻松3.Dhnet: 网络http请求的解决方案,使用简单,减少代码,自带多种网络访问缓存策略4.adapter模块: 数据绑定轻松,不用写多余的adapter,天生网络支持(一行代码搞定加载,刷新问题)5.DhDb: android中sqlite的最轻量orm框架(增删改查轻松搞定)6.Perference: android自带Perference 升级版,让你的Perference更强大,更方便工具集合 JSONUtil(安全处理json),ViewUtil(数据绑定更快) ThreadWorker(异步任务工具)...优点:功能全面,有demo,作者也是为公司开发的框架。缺点:文档方面现在不是很好,就eoe上的那些。七、 SmartAndroid项目地址:http://www.aplesson.com/smartAndroid/demos官方介绍:SmartAndroid是一套给 Android开发者使用的应用程序开发框架和工具包。它提供一套丰富的标准库以及简单的接口和逻辑结构,其目的是使开发人员更快速地进行项目开发。使用 SmartAndroid可以减少代码的编写量,并将你的精力投入到项目的创造性开发上。功能:SmartAndroid 拥有全范围的类库,可以完成大多数通常需要的APP开发任务,包括: 异步网络操作相关所有功能、强大的图片处理操作、轻量级ORM数据库Sqlite库、zip操作 、动画特效、Html等解析采集、事件总线EventBus/Otto、Gson(Json)、AQuery、主流所有UI控件(例如:ActionbarSherlock,SlidingMenu,BottomView,Actionbar,DragListView等10多种UI库)等。优点:功能非常全,超出你索要、文档完善(作者很全面,官方网站是web响应式网站,框架里功能有UI各种特效应该最全了,一直更新中)缺点:jar包大点?(功能多不可避免,不是问题),在线文档(随响应式的手机访问也方便,但是网速慢就不好了,页面打开不是很流畅)八、 andBase官方介绍:andbase是为Android开发者量身打造的一款开源类库产品开源地址:https://code.jd.com/zhaoqp2010_m/andbase功能:1.andbase中包含了大量的开发常用手段。如网络下载,多线程与线程池的管理,数据库ORM,图片缓存管理,图片文件下载上传,Http请求工具,常用工具类(字符串,日期,文件处理,图片处理工具类等),能够使您的应用在团队开发中减少冗余代码,很大的提高了代码的维护性与开发高效性,能很好的规避由于开发疏忽而导致常犯的错误。2.andbase封装了大量的常用控件。如list分页,下拉刷新,图片轮播,表格,多线程下载器,侧边栏,图片上传,轮子选择,图表,Tab滑动,日历选择器等。3.强大的AbActivity,您没有理由不继承它。继承它你能够获得一个简单强大可设置的操作栏,以及一系列的简单调用,如弹出框,提示框,进度框,副操作栏等。4.提供效率较高图片缓存管理策略,使内存大幅度节省,利用率提高,效率提高。程序中要管理大量的图片资源,andbase提供简单的方法,几步完成下载与显示,并支持缩放,裁剪,缓存功能。5.封装了大量常见工具类。包括日期,字符,文件,图片等各种处理函数,多而全。6.用andbase大量减少handler的使用,而采用回调函数,代码更整洁。handler会产生大量代码,并且不好维护,andbase对handler进行了封装。7.简单轻量支持注解自动建表的ORM框架(支持一/多对多的关联操作)。写sql,建表,工作量大,andbase提供更傻瓜异步增删改查工具类。8.异步请求http框架,网络请求标准化,支持文件上传下载,get,post,进度显示。包含了异步与http请求的工具类,实用。9.热情的支持群体。优点:功能很全,demo做的好 、API文档完善、接近完美缺点:希望文档更详细些。九、 AndroidAnnotations项目地址:https://github.com/excilys/androidannotations功能:完全注解框架,一切皆为注解:声明控件,绑定控件,设置监听,setcontentview,长按事件,异步线程,全部通过注解实现。优点:完全的注解,使开发起来更加便利,程序员写的代码也更少。缺点:文档是全英文的加上功能比较少没有具体研究,由于一切都是注解,感觉效率不高,不过根据官方介绍说并不是使用的反射加载,所以效率比一般注解高很多。十、 volley项目地址: https://github.com/smanikandan14/Volley-demo功能:Volley是Android平台上的网络通信库,能使网络通信更快,更简单,更健壮异步加载网络图片、网络数据优点:Google官方推荐,请看去年的开发者大会介绍。缺点:功能比较少,只有网络数据加载和网络图片加载十一、 android-async-http项目地址:https://github.com/loopj/android-async-http文档介绍:http://loopj.com/android-async-http/ (1) 在匿名回调中处理请求结果 (2) 在UI线程外进行http请求 (3) 文件断点上传 (4) 智能重试 (5) 默认gzip压缩 (6) 支持解析成Json格式 (7) 可将Cookies持久化到SharedPreferences 有点:很简单很实用缺点:功能比较少, (只是针对的功能不是什么缺点)最后来个总结吧: 以上的开发框架网上都可以下载源码,也有demo实例的。当然我没分析和对比框架的效率性能,但是都非常实用,其作者大部分是个人,都是些牛人或天才。你可以直接使用,也可以把有用跳出来用,至少有很多使用工具。如果有发现Bug,作者希望把bug交给他。 Afinal 和 xUtils简单实用但是demo和更新的问题。 KJFrameForAndroid 算是新出的,功能也多,效率也应该好,代码也注释多 用起来也很方便。Dhroid 作者自己公司的框架,也可以直接请教。SmartAndroid 强劲的框架功能俱全。andBase 出来早各个方面算是完整的吧。转自:http://blog.csdn.net/buddyuu/article/details/40503471

元芳啊 2019-12-02 00:55:54 0 浏览量 回答数 0

回答

springboot 对新人来说可能上手比springmvc要快,但是对于各位从springmvc转战到springboot的话,有些地方还需要适应下,尤其是xml配置。我个人是比较喜欢注解➕xml是因为看着方便,查找方便,清晰明了。但是xml完全可以使用注解代替,今天就扒一扒springboot中事务使用注解的玩法。   springboot的事务也主要分为两大类,一是xml声明式事务,二是注解事务,注解事务也可以实现类似声明式事务的方法,关于注解声明式事务,目前网上搜索不到合适的资料,所以在这里,我将自己查找和总结的几个方法写到这里,大家共同探讨 springboot 之 xml事务 可以使用 @ImportResource("classpath:transaction.xml") 引入该xml的配置,xml的配置如下 <?xml version="1.0" encoding="UTF-8"?> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" ></property> </bean> <tx:advice id="cftxAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="query*" propagation="SUPPORTS" read-only="true" ></tx:method> <tx:method name="get*" propagation="SUPPORTS" read-only="true" ></tx:method> <tx:method name="select*" propagation="SUPPORTS" read-only="true" ></tx:method> <tx:method name="*" propagation="REQUIRED" rollback-for="Exception" ></tx:method> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="allManagerMethod" expression="execution (* com.exmaple.fm..service.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethod" order="0" /> </aop:config> springboot 启动类如下:package com.example.fm; import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.ImportResource; @ImportResource("classpath:transaction.xml")@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }启动后即可开启事务,不过项目里导入了xml配置,如果不想导入xml配置,可以使用注解的方式。 springboot 之 注解事务   注解事务讲解之前,需要先了解下spring创建代理的几个类,在spring内部,是通过BeanPostProcessor来完成自动创建代理工作的。BeanPostProcessor接口的实现只是在ApplicationContext初始化的时候才会自动加载,而普通的BeanFactory只能通过编程的方式调用之。根据 匹配规则的不同大致分为三种类别:     a、匹配Bean的名称自动创建匹配到的Bean的代理,实现类BeanNameAutoProxyCreator*Service testInterceptor b、根据Bean中的AspectJ注解自动创建代理,实现类AnnotationAwareAspectJAutoProxyCreator <aop:aspect ref="annotationAwareAspectJAutoProxyCreatorTest"> <aop:around method="process" pointcut="execution (* com.example.service.fm..*.*(..))"/> </aop:aspect> c、根据Advisor的匹配机制自动创建代理,会对容器中所有的Advisor进行扫描,自动将这些切面应用到匹配的Bean中,实现类DefaultAdvisorAutoProxyCreator

zwt9000 2019-12-02 00:20:32 0 浏览量 回答数 0

问题

【精品问答】Java必备核心知识1000+(附源码)

问问小秘 2019-12-01 22:00:28 870 浏览量 回答数 1

回答

PHP的编译并不是很耗时 我之前的文章也介绍过, PHP的编译是线性的编译过程, 不做任何优化, 所以这个过程非常之快. 而编译和执行分离这个特性的提出着认为分离以后, 可以省掉编译过程, 会有很大的性能提升开发速度 PHP的一个优点就是开发/部署/调试非常方案, 更改立即见效, 而如果我们采用了编译/执行分离以后, 那么更改就需要首先编译, 然后部署, 然后才能生效, 这对于开发来说, 并不是什么好事我们有APC/Zend O+等第三方的代码缓存工具 APC等第三方的代码缓存工具(Opcodes Cache)已经相对比较成熟, 并对开发者透明, 大家只要在服务器上安装了APC, 就可以得到编译/执行分离的性能提升. 比如编译/执行分离这个方案是有人在做的, 但是还不成熟等等 要实现编译和执行分离, 其实我们借助APC就能做到, APC提供了一族apc_bin_dump, apc_bin_load函数, 能把Opcodes缓存导出到外部文件中 经过我对apc_bin系列函数的重新梳理, 修复以后, 这部分功能现在终于可以正常工作了, 那么基于这些函数, 我们就可以实现编译执行分离 思路很简单, 在本地通过apc_bin_dumpfile把我们的php文件, 导出成bin文件, 然后在服务器上通过apc_bin_loadfile来读取这些bin文件. 就可以实现编译和执行分离啦, 一个简单的示意代码如下: $ find ./ -name "*.php" -exec php -r "apc_bin_dumpfile(array('{}'), array(), '{}' . '.bin');" \; 然后在服务器端的文件自动加载部分 <?php function __autoload($name) { /*首先计算出文件名字*/ $file = 根据类名得到PHP文件路径(); if (!file_exists($file)) { //文件不存在, 说明我们还没有load过, 那么创建一个空文件. file_put_contents($file, ''); apc_bin_loadfile($file . '.bin'); } else { //我们已经load过了, 理论上应该已经被服务器的APC缓存处理Cache住了. } include ($file); } 当然, 这里只是一个简单的示意, 如果要实际使用, 你还要考虑缓存被换出的可能, 那么一个解决方案就是设置俩个自动加载函数, 第一个如上, 第二个如果被调用, 就说明缓存被换出, 导致include了一个空文件, 于是就再次load一次bin文件就可以了 当然, 你也可以把所有的文件打包到一个bin文件中, 然后只load一次, 后续就交给服务器上的APC Cache来做就可以了. 但是这里有一个要注意的点就是, 那么对于这部分希望代码保护功能的人来说, 就可以使用APC来免费的完成这些事情了. 不过, 这个方案确实有点丑陋, 后续可以考虑在APC上增加直接对bin文件的支持. 

一枚小鲜肉帅哥 2020-05-31 20:56:17 0 浏览量 回答数 0

回答

配置管理可以分两块: 1.静态配置统一放在一个目录: res/default/ 默认配置 jdbc. properties web.properties xxx.properties res/dev 本地开发配置(dev配置会自动覆盖default配置) 作用:开发 测试 正式 可以分开管理 2.动态配置部分: 静态配置文件 一般改了之后要重新启服务,很多时候希望动态改变配置,不用重启就能生效。 1.JOB自动从DB加载对应配置项,动态改变static 配置变量值。 2.手工更新配置项。 如果觉得这个办法不错,可以采纳为答案,3Q ######手机不能搞。 回头设置哈######我尝试一下,看上出不错,哈哈######     jfinal 早就提供了 PropKit 支持你的需求,只需要将不同的配置分类存放在不同的配置文件中,然后使用PropKit.get(...)、PropKit.use("c1.txt").get(...) 、PropKit.use("c2.txt").get(...) 分别可以从默认配置、c1.txt配置、c2.txt 中获取参数。      配置放在数据库中通常用于需要动态改变配置,并且实时生效的应用场景,通常有相应的管理界面和功能来管理。而配置放在文件中通常用于系统启动前的固定配置,无需动态改变。所以视应用场景即可。 ######谢波总出招###### #Disconf#的思路非常赞:http://www.oschina.net/p/disconf 在大规模系统中会比我们单纯的配置文件要省心得多! ######@孤独的3 以前公司一个做运维的就常常管这些,这个好像不错,下次试试。######回复 @javagoboy : 不是,就是一个配置管理平台+插件的东西! 在那个管理平台上就能修改配置文件会同步到各个节点######回复 @小99 : 他是使用的Spring,最好是有个大牛有时间按照他这个整一个JFinal版本的!配置管理平台+一个插件######我看一下。 看看适不适合我,谢啦######这怎么像是运维要用的东西?###### 我们一般是这样分的 +config     +dev         +db.properties         +redis.properties         +xxx.properties     +release         +db.properties         +redis.properties         +xxx.properties 1.配置文件会单独放在一个源代码目录中 2.dev目录存放开发配置文件 release存放正式环境配置文件 如果你们公司有专门的测试还会有test这个目录 3.dev和release中的文件名是一模一样的,配置文件的key也是一抹一样的,值是不一样的 4.项目中抽象一个配置管理类来管理配置文件的加载,其实就是对PropKit的一次封装,在JFinalConfig中决定加载dev还是release ######我不知道这部分怎么写######4.项目中抽象一个配置管理类来管理配置文件的加载,其实就是对PropKit的一次封装,在JFinalConfig中决定加载dev还是release 这个能具体说下,怎么实现好一些

kun坤 2020-05-31 17:34:22 0 浏览量 回答数 0

回答

配置管理可以分两块: 1.静态配置统一放在一个目录: res/default/ 默认配置 jdbc. properties web.properties xxx.properties res/dev 本地开发配置(dev配置会自动覆盖default配置) 作用:开发 测试 正式 可以分开管理 2.动态配置部分: 静态配置文件 一般改了之后要重新启服务,很多时候希望动态改变配置,不用重启就能生效。 1.JOB自动从DB加载对应配置项,动态改变static 配置变量值。 2.手工更新配置项。 如果觉得这个办法不错,可以采纳为答案,3Q ######手机不能搞。 回头设置哈######我尝试一下,看上出不错,哈哈######     jfinal 早就提供了 PropKit 支持你的需求,只需要将不同的配置分类存放在不同的配置文件中,然后使用PropKit.get(...)、PropKit.use("c1.txt").get(...) 、PropKit.use("c2.txt").get(...) 分别可以从默认配置、c1.txt配置、c2.txt 中获取参数。      配置放在数据库中通常用于需要动态改变配置,并且实时生效的应用场景,通常有相应的管理界面和功能来管理。而配置放在文件中通常用于系统启动前的固定配置,无需动态改变。所以视应用场景即可。 ######谢波总出招###### #Disconf#的思路非常赞:http://www.oschina.net/p/disconf 在大规模系统中会比我们单纯的配置文件要省心得多! ###### @孤独的3 以前公司一个做运维的就常常管这些,这个好像不错,下次试试。######回复 @javagoboy : 不是,就是一个配置管理平台+插件的东西! 在那个管理平台上就能修改配置文件会同步到各个节点######回复 @小99 : 他是使用的Spring,最好是有个大牛有时间按照他这个整一个JFinal版本的!配置管理平台+一个插件######我看一下。 看看适不适合我,谢啦######这怎么像是运维要用的东西?###### 我们一般是这样分的 +config     +dev         +db.properties         +redis.properties         +xxx.properties     +release         +db.properties         +redis.properties         +xxx.properties 1.配置文件会单独放在一个源代码目录中 2.dev目录存放开发配置文件 release存放正式环境配置文件 如果你们公司有专门的测试还会有test这个目录 3.dev和release中的文件名是一模一样的,配置文件的key也是一抹一样的,值是不一样的 4.项目中抽象一个配置管理类来管理配置文件的加载,其实就是对PropKit的一次封装,在JFinalConfig中决定加载dev还是release ######我不知道这部分怎么写######4.项目中抽象一个配置管理类来管理配置文件的加载,其实就是对PropKit的一次封装,在JFinalConfig中决定加载dev还是release 这个能具体说下,怎么实现好一些

kun坤 2020-06-20 13:41:54 0 浏览量 回答数 0

回答

新地址 24题 Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成 Spring 及其他技术,而不需要到处找示例代码和依赖包。如你想使用 Spring JPA 访问数据库,只要加入 spring-boot-starter-data-jpa 启动器依赖就能使用了。Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。 23题 Spring Boot 的核心配置文件是application(.yml 或者 .properties) 和 bootstrap(.yml 或者 .properties) 配置文件。boostrap 由父 ApplicationContext 加载,比 applicaton 优先加载,boostrap 里面的属性不能被覆盖。application 配置文件主要用于 Spring Boot 项目的自动化配置。bootstrap 配置文件的应用场景:使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;一些固定的不能被覆盖的属性;一些加密/解密的场景。 22题 优点:快速构建项目;对主流开发框架的无配置集成;starters自动依赖与版本控制;大量的自动配置,简化开发,也可修改默认值;无需配置XML,无代码生成,开箱即用;项目可独立运行,无须外部依赖Servlet容器;提供运行时的应用监控;与云计算的天然集成。缺点:集成度较高,使用过程中不太容易了解底层。 21题 Spring Boot的初衷就是为了简化spring的配置,使得开发中集成新功能时更快,简化或减少相关的配置文件。Spring Boot其实是一个整合很多可插拔的组件(框架),内嵌了使用工具(比如内嵌了Tomcat、Jetty等),方便开发人员快速搭建和开发的一个框架。 20题 当程序创建对象、数组等引用类型实体时,系统会在堆内存中为之分配一块内存区,对象就保存在内存区中,不需要显式的去释放一个对象的内存,而是由虚拟机自行执行。在JVM 中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,标记那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。 19题 HashMap线程不安全,HashTable线程安全。HashMap允许有一个key为null,多个value为null;而HashTable不允许key和vale为null。继承类不一样,HashMap继承的是AbstractMap,HashTable继承的是Dictionary。初始容量不一样。使用的hashcode不一样。内部遍历方式的实现不一样。 18题 作用:内容可见性和禁止指令重排。内存可见性:某线程对 volatile 变量的修改,对其他线程都是可见的,即获取 volatile 变量的值都是最新的;禁止指令重排:重排序在单线程下一定能保证结果的正确性,但是在多线程环境下,可能发生重排序影响结果,若用volatile修饰共享变量,在编译时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。使用:当一个线程需要立刻读取到另外一个线程修改的变量值的时候,我们就可以使用volatile。区别:volatile是变量修饰符,而synchronized则作用于一段代码或者方法;volatile只是在线程内存和main memory(主内存)间同步某个变量的值,而synchronized通过锁定和解锁某个监视器同步所有变量的值。显然synchronized要比volatile消耗更多资源;synchronized 关键字可以保证变量原子性和可见性,volatile 不能保证原子性。 17题 非公平主要表现在获取锁的行为上,并非是按照申请锁的时间前后给等待线程分配锁的 ,每当锁被释放后 ,任何一个线程都有机会竞争到锁,这样做的目的是为了提高执行性能 ,缺点是可能会产生线程饥饿现象 。 16题 如果线程遇到了 IO 阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接接触到操作系统。如果线程因为调用 wait()、sleep()、或者 join()方法而导致的阻塞,可以中断线程,并且通过抛出 InterruptedException 来唤醒它。 15题 原子操作就是无法被别的线程打断的操作。要么不执行,要么就执行成功。在Java中可以通过锁和循环CAS的方式来实现原子操作。从JDK 1.5开始提供了java.util.concurrent.atomic包,这个包中的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式。 14题 wait()是Object类的方法,所以每一个对象能使用wait()方法。sleep()是Thread类中的静态方法。sleep不会释放锁,但会让出cpu,sleep会在指定的休眠时间后自动唤醒。wait则会释放锁,让出系统资源,并且加入wait set中,wait不会自动唤醒,而需要notify()或者notifyAll()唤醒。sleep和wait都可以被中断,使用sleep需要捕获异常。wait与notify、notifyAll只能在同步代码块中使用,而sleep可以在任何地方使用。 13题 Synchronized 是由 JVM 实现的一种实现互斥同步的一种方式,查看编译后的字节码,会发现被 Synchronized 修饰过的程序块,在编译前后被编译器生成了monitorenter 和 monitorexit 两个字节码指令。在虚拟机执行到 monitorenter 指令时,首先要尝试获取对象的锁:如果这个对象没有锁定,或者当前线程已经拥有了这个对象的锁,把锁的计数器+1;当执行 monitorexit 指令时将锁计数器-1;当计数器为0时,锁就被释放了。如果获取对象失败了,那当前线程就要阻塞等待,直到对象锁被另外一个线程释放为止。Java 中 Synchronize 通过在对象头设置标记,达到了获取锁和释放锁的目的。 12题 Mybatis 通过动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler 的 invoke()方法,只会拦截那些你指定需要拦截的方法。 实现方法:1.编写Intercepror接口的实现类;2.设置插件的签名,告诉mybatis拦截哪个对象的哪个方法;3.最后将插件注册到全局配置文件中。 11题 Mybatis可以映射枚举类,不单可以映射枚举类,Mybatis可以映射任何对象到表的一列上。映射方式为自定义一个TypeHandler,实现TypeHandler的setParameter()和getResult()接口方法。TypeHandler 有两个作用,一是完成从 javaType至jdbcType 的转换,二是完成jdbcType至javaType的转换,体现为 setParameter()和getResult()两个方法,分别代表设置sql问号占位符参数和获取列查询结果。 10题 Mybatis使用RowBounds对象进行分页,也可以直接编写sql实现分页,也可以使用Mybatis的分页插件。分页插件的原理:使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。举例:select * from student,拦截 sql 后重写为:select t.* from(select * from student)t limit 0,10。 9题 resultType和resultMap都是表示数据库表与pojo之间的映射规则的。类的名字和数据库相同时,可以直接设置resultType 参数为Pojo类。若不同或者有关联查询,需要设置resultMap将结果名字和Pojo名字进行转换。在项目中我们定义的resultMap多了property和column属性,实际也就是分别配置Pojo类的属性和对应的表字段之间的映射关系,多了这个映射关系以后,方便维护。 8题 之所以说Mybatis半自动化,是因为SQL语句需要用户自定义,SQL的解析、执行等工作由Mybatis执行。区别:Hibernate属于全自动 ORM 映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而 Mybatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,所以它是半自动ORM映射工具。 7题 MyBatis 的缓存分为一级缓存和二级缓存。一级缓存是SqlSession级别的缓存,默认就有,在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据,不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。二级缓存是mapper级别的缓存,默认是不打开的,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。 6题 RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。用于方法上是为了细化映射,即根据特定的HTTP请求方法(GET、POST 方法等)、HTTP请求中是否携带特定参数等条件,将请求映射到匹配的方法上。 5题 1、前置通知(before advice):在目标方法调用之前执行; 2、后置通知(after returning advice):在目标方法调用之后执行,一旦目标方法产生异常不会执行; 3、最终通知(after(finally) advice):在目标调用方法之后执行,无论目标方法是否产生异常,都会执行; 4、异常通知(after throwing advice):在目标方法产生异常时执行; 5、环绕通知(around advice):在目标方法执行之前和执行之后都会执行,可以写一些非核心的业务逻辑,一般用来替代前置通知和后置通知。 4题 1、通过构造器或工厂方法创建Bean实例;2、为Bean的属性设置值和对其他Bean的引用;3、将Bean实例传递给Bean后置处理器的postProcessBeforeInitialization方法;4、调用Bean的初始方法(init-method);5、将bean实例传递给bean后置处理器的postProcessAfterInitialization方法;6、bean可以使用了;7、当容器关闭时,调用Bean的销毁方法(destroy-method) 3题 在TransactionDefinition接口中定义了五个表示隔离级别的常量: ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,Mysql默认采用的REPEATABLE_READ隔离级别;Oracle默认采用的READ_COMMITTED隔离级别。 ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。 ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生 ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。 ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。 2 题 自动装配提供五种不同的模式供Spring容器用来自动装配beans之间的依赖注入: 1.默认的方式是不进行自动装配,通过手工设置ref 属性来进行装配bean。 2.byName:通过参数名自动装配,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。 3.byType:按照参数的数据类型进行自动装配,之后容器试图匹配和装配和该bean的属性类型一样的bean。如果存在多个相同类型的bean对象,会出错。 4.constructor:使用构造方法完成对象注入,其实也是根据构造方法的参数类型进行对象查找,相当于采用byType的方式。 5.autodetect:如果找到默认的构造函数,则通过 constructor的方式自动装配,否则使用 byType的方式自动装配。在Spring3.0以后的版本此模式已被废弃,已经不再合法了。 1 题 循环依赖只会存在在单例实例中,多例循环依赖直接报错。Spring先用构造器实例化Bean对象,然后将实例化结束的对象放到一个Map中,并且Spring提供获取这个未设置属性的实例化对象的引用方法。当Spring实例化了A类、B类后,紧接着会去设置对象的属性,此时发现A类依赖B类,就会去Map中取出已经存在的单例B类对象,以此类推。因为所持有的都是引用,所以A类一改变B类也会跟着改变。从而解决循环依赖问题。

游客ih62co2qqq5ww 2020-03-03 18:05:36 0 浏览量 回答数 0

回答

一.无限滚动概念首先,它是基于jQuery的,另外还要明白无限滚动的概念:无限滚动的实现原理就是当你在网页上的滚动条滚动到离网页底部一定长度的时候,触发某ajax函数(infinite-scroll内已经封装好),往后台加载文件或者数据,又或者从外部引入静态html形式文件。二.探讨infinite-scroll1.从网页头引入两个js文件,注意必须先放jquery的 [javascript] view plain copy 在CODE上查看代码片派生到我的代码片 <script src="css/infinite-scroll/jquery-1.6.4.js"></script> <script src="css/infinite-scroll/jquery.infinitescroll.js"></script> 2.之后在网页头自己写一个js脚本 [javascript] view plain copy 在CODE上查看代码片派生到我的代码片 <script> $(document).ready(function (){ $("#container").infinitescroll({ navSelector: "#navigation", //页面分页元素--本页的导航,意思就是一个可以触发ajax函数的模块 nextSelector: "#navigation a", //下一页的导航 itemSelector: ".scroll " , //此处我用了类选择器,选择的是你要加载的那一个块(每次载入的数据放的地方) animate: true, //加载时候时候需要动画,默认是false maxPage: 3, //最大的页数,也就是滚动多少次停。这个页码必须得要你从数据库里面拿 }); }); </script> 3.或许你看到这里还是不太清楚网页怎么定义,这里给出我的demo,希望可以有帮助 [html] view plain copy 在CODE上查看代码片派生到我的代码片 <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>无限翻页效果</title> <script src="css/infinite-scroll/jquery-1.6.4.js"></script> <script src="css/infinite-scroll/jquery.infinitescroll.js"></script> <script src="css/infinite-scroll/test/debug.js"></script> <script> $(document).ready(function (){ //别忘了加这句,除非你没学Jquery $("#container").infinitescroll({ navSelector: "#navigation", //页面分页元素--成功后自动隐藏 nextSelector: "#navigation a", itemSelector: ".scroll " , animate: true, maxPage: 3, }); }); </script> </head> <body> <div id="container"> <!-- 容器 --> <div class="scroll"> <!-- 每次要加载数据的数据块--> 第一页内容第一页内容<br> 第一页内容<br>第一页内容<br>第一页内容<br> 第一页内容<br>第一页内容<br>第一页内容<br> 第一页内容<br>第一页内容<br>第一页内容 </div> </div> <div id="navigation" align="center"> <!-- 页面导航--> <a href="user/list?page=1"></a> <!-- 此处可以是url,可以是action,要注意不是每种html都可以加,是跟当前网页有相同布局的才可以。另外一个重要的地方是page参数,这个一定要加在这里,它的作用是指出当前页面页码,没加载一次数据,page自动+1,我们可以从服务器用request拿到他然后进行后面的分页处理。--> </div> </body> </html> 三.细微部分1.js函数里还可定义的其他属性: [javascript] view plain copy 在CODE上查看代码片派生到我的代码片 debug : true, //用于调试,如果需要用到,只需在网页头引入官网demo里的debug.js文件 loadingImg : "/img/loading.gif", //加载时候显示的进度条,用户可以自定义 loadingText : "Loading new posts...", //加载时显示的文字 extraScrollPx: 50, //离网页底部多少像素时触发ajax donetext : "I think we've hit the end, Jim" , //加载完数据(到达底部时)显示的文字提醒 errorCallback: function(){}, //加载完数据后的回调函数,可选 其他属性暂不作过多介绍 2.数据的载入方式①html :如果你已经有固定的数据块,可以放到html里面加载静态页面。②json :可以用后台返回json的方式,返回的时候要指定temple里面的html模版,否则会出错。③我上面例子用的其实也是json,前台在Action层把数据取出后再用StringBuilder拼装成html格式的字符串返回前台。(个人习惯)3.数据分页方式本例用hibernate进行数据分页。

小旋风柴进 2019-12-02 02:37:33 0 浏览量 回答数 0

回答

生命周期:加载和实例化Servlet我们来看一下Tomcat是如何加载的: 1. 如果已配置自动装入选项,则在启动时自动载入。 2. 在服务器启动时,客户机首次向Servlet发出请求。 3. 重新装入Servlet时。 当启动Servlet容器时,容器首先查找一个配置文件web.xml,这个文件中记录了可以提供服务的Servlet。每个Servlet被指定一个Servlet名,也就是这个Servlet实际对应的Java的完整class文件名。Servlet容器会为每个自动装入选项的Servlet创建一个实例。所以,每个Servlet类必须有一个公共的无参数的构造器。 初始化 当Servlet被实例化后,Servlet容器将调用每个Servlet的init方法来实例化每个实例,执行完init方法之后,Servlet处于“已初始化”状态。所以说,一旦Servlet被实例化,那么必将调用init方法。通过Servlet在启动后不立即初始化,而是收到请求后进行。在web.xml文件中用<load-on-statup> ...... </load-on-statup>对Servlet进行预先初始化。 初始化失败后,执行init()方法抛出ServletException异常,Servlet对象将会被垃圾回收器回收,当客户端第一次访问服务器时加载Servlet实现类,创建对象并执行初始化方法。 请求处理 Servlet 被初始化以后,就处于能响应请求的就绪状态。每个对Servlet 的请求由一个Servlet Request 对象代表。Servlet 给客户端的响应由一个Servlet Response对象代表。对于到达客户机的请求,服务器创建特定于请求的一个“请求”对象和一个“响应”对象。调用service方法,这个方法可以调用其他方法来处理请求。 Service方法会在服务器被访问时调用,Servlet对象的生命周期中service方法可能被多次调用,由于web-server启动后,服务器中公开的部分资源将处于网络中,当网络中的不同主机(客户端)并发访问服务器中的同一资源,服务器将开设多个线程处理不同的请求,多线程同时处理同一对象时,有可能出现数据并发访问的错误。 另外注意,多线程难免同时处理同一变量时(如:对同一文件进行写操作),且有读写操作时,必须考虑是否加上同步,同步添加时,不要添加范围过大,有可能使程序变为纯粹的单线程,大大削弱了系统性能;只需要做到多个线程安全的访问相同的对象就可以了。 卸载Servlet 当服务器不再需要Servlet实例或重新装入时,会调用destroy方法,使用这个方法,Servlet可以释放掉所有在init方法申请的资源。一个Servlet实例一旦终止,就不允许再次被调用,只能等待被卸载。 Servlet一旦终止,Servlet实例即可被垃圾回收,处于“卸载”状态,如果Servlet容器被关闭,Servlet也会被卸载,一个Servlet实例只能初始化一次,但可以创建多个相同的Servlet实例。如相同的Servlet可以在根据不同的配置参数连接不同的数据库时创建多个实例。 各个方法:init()方法 在Servlet的生命周期中,仅执行一次init()方法,它是在服务器装入Servlet时执行的,可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init(); service()方法 它是Servlet的核心,每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。 destroy()方法 仅执行一次,在服务器端停止且卸载Servlet时执行该方法,有点类似于C++的delete方法。一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。 下面来谈谈Servlet的生命周期,Servlet的生命周期是由Servlet容器来控制的,它始于装入Web服务器的内存时,并在终止或重新装入Servlet时结束。这项操作一般是动态执行的。然而,Server通常会提供一个管理的选项,用于在Server启动时强制装载和初始化特定的Servlet。 在代码中,Servlet生命周期由接口javax.servlet.Servlet定义。所有的Java Servlet 必须直接或间接地实现javax.servlet.Servlet接口,这样才能在Servlet Engine上运行。javax.servlet.Servlet接口定义了一些方法,在Servlet 的生命周期中,这些方法会在特定时间按照一定的顺序被调用。

小川游鱼 2019-12-02 01:50:40 0 浏览量 回答数 0

问题

spring 集成quazt 后如何实现等spring容器加载完成之后自动执行一次任务?

长安归故里. 2020-01-31 13:50:56 1 浏览量 回答数 1

问题

关于 PHP 的编译和执行分离:报错 

kun坤 2020-06-08 16:00:00 1 浏览量 回答数 1

回答

概念 Apache Tomcat最早是由Sun Microsystems开发的一个Servlet容器,在1999年被捐献给ASF(Apache Software Foundation),隶属于Jakarta项目,现在已经独立为一个顶级项目。Tomcat主要实现了Java EE中的Servlet、JSP规范,同时也提供HTTP服务,是市场上非常流行的Java Web容器。 目录结构 以Tomcat-8.5为例,分析下各个目录都有哪些文件、有哪些作- 1. 用。 bin:主要存放tomcat的操作命令,根据操作系统可以分为两大类:一是以.bat结尾(Windows);二是以.sh结尾(Linux)。比如可以通过startup启动,shutdown关闭Tomcat。 conf:全局配置文件 一个策略文件:catalina.policy 定义了安全策略。 两个属性文件:catalina.properties 和 logging.properties 。 四个XML配置文件: server.xml:Tomcat的主要配置文件,配置整个服务器信息,如修改连接器端口号(默认为8080)。不能动态重加载,文件修改之后必须重启服务器才能生效。 web.xml:全局的web应用程序部署描述文件,如可以设置tomcat支持的文件类型。 context.xml:Tomcat的一些特定配置项,针对所有应用程序生效。 tomcat-users.xml:配置Tomcat的用户名、密码,管理身份验证以及访问控制权限。 lib:Tomcat运行依赖的一些Jar文件,比如常见的servlet-api.jar、jsp-api.jar。所有的应用程序可用,可以放置一些公用的Jar文件,如MySQL JDBC驱动(mysql-connector-java-5.1.{xx}-bin.jar)。 logs:运行中产生的日志文件。包含引擎(engine)日志文件 Catalina.{yyyy-mm-dd}.log,主机日志文件localhost.{yyyy-mm-dd}.log,以及一些其他应用日志文件如manager、host-manager。访问日志也保存在此目录下。 temp:临时文件目录,清空不会影响Tomcat运行 webapps:默认的应用程序根目录,Tomcat启动时会自动加载该目录下的应用程序,可以以文件夹、war包、jar包的形式发布(启动时会自动解压成相应的文件夹)。也可以把应用程序放置在其他路径下,需要在文件中配置路径映射。 work:用来存放tomcat在运行时的编译后文件,如JSP编译后的文件。清空work目录,然后重启tomcat,可以达到清除缓存的作用。 架构 Tomcat是一个HTTP服务器,同时也是一个Servlet容器(可以执行Servlet文件,JSP、JSF会被转换成Servlet),支持多种功能,因此采用了分层、模块化的设计。 查看conf文件夹中的server.xml文件,可以发现上图的层次结构。 <Server> <Service> <Connector/> <Engine> <Host></Host> </Engine> </Service> </Server> Server Server是一个顶级组件,代表了一个Tomcat实例,一个JVM进程中只能有一个Server实例。Tomcat提供了一个实现了 org.apache.catalina.Server接口的 org.apache.catalina.core.StandardServer默认类,读取Server元素配置。 Server是配置文件中的最外层元素,支持以下属性: className:指定要使用的实现类(必须实现org.apache.catalina.Server接口)名称。如果不指定,默认使用标准实现类StandardServer。 address:等待shutdown命令的服务器IP地址,默认是localhost。 port:等待shutdown命令的监听端口,如果设置为-1,表示关闭shutdown端口。 shutdown:指定终止Tomcat服务器运行时,发给Tomcat服务器的shutdown监听端口的字符串.该属性必须设置 。   启动Tomcat,打开命令行工具,通过telnet命令:telnet localhost 8005 连接服务器 输入SHUTDOWN命令,即可关闭Tomcat Cluster Cluster可以解决应用之间session共享、上下文属性共享,以及在集群内共同部署应用程序的问题。元素可以包含在或者元素下。 Context Host元素定义了虚拟主机,Context则是虚拟主机下的具体应用。Tomcat启动后,webapps目录下的所有应用程序都会自动运行,访问某个具体项目需要在URL中指定项目名称,如 http://localhost:8080/examples/ ,ROOT目录除外。想要通过 http://localhost:8080 来访问自定义项目,可以把应用程序直接放到ROOT目录中(让ROOT做为项目的根目录),也可以通过Context来配置映射。 <!-- path:访问项目时的URL,加在localhost:8080后 docBase:path对应的项目目录 reloadable:监视 /WEB-INF/classes/ 和 /WEB-INF/lib目录中的类文件,更改后自动重载应用程序, 生成环境不建议使用,默认为“false” -->  更改server.xml文件后,重新启动Tomcat,在浏览器中输入 http://localhost:8080 即可访问examples应用。 Host 一个Host元素代表了一个虚拟主机,默认主机名为localhost,支持多个Context。 <!-- appBase:定义了应用程序的根目录,默认是webapps unpackWARS:定义了是否解压webapps中的WAR文件,如果指定为“false”,会从WAR文件直接运行程序,执行较慢 autoDeploy:把应用程序直接拖到webapps目录下,是否自动运行 -->

问问小秘 2020-04-30 17:01:07 0 浏览量 回答数 0

回答

(一)java 静态代码块 静态方法区别 一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序来调用的时候,需要使用静态方法,这种代码是被动执行的. 静态方法在类加载的时候 就已经加载 可以用类名直接调用 比如main方法就必须是静态的 这是程序入口 两者的区别就是:静态代码块是自动执行的; 静态方法是被调用的时候才执行的. 静态方法 (1)在Java里,可以定义一个不需要创建对象的方法,这种方法就是静态方法。要实现这样的效果,只需要在类中定义的方法前加上static关键字。例如: public static int maximum(int n1,int n2) 使用类的静态方法时,注意: a在静态方法里只能直接调用同类中其他的静态成员(包括变量和方法),而不能直接访问类中的非静态成员。这是因为,对于非静态的方法和变量,需要先创建类的实例对象后才可使用,而静态方法在使用前不用创建任何对象。 b 静态方法不能以任何方式引用this和super关键字,因为静态方法在使用前不用创建任何实例对象,当静态方法调用时,this所引用的对象根本没有产生。 (2)静态变量是属于整个类的变量而不是属于某个对象的。注意不能把任何方法体内的变量声明为静态,例如: fun() { static int i=0;//非法。 } (3)一个类可以使用不包含在任何方法体中的静态代码块,当类被载入时,静态代码块被执行,且只被执行一次,静态块常用来执行类属性的初始化。例如: static { } 类装载步骤 在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又可以分成校验、准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下: 装载:查找和导入类或接口的二进制数据; 链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的; 校验:检查导入类或接口的二进制数据的正确性; 准备:给类的静态变量分配并初始化存储空间; 解析:将符号引用转成直接引用; 初始化:激活类的静态变量的初始化Java代码和静态Java代码块。 初始化类中属性是静态代码块的常用用途,但只能使用一次。 (二)静态代码块的初始化顺序 class Parent{ static String name = "hello"; { System.out.println("parent block"); } static { System.out.println("parent static block"); } public Parent(){ System.out.println("parent constructor"); } } class Child extends Parent{ static String childName = "hello"; { System.out.println("child block"); } static { System.out.println("child static block"); } public Child(){ System.out.println("child constructor"); } } public class StaticIniBlockOrderTest { public static void main(String[] args) { new Child();//语句(*) } } 问题:当执行完语句()时,打印结果是什么顺序?为什么? 解答:当执行完语句()时,打印结果是这样一个顺序 : parent static block child static block parent block parent constructor child block child constructor 行完毕之后,接着去执行子类(自己这个类)里面的静态代码块,当子类的静态代码块执行完毕之后,它接着又去看父类有没有非静态代码块,如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。子类的非静态代码块执行完毕再去执行子类的构造方法,这个就是一个对象的初始化顺序。 总结: 对象的初始化顺序:首先执行父类静态的内容,父类静态的内容执行完毕后,接着去执行子类的静态的内容,当子类的静态内容执行完毕之后,再去看父类有没有非静态代码块,如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。子类的非静态代码块执行完毕再去执行子类的构造方法。总之一句话,静态代码块内容先执行,接着执行父类非静态代码块和构造方法,然后执行子类非静态代码块和构造方法。 注意:子类的构造方法,不管这个构造方法带不带参数,默认的它都会先去寻找父类的不带参数的构造方法。如果父类没有不带参数的构造方法,那么子类必须用supper关键子来调用父类带参数的构造方法,否则编译不能通过。 原文链接:https://www.cnblogs.com/jiangyi666/p/5665130.html

问问小秘 2020-07-01 18:00:51 0 浏览量 回答数 0

回答

<p>你把jar解压看看,应该是没有那些包和类的,这个问题我遇到过</p> 本身其实就没有包,是使用JavaCompiler编译器在内存中把sting字符串编译然后通过类加载器去加载的对象 你看target里面有没有你需要的那个包啊 如果没有 看看maven打包时候 是不是有啥问题 jar包解压后里面lib目录下依赖对象都有,编译报错找不到包的的对象是存在的,只是使用JavaCompiler编译器编译的对象找不到那些依赖对象 <p>请问你这个问题解决了吗,同遇</p> 回复 <a class="referer" target="_blank">@林荫小憩</a> : 数据库的数据也可以直接通过maven插件读取的,代码自动生成就是读取数据库字段去生成文件的 回复 <a class="referer" target="_blank">@青宇0223</a> : 直接将字符串通过maven插件生成好文件?我这字符串是存数据库中,动态获取的。 没解决,放弃了,改成maven插件了,直接在编译之前,通过maven插件,生成好文件,然后编译到jar包里面 <p>吧需要引入的jar包 放到一个lib目录下,然后编译的时候加上这些jar包的路径即可.我现在想让他直接读取springboot的boot info下的lib 还不知道怎么实现</p> JavaFileObject javaFileObject = manager.makeStringSource(className, javaStr); Iterable<String> options = null; if(isJar()) { options = Arrays.asList( "-classpath", getJarFiles(getPath()) ); } JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, options, null, Arrays.asList(javaFileObject));

爱吃鱼的程序员 2020-06-05 15:42:11 0 浏览量 回答数 0

问题

【精品问答】前端开发必懂之JS技术二百问

茶什i 2019-12-01 22:05:04 146 浏览量 回答数 0

问题

移动测试里名词解释都有哪些?

猫饭先生 2019-12-01 20:55:34 807 浏览量 回答数 0

回答

这是个好问题。不知道题主是否熟悉自由测试和弱网测试这两个提法——这其实就是你提出的测试需求。简而言之:自由测试就是乱点;弱网测试就是人为制造掉包和延迟(可能制造成随机或确定性的)。这两个测试都是非常重要的。程序能否顶住这两项测试,保证一切情况下的响应都是合理的(而不是跑飞),这是开发者对健壮性把握如何的一个重要指标。问题一分为二地看。先忽略“点击速率的控制”,仅看“如何保证加载结果正确”这一点。从体验的角度来看,用户点击多个选项卡时,内容应该仅以用户点击的最后一个选项卡为准。毕竟用户点击了新的选项卡,就包含着“之前没加载出来的旧选项卡,全都丢弃不要了”的潜台词。考虑这个序列:选项卡1点击 - 选项卡2点击 - 选项卡1响应到达 - 选项卡2响应永远丢包。此时用户体验来看,弹出选项卡1必然是怪异的(我明明点击的是选项卡2!)。唯一的正确答案是:显示为选项卡2永远加载中(或者提示超时出错,允许用户重新加载),而永远丢弃选项卡1的响应。从这个意义上,AJAX请求的发出你是不应当阻止的。你的真正需求是:发出新的AJAX请求的时候,如何将旧的请求全部停下来。这里必须说明的是:AJAX对象,保证HTTP的响应与请求一一对应。具体而言:某个具体的XMLHttpRequest实例发出了HTTP请求。那么此HTTP请求的响应,就会回到发请求的那个XMLHttpRequest实例上。这一点自动、必然、绝对、100%准确无误,并且由浏览器(或JS引擎)直接保证,无需任何编程干预。以上是针对原生AJAX而言的。jQuery也一样,只是对象变成了jQuery封装过的jqXHR而已。1次AJAX请求必然有1个实例,多个请求那就有多个实例来管理,这与任何其他条件无关,根本不用考虑“多个AJAX请求相同页面,响应会不会对应乱了”这种杞人忧天的问题。你说回调?那只不过是挂载在各个AJAX对象实例上的一个普通成员变量(JavaScript里函数和变量同为一等公民)。请求对象对应正确了,回调自然也不会乱。这种1次请求对应1个对象的关系,就给了我们在AJAX请求发出后,仍然能对其进行控制的可能。我们确实通常把 $.ajax() 当语句使用($.ajax(settings);),但事实上 $.ajax() 是有返回值的。$.ajax() 返回此次请求对应的 jqXHR 对象,我们可以通过此对象,来影响和操作这次请求本身。那么每次点击选项卡都发出请求,但只响应用户发出的最后一个请求的代码就非常好写了:$(function() { $('#单选你的选项卡的容器').data('request_buffer', null); }); $('.多选你的每一个选项卡').click(function() { // 旧的HTTP请求直接放弃加载 var previous_jqxhr = $('#单选你的选项卡的容器').data('request_buffer'); if (previous_jqxhr) { previous_jqxhr.abort(); } var current_jqxhr = $.ajax({ type: your_type, url: your_url, data: your_data, timeout: your_timeout_seconds * 1000, context: this, }) .beforeSend(function() { // 显示点loading小动画什么的 }) .done(function() { // 点亮你点击的选项卡,灭掉其他的 $('.多选你的每一个选项卡').removeClass('.选项卡点亮的效果'); $(this).addClass('.选项卡点亮的效果'); // 填充正文区域 $('#单选你显示正文的区域').html(你得到的响应正文); }) .fail(function() { // 你认为合适的超时处理 }); // 新的请求顶掉旧的请求 $('#单选你的选项卡的容器').data('request_buffer', current_jqxhr); });回调函数是控制HTTP请求的jqXHR对象调用的,所以如果不加污染,那么回调函数内的this指的是jqXHR本身。那么回调函数在调用到的时候,根本没有办法反查到你点击了哪个选项卡。所以一定注意代码里那个context。jqXHR对象的context,确定了jqXHR在调用回调函数的时候,把回调函数内看到的this污染成谁。只有在产生jqXHR的时候(即调用$.ajax()时)明确告知“此请求和哪些对象有联系”,在回调的时候才不会迷失方向,导致一些设置视觉效果的需求做不出来。实现要基于事物的本源。如果一个AJAX请求要丢弃,那就应当把请求对象本身挖出来,通知他自己放弃。这样不但彻底把待丢弃的无效回调本身消灭,更可以命令浏览器直接断开HTTP连接,节省宝贵的流量和并发数。这一点也是很重要的。而明知道请求用不着了还要接收下来,再以“提前return”之类的修补手段“手工丢弃”,这个绕圈子的方案明显是不够优的。实际上以上的措施,已经能够达到“保证加载结果正确”的目的了。 用户点得快,发出的请求多又怎么样? 反正同一时刻同时只有1条请求在网上跑,只有1个回调有调到的可能,一切的干扰要素都排除光了。在此基础上,如果引入“限制用户点击的速率”,那么就是纯粹为了减轻服务器压力考虑了。这个的办法就更加简单:用户点击一个选项卡(启动HTTP请求发送,可以挂在beforeSend事件上)时把所有的选项卡置灰。(不能点是必须明确提示用户的)然后等待以下两个触发条件触发任意一个,就可以把所有的选项卡恢复点击:成功分支:用户点的这个选项卡加载成功了(立刻允许用户切换到其他选项卡)失败情况:用户点击之后过去了 X 秒(加载不出来了,允许用户发出新的请求)这个的代码就略了。

小旋风柴进 2019-12-02 02:24:30 0 浏览量 回答数 0

回答

初识 MyBatis MyBatis 是第一个支持自定义 SQL、存储过程和高级映射的类持久框架。MyBatis 消除了大部分 JDBC 的样板代码、手动设置参数以及检索结果。MyBatis 能够支持简单的 XML 和注解配置规则。使 Map 接口和 POJO 类映射到数据库字段和记录。 MyBatis 的特点 那么 MyBatis 具有什么特点呢?或许我们可以从如下几个方面来描述 MyBatis 中的 SQL 语句和主要业务代码分离,我们一般会把 MyBatis 中的 SQL 语句统一放在 XML 配置文件中,便于统一维护。 解除 SQL 与程序代码的耦合,通过提供 DAO 层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。SQL 和代码的分离,提高了可维护性。 MyBatis 比较简单和轻量 本身就很小且简单。没有任何第三方依赖,只要通过配置 jar 包,或者如果你使用 Maven 项目的话只需要配置 Maven 以来就可以。易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。 屏蔽样板代码 MyBatis 回屏蔽原始的 JDBC 样板代码,让你把更多的精力专注于 SQL 的书写和属性-字段映射上。 编写原生 SQL,支持多表关联 MyBatis 最主要的特点就是你可以手动编写 SQL 语句,能够支持多表关联查询。 提供映射标签,支持对象与数据库的 ORM 字段关系映射 ORM 是什么?对象关系映射(Object Relational Mapping,简称ORM) ,是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。 提供 XML 标签,支持编写动态 SQL。 你可以使用 MyBatis XML 标签,起到 SQL 模版的效果,减少繁杂的 SQL 语句,便于维护。 MyBatis 整体架构 MyBatis 最上面是接口层,接口层就是开发人员在 Mapper 或者是 Dao 接口中的接口定义,是查询、新增、更新还是删除操作;中间层是数据处理层,主要是配置 Mapper -> XML 层级之间的参数映射,SQL 解析,SQL 执行,结果映射的过程。上述两种流程都由基础支持层来提供功能支撑,基础支持层包括连接管理,事务管理,配置加载,缓存处理等。 接口层 在不与Spring 集成的情况下,使用 MyBatis 执行数据库的操作主要如下: InputStream is = Resources.getResourceAsStream("myBatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); sqlSession = factory.openSession(); 其中的SqlSessionFactory,SqlSession是 MyBatis 接口的核心类,尤其是 SqlSession,这个接口是MyBatis 中最重要的接口,这个接口能够让你执行命令,获取映射,管理事务。 数据处理层 配置解析 在 Mybatis 初始化过程中,会加载 mybatis-config.xml 配置文件、映射配置文件以及 Mapper 接口中的注解信息,解析后的配置信息会形成相应的对象并保存到 Configration 对象中。之后,根据该对象创建SqlSessionFactory 对象。待 Mybatis 初始化完成后,可以通过 SqlSessionFactory 创建 SqlSession 对象并开始数据库操作。 SQL 解析与 scripting 模块 Mybatis 实现的动态 SQL 语句,几乎可以编写出所有满足需要的 SQL。 Mybatis 中 scripting 模块会根据用户传入的参数,解析映射文件中定义的动态 SQL 节点,形成数据库能执行的SQL 语句。 SQL 执行 SQL 语句的执行涉及多个组件,包括 MyBatis 的四大核心,它们是: Executor、StatementHandler、ParameterHandler、ResultSetHandler。SQL 的执行过程可以用下面这幅图来表示 MyBatis 层级结构各个组件的介绍(这里只是简单介绍,具体介绍在后面): SqlSession: ,它是 MyBatis 核心 API,主要用来执行命令,获取映射,管理事务。接收开发人员提供 Statement Id 和参数。并返回操作结果。Executor :执行器,是 MyBatis 调度的核心,负责 SQL 语句的生成以及查询缓存的维护。StatementHandler : 封装了JDBC Statement 操作,负责对 JDBC Statement 的操作,如设置参数、将Statement 结果集转换成 List 集合。ParameterHandler : 负责对用户传递的参数转换成 JDBC Statement 所需要的参数。ResultSetHandler : 负责将 JDBC 返回的 ResultSet 结果集对象转换成 List 类型的集合。TypeHandler : 用于 Java 类型和 JDBC 类型之间的转换。MappedStatement : 动态 SQL 的封装SqlSource : 表示从 XML 文件或注释读取的映射语句的内容,它创建将从用户接收的输入参数传递给数据库的 SQL。Configuration: MyBatis 所有的配置信息都维持在 Configuration 对象之中。 基础支持层 反射模块 Mybatis 中的反射模块,对 Java 反射进行了很好的封装,提供了简易的 API,方便上层调用,并且对反射操作进行了一系列的优化,比如,缓存了类的 元数据(MetaClass)和对象的元数据(MetaObject),提高了反射操作的性能。 类型转换模块 Mybatis 的别名机制,能够简化配置文件,该机制是类型转换模块的主要功能之一。类型转换模块的另一个功能是实现 JDBC 类型与 Java 类型的转换。在 SQL 语句绑定参数时,会将数据由 Java 类型转换成 JDBC 类型;在映射结果集时,会将数据由 JDBC 类型转换成 Java 类型。 日志模块 在 Java 中,有很多优秀的日志框架,如 Log4j、Log4j2、slf4j 等。Mybatis 除了提供了详细的日志输出信息,还能够集成多种日志框架,其日志模块的主要功能就是集成第三方日志框架。 资源加载模块 该模块主要封装了类加载器,确定了类加载器的使用顺序,并提供了加载类文件和其它资源文件的功能。 解析器模块 该模块有两个主要功能:一个是封装了 XPath,为 Mybatis 初始化时解析 mybatis-config.xml配置文件以及映射配置文件提供支持;另一个为处理动态 SQL 语句中的占位符提供支持。 数据源模块 Mybatis 自身提供了相应的数据源实现,也提供了与第三方数据源集成的接口。数据源是开发中的常用组件之一,很多开源的数据源都提供了丰富的功能,如连接池、检测连接状态等,选择性能优秀的数据源组件,对于提供ORM 框架以及整个应用的性能都是非常重要的。 事务管理模块 一般地,Mybatis 与 Spring 框架集成,由 Spring 框架管理事务。但 Mybatis 自身对数据库事务进行了抽象,提供了相应的事务接口和简单实现。 缓存模块 Mybatis 中有一级缓存和二级缓存,这两级缓存都依赖于缓存模块中的实现。但是需要注意,这两级缓存与Mybatis 以及整个应用是运行在同一个 JVM 中的,共享同一块内存,如果这两级缓存中的数据量较大,则可能影响系统中其它功能,所以需要缓存大量数据时,优先考虑使用 Redis、Memcache 等缓存产品。 Binding 模块 在调用 SqlSession 相应方法执行数据库操作时,需要制定映射文件中定义的 SQL 节点,如果 SQL 中出现了拼写错误,那就只能在运行时才能发现。为了能尽早发现这种错误,Mybatis 通过 Binding 模块将用户自定义的Mapper 接口与映射文件关联起来,系统可以通过调用自定义 Mapper 接口中的方法执行相应的 SQL 语句完成数据库操作,从而避免上述问题。注意,在开发中,我们只是创建了 Mapper 接口,而并没有编写实现类,这是因为 Mybatis 自动为 Mapper 接口创建了动态代理对象。 MyBatis 核心组件 在认识了 MyBatis 并了解其基础架构之后,下面我们来看一下 MyBatis 的核心组件,就是这些组件实现了从 SQL 语句到映射到 JDBC 再到数据库字段之间的转换,执行 SQL 语句并输出结果集。首先来认识 MyBatis 的第一个核心组件 SqlSessionFactory 对于任何框架而言,在使用该框架之前都要经历过一系列的初始化流程,MyBatis 也不例外。MyBatis 的初始化流程如下 String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); sqlSessionFactory.openSession(); 上述流程中比较重要的一个对象就是SqlSessionFactory,SqlSessionFactory 是 MyBatis 框架中的一个接口,它主要负责的是 MyBatis 框架初始化操作 为开发人员提供SqlSession 对象 SqlSessionFactory 有两个实现类,一个是 SqlSessionManager 类,一个是 DefaultSqlSessionFactory 类 DefaultSqlSessionFactory : SqlSessionFactory 的默认实现类,是真正生产会话的工厂类,这个类的实例的生命周期是全局的,它只会在首次调用时生成一个实例(单例模式),就一直存在直到服务器关闭。 SqlSessionManager : 已被废弃,原因大概是: SqlSessionManager 中需要维护一个自己的线程池,而使用MyBatis 更多的是要与 Spring 进行集成,并不会单独使用,所以维护自己的 ThreadLocal 并没有什么意义,所以 SqlSessionManager 已经不再使用。 ####SqlSessionFactory 的执行流程 下面来对 SqlSessionFactory 的执行流程来做一个分析 首先第一步是 SqlSessionFactory 的创建 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 1 从这行代码入手,首先创建了一个 SqlSessionFactoryBuilder 工厂,这是一个建造者模式的设计思想,由 builder 建造者来创建 SqlSessionFactory 工厂 然后调用 SqlSessionFactoryBuilder 中的 build 方法传递一个InputStream 输入流,Inputstream 输入流中就是你传过来的配置文件 mybatis-config.xml,SqlSessionFactoryBuilder 根据传入的 InputStream 输入流和environment、properties属性创建一个XMLConfigBuilder对象。SqlSessionFactoryBuilder 对象调用XMLConfigBuilder 的parse()方法,流程如下。 XMLConfigBuilder 会解析/configuration标签,configuration 是 MyBatis 中最重要的一个标签,下面流程会介绍 Configuration 标签。 MyBatis 默认使用 XPath 来解析标签,关于 XPath 的使用,参见 https://www.w3school.com.cn/xpath/index.asp 在 parseConfiguration 方法中,会对各个在 /configuration 中的标签进行解析 重要配置 说一下这些标签都是什么意思吧 properties,外部属性,这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。 <properties> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/test" /> <property name="username" value="root" /> <property name="password" value="root" /> </properties> 一般用来给 environment 标签中的 dataSource 赋值 <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </environment> 还可以通过外部属性进行配置,但是我们这篇文章以原理为主,不会介绍太多应用层面的操作。 settings ,MyBatis 中极其重要的配置,它们会改变 MyBatis 的运行时行为。 settings 中配置有很多,具体可以参考 https://mybatis.org/mybatis-3/zh/configuration.html#settings 详细了解。这里介绍几个平常使用过程中比较重要的配置 一般使用如下配置 <settings> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> </settings> typeAliases,类型别名,类型别名是为 Java 类型设置的一个名字。 它只和 XML 配置有关。 <typeAliases> <typeAlias alias="Blog" type="domain.blog.Blog"/> </typeAliases> 当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。 typeHandlers,类型处理器,无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。 在 org.apache.ibatis.type 包下有很多已经实现好的 TypeHandler,可以参考如下 你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。 具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很方便的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个 JDBC 类型。 objectFactory,对象工厂,MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现。 public class ExampleObjectFactory extends DefaultObjectFactory { public Object create(Class type) { return super.create(type); } public Object create(Class type, List constructorArgTypes, List constructorArgs) { return super.create(type, constructorArgTypes, constructorArgs); } public void setProperties(Properties properties) { super.setProperties(properties); } public boolean isCollection(Class type) { return Collection.class.isAssignableFrom(type); } } 然后需要在 XML 中配置此对象工厂 <objectFactory type="org.mybatis.example.ExampleObjectFactory"> <property name="someProperty" value="100"/> </objectFactory> plugins,插件开发,插件开发是 MyBatis 设计人员给开发人员留给自行开发的接口,MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。MyBatis 允许使用插件来拦截的方法调用包括:Executor、ParameterHandler、ResultSetHandler、StatementHandler 接口,这几个接口也是 MyBatis 中非常重要的接口,我们下面会详细介绍这几个接口。 environments,MyBatis 环境配置,MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中 使用相同的 SQL 映射。 这里注意一点,虽然 environments 可以指定多个环境,但是 SqlSessionFactory 只能有一个,为了指定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties); databaseIdProvider ,数据库厂商标示,MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 <databaseIdProvider type="DB_VENDOR"> <property name="SQL Server" value="sqlserver"/> <property name="DB2" value="db2"/> <property name="Oracle" value="oracle" /> </databaseIdProvider> mappers,映射器,这是告诉 MyBatis 去哪里找到这些 SQL 语句,mappers 映射配置有四种方式 上面的一个个属性都对应着一个解析方法,都是使用 XPath 把标签进行解析,解析完成后返回一个 DefaultSqlSessionFactory 对象,它是 SqlSessionFactory 的默认实现类。这就是 SqlSessionFactoryBuilder 的初始化流程,通过流程我们可以看到,初始化流程就是对一个个 /configuration 标签下子标签的解析过程。 SqlSession 在 MyBatis 初始化流程结束,也就是 SqlSessionFactoryBuilder -> SqlSessionFactory 的获取流程后,我们就可以通过 SqlSessionFactory 对象得到 SqlSession 然后执行 SQL 语句了。具体来看一下这个过程‘ 在 SqlSessionFactory.openSession 过程中我们可以看到,会调用到 DefaultSqlSessionFactory 中的 openSessionFromDataSource 方法,这个方法主要创建了两个与我们分析执行流程重要的对象,一个是 Executor 执行器对象,一个是 SqlSession 对象。执行器我们下面会说,现在来说一下 SqlSession 对象 SqlSession 对象是 MyBatis 中最重要的一个对象,这个接口能够让你执行命令,获取映射,管理事务。SqlSession 中定义了一系列模版方法,让你能够执行简单的 CRUD 操作,也可以通过 getMapper 获取 Mapper 层,执行自定义 SQL 语句,因为 SqlSession 在执行 SQL 语句之前是需要先开启一个会话,涉及到事务操作,所以还会有 commit、 rollback、close 等方法。这也是模版设计模式的一种应用。 MapperProxy MapperProxy 是 Mapper 映射 SQL 语句的关键对象,我们写的 Dao 层或者 Mapper 层都是通过 MapperProxy 来和对应的 SQL 语句进行绑定的。下面我们就来解释一下绑定过程 这就是 MyBatis 的核心绑定流程,我们可以看到 SqlSession 首先调用 getMapper 方法,我们刚才说到 SqlSession 是大哥级别的人物,只定义标准(有一句话是怎么说的来着,一流的企业做标准,二流的企业做品牌,三流的企业做产品)。 SqlSession 不愿意做的事情交给 Configuration 这个手下去做,但是 Configuration 也是有小弟的,它不愿意做的事情直接甩给小弟去做,这个小弟是谁呢?它就是 MapperRegistry,马上就到核心部分了。MapperRegistry 相当于项目经理,项目经理只从大面上把握项目进度,不需要知道手下的小弟是如何工作的,把任务完成了就好。最终真正干活的还是 MapperProxyFactory。看到这段代码 Proxy.newProxyInstance ,你是不是有一种恍然大悟的感觉,如果你没有的话,建议查阅一下动态代理的文章,这里推荐一篇 (https://www.jianshu.com/p/95970b089360) 也就是说,MyBatis 中 Mapper 和 SQL 语句的绑定正是通过动态代理来完成的。 通过动态代理,我们就可以方便的在 Dao 层或者 Mapper 层定义接口,实现自定义的增删改查操作了。那么具体的执行过程是怎么样呢?上面只是绑定过程,别着急,下面就来探讨一下 SQL 语句的执行过程。 MapperProxyFactory 会生成代理对象,这个对象就是 MapperProxy,最终会调用到 mapperMethod.execute 方法,execute 方法比较长,其实逻辑比较简单,就是判断是 插入、更新、删除 还是 查询 语句,其中如果是查询的话,还会判断返回值的类型,我们可以点进去看一下都是怎么设计的。 很多代码其实可以忽略,只看我标出来的重点就好了,我们可以看到,不管你前面经过多少道关卡处理,最终都逃不过 SqlSession 这个老大制定的标准。 我们以 selectList 为例,来看一下下面的执行过程。 这是 DefaultSqlSession 中 selectList 的代码,我们可以看到出现了 executor,这是什么呢?我们下面来解释。 Executor 还记得我们之前的流程中提到了 Executor(执行器) 这个概念吗?我们来回顾一下它第一次出现的位置。 由 Configuration 对象创建了一个 Executor 对象,这个 Executor 是干嘛的呢?下面我们就来认识一下 Executor 的继承结构 每一个 SqlSession 都会拥有一个 Executor 对象,这个对象负责增删改查的具体操作,我们可以简单的将它理解为 JDBC 中 Statement 的封装版。 也可以理解为 SQL 的执行引擎,要干活总得有一个发起人吧,可以把 Executor 理解为发起人的角色。 首先先从 Executor 的继承体系来认识一下 如上图所示,位于继承体系最顶层的是 Executor 执行器,它有两个实现类,分别是BaseExecutor和 CachingExecutor。 BaseExecutor 是一个抽象类,这种通过抽象的实现接口的方式是适配器设计模式之接口适配 的体现,是Executor 的默认实现,实现了大部分 Executor 接口定义的功能,降低了接口实现的难度。BaseExecutor 的子类有三个,分别是 SimpleExecutor、ReuseExecutor 和 BatchExecutor。 SimpleExecutor : 简单执行器,是 MyBatis 中默认使用的执行器,每执行一次 update 或 select,就开启一个Statement 对象,用完就直接关闭 Statement 对象(可以是 Statement 或者是 PreparedStatment 对象) ReuseExecutor : 可重用执行器,这里的重用指的是重复使用 Statement,它会在内部使用一个 Map 把创建的Statement 都缓存起来,每次执行 SQL 命令的时候,都会去判断是否存在基于该 SQL 的 Statement 对象,如果存在 Statement 对象并且对应的 connection 还没有关闭的情况下就继续使用之前的 Statement 对象,并将其缓存起来。因为每一个 SqlSession 都有一个新的 Executor 对象,所以我们缓存在 ReuseExecutor 上的 Statement作用域是同一个 SqlSession。 BatchExecutor : 批处理执行器,用于将多个 SQL 一次性输出到数据库 CachingExecutor: 缓存执行器,先从缓存中查询结果,如果存在就返回之前的结果;如果不存在,再委托给Executor delegate 去数据库中取,delegate 可以是上面任何一个执行器。 Executor 的创建和选择 我们上面提到 Executor 是由 Configuration 创建的,Configuration 会根据执行器的类型创建,如下 这一步就是执行器的创建过程,根据传入的 ExecutorType 类型来判断是哪种执行器,如果不指定 ExecutorType ,默认创建的是简单执行器。它的赋值可以通过两个地方进行赋值: 可以通过 标签来设置当前工程中所有的 SqlSession 对象使用默认的 Executor <settings> <!--取值范围 SIMPLE, REUSE, BATCH --> <setting name="defaultExecutorType" value="SIMPLE"/> </settings> 另外一种直接通过Java对方法赋值的方式 session = factory.openSession(ExecutorType.BATCH); Executor 的具体执行过程 Executor 中的大部分方法的调用链其实是差不多的,下面是深入源码分析执行过程,如果你没有时间或者暂时不想深入研究的话,给你下面的执行流程图作为参考。 我们紧跟着上面的 selectList 继续分析,它会调用到 executor.query 方法。 当有一个查询请求访问的时候,首先会经过 Executor 的实现类 CachingExecutor ,先从缓存中查询 SQL 是否是第一次执行,如果是第一次执行的话,那么就直接执行 SQL 语句,并创建缓存,如果第二次访问相同的 SQL 语句的话,那么就会直接从缓存中提取。 上面这段代码是从 selectList -> 从缓存中 query 的具体过程。可能你看到这里有些觉得类都是什么东西,我想鼓励你一下,把握重点,不用每段代码都看,从找到 SQL 的调用链路,其他代码想看的时候在看,看源码就是很容易发蒙,容易烦躁,但是切记一点,把握重点。 上面代码会判断缓存中是否有这条 SQL 语句的执行结果,如果没有的话,就再重新创建 Executor 执行器执行 SQL 语句,注意, list = doQuery 是真正执行 SQL 语句的过程,这个过程中会创建我们上面提到的三种执行器,这里我们使用的是简单执行器。 到这里,执行器所做的工作就完事了,Executor 会把后续的工作交给 StatementHandler 继续执行。下面我们来认识一下 StatementHandler 上面代码会判断缓存中是否有这条 SQL 语句的执行结果,如果没有的话,就再重新创建 Executor 执行器执行 SQL 语句,注意, list = doQuery 是真正执行 SQL 语句的过程,这个过程中会创建我们上面提到的三种执行器,这里我们使用的是简单执行器。 到这里,执行器所做的工作就完事了,Executor 会把后续的工作交给 StatementHandler 继续执行。下面我们来认识一下 StatementHandler StatementHandler 的继承结构 有没有感觉和 Executor 的继承体系很相似呢?最顶级接口是四大组件对象,分别有两个实现类 BaseStatementHandler 和 RoutingStatementHandler,BaseStatementHandler 有三个实现类, 他们分别是 SimpleStatementHandler、PreparedStatementHandler 和 CallableStatementHandler。 RoutingStatementHandler : RoutingStatementHandler 并没有对 Statement 对象进行使用,只是根据StatementType 来创建一个代理,代理的就是对应Handler的三种实现类。在MyBatis工作时,使用的StatementHandler 接口对象实际上就是 RoutingStatementHandler 对象。 BaseStatementHandler : 是 StatementHandler 接口的另一个实现类,它本身是一个抽象类,用于简化StatementHandler 接口实现的难度,属于适配器设计模式体现,它主要有三个实现类 SimpleStatementHandler: 管理 Statement 对象并向数据库中推送不需要预编译的SQL语句。PreparedStatementHandler: 管理 Statement 对象并向数据中推送需要预编译的SQL语句。CallableStatementHandler:管理 Statement 对象并调用数据库中的存储过程。 StatementHandler 的创建和源码分析 我们继续来分析上面 query 的调用链路,StatementHandler 的创建过程如下 MyBatis 会根据 SQL 语句的类型进行对应 StatementHandler 的创建。我们以预处理 StatementHandler 为例来讲解一下 执行器不仅掌管着 StatementHandler 的创建,还掌管着创建 Statement 对象,设置参数等,在创建完 PreparedStatement 之后,我们需要对参数进行处理了。 如 如果用一副图来表示一下这个执行流程的话我想是这样 这里我们先暂停一下,来认识一下第三个核心组件 ParameterHandler ParameterHandler - ParameterHandler 介绍 ParameterHandler 相比于其他的组件就简单很多了,ParameterHandler 译为参数处理器,负责为 PreparedStatement 的 sql 语句参数动态赋值,这个接口很简单只有两个方法 ParameterHandler 只有一个实现类 DefaultParameterHandler , 它实现了这两个方法。 getParameterObject: 用于读取参数setParameters: 用于对 PreparedStatement 的参数赋值ParameterHandler 的解析过程 上面我们讨论过了 ParameterHandler 的创建过程,下面我们继续上面 parameterSize 流程 这就是具体参数的解析过程了,下面我们来描述一下 下面用一个流程图表示一下 ParameterHandler 的解析过程,以简单执行器为例 我们在完成 ParameterHandler 对 SQL 参数的预处理后,回到 SimpleExecutor 中的 doQuery 方法 上面又引出来了一个重要的组件那就是 ResultSetHandler,下面我们来认识一下这个组件 ResultSetHandler - ResultSetHandler 简介 ResultSetHandler 也是一个非常简单的接口 ResultSetHandler 是一个接口,它只有一个默认的实现类,像是 ParameterHandler 一样,它的默认实现类是DefaultResultSetHandler ResultSetHandler 解析过程 MyBatis 只有一个默认的实现类就是 DefaultResultSetHandler,DefaultResultSetHandler 主要负责处理两件事 处理 Statement 执行后产生的结果集,生成结果列表 处理存储过程执行后的输出参数 按照 Mapper 文件中配置的 ResultType 或 ResultMap 来封装成对应的对象,最后将封装的对象返回即可。 其中涉及的主要对象有: ResultSetWrapper : 结果集的包装器,主要针对结果集进行的一层包装,它的主要属性有 ResultSet : Java JDBC ResultSet 接口表示数据库查询的结果。 有关查询的文本显示了如何将查询结果作为java.sql.ResultSet 返回。 然后迭代此ResultSet以检查结果。 TypeHandlerRegistry: 类型注册器,TypeHandlerRegistry 在初始化的时候会把所有的 Java类型和类型转换器进行注册。 ColumnNames: 字段的名称,也就是查询操作需要返回的字段名称 ClassNames: 字段的类型名称,也就是 ColumnNames 每个字段名称的类型 JdbcTypes: JDBC 的类型,也就是 java.sql.Types 类型 ResultMap: 负责处理更复杂的映射关系 在 DefaultResultSetHandler 中处理完结果映射,并把上述结构返回给调用的客户端,从而执行完成一条完整的SQL语句。 内容转载自:CSDN博主:cxuann 原文链接:https://blog.csdn.net/qq_36894974/article/details/104132876?depth_1-utm_source=distribute.pc_feed.none-task&request_id=&utm_source=distribute.pc_feed.none-task

问问小秘 2020-03-05 15:44:27 0 浏览量 回答数 0

回答

Java之JVM垃圾回收 内存结构以及垃圾回收算法前言:由于小组技术分享的需要,懂的不是很多所以我就找了这个我自己感兴趣的知识点给大家做个简单的介绍。由于是新人,算不了很懂,只是总结性的讲了些概念性的东西。给大家分享的同时,算是给自己做个笔记吧。作为Java语言的核心之一,JVM垃圾回收帮我们解决了让我们很头疼的垃圾回收问题。我们不需要像VC++一样,作为内存管理的统治者需要我们对我们分配的每一块内存进行回收,否则就会造成内存泄露问题。是不是只要有JVM存在我们就不会出现内存泄露问题,出现内存泄露问题我们又该怎么办,如果我们想提高我们程序的稳定性和其他性能我们能从什么地方下手!!!相信这些问题是我们程序过程中不可逾越的。了解JVM的内存分配及其相应的垃圾回收机制,不仅仅是可以了解底层的JVM运行机制,而且对于程序性能的优化和提升还是很有必要的。一、JVM内存分配区域结构图一从图一可以看出JVM中的内存分配包括PC Register(PC寄存器) JVM栈 堆(Heap) 方法区域(MethodArea)运行时常量池(RuntimeConstant Pool) 本地方法堆栈(NativeMethod Stacks),这几部分区域但是从程序员的角度来看我们只关注JVM Heap和JVM Stack,因为这两部分是直接关系程序运行期间的内存状态,所以我会主要介绍这两部分内存,其他的我只是给出了简单的一些概念性解释:PC Register(Program Counter 寄存器):主要作用是记录当前线程所执行的字节码的行号。方法区域(MethodArea):方法区域存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,法区域也是全局共享的,它在虚拟机启动时在一定的条件下它也会被GC,当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。运行时常量池(RuntimeConstant Pool):存放的为类中的固定的常量信息、方法和Field的引用信息等,其空间从方法区域中分配。本地方法堆栈(NativeMethod Stacks):JVM采用本地方法堆栈来支持native方法的执行,此区域用于存储每个native方法调用的状态。JVM栈:主要存放一些基本类型的变量和对象的引用变量。JVM堆:用来存放由 new 创建的对象和数组Java 虚拟机的自动垃圾回收器来管理(注意数组也是对象,所以说数组也是存放在JVM堆中)。由于栈中存放的是主要存放一些基本类型的变量和对象的引用变量,所以当过了变量的作用区域或者是当程序运行结束后它所占用的内存会自动的释放掉,所以不用来关心,下面我们主要来说的是堆内存的分配以及回收的算法。二、JVM堆内存介绍工欲善其事,必先利其器。所以了解堆内存的内部结构是很必要的。在Jvm中堆空间划分为三个代:年轻代(Young Generation)、年老代(Old Generation)和永久代(Permanent Generation)。年轻带主要是动态的存储,年轻带主要储存新产生的对象,年老代储存年龄大些的对象,永久带主要是存储的是java的类信息,包括解析得到的方法、属性、字段等。永久带基本不参与垃圾回收。所以说我们说的垃圾回收主要是针对年轻代和年老代。图二年轻代又分成3个部分,一个eden区和两个相同的survior区。刚开始创建的对象都是放置在eden区的。分成这样3个部分,主要是为了生命周期短的对象尽量留在年轻带。当eden区申请不到空间的时候,进行minorGC,把存活的对象拷贝到survior。年老代主要存放生命周期比较长的对象,比如缓存对象。(经过IBM的一个研究机构研究数据表明,基本上80%-98%的对象都会在年轻代的Eden区死掉从而本回收掉,所以说真正进入到老年代的对象很少,这也是为什么MinorGC比MajorGC更加频繁的原因)具体JVM内存垃圾回收过程描述如下 :1、对象在Eden区完成内存分配2、当Eden区满了,再创建对象,会因为申请不到空间,触发minorGC,进行young(eden+1survivor)区的垃圾回收3、minorGC时,Eden不能被回收的对象被放入到空的survivor(Eden肯定会被清空),另一个survivor里不能被GC回收的对象也会被放入这个survivor,始终保证一个survivor是空的4、当做第3步的时候,如果发现survivor满了,则这些对象被copy到old区,或者survivor并没有满,但是有些对象已经足够Old,也被放入Old区 XX:MaxTenuringThreshold5、当Old区被放满的之后,进行fullGC补充: MinorGC:年轻代所进行的垃圾回收,非常频繁,一般回收速度也比较快。 MajorGC:老年代进行的垃圾回收,发生一次MajorGC至少伴随一次MinorGC,一般比MinorGC速度慢十倍以上。 FullGC:整个堆内存进行的垃圾回收,很多时候是MajorGC 以后就是堆内存结构已经大致的垃圾回收过程。三、对象分配原则1.对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC。2.大对象直接进入老年代(大对象是指需要大量连续内存空间的对象)。这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。3.长期存活的对象进入老年代。虚拟机为每个对象定义了一个年龄计数器,如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,知道达到阀值对象进入老年区。4.动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。5.空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC,如果小于检查HandlePromotionFailure设置,如果true则只进行Monitor GC,如果false则进行Full GC。四、垃圾收集器作为JVM中的核心之一垃圾收集器,主要完成的功能包括:(1)发现无用信息对象;(2)回收被无用对象占用的内存空间,使该空间可被程序再次使用。所以说我们在实现垃圾收集器的同时就要实现两个算法一个是发现无用的对象第二就是回收该对象的内存。收集器主要分为引用计数器和跟踪收集器两种,Sun JDK中采用跟踪收集器作为GC实现策略。发现无用对象只要的实现算法包括引用计数法和根搜索算法,引用计数法主要是JVM的早期实现方法,因为引用计数无法解决循环引用的问题,所以现在JVM实现的主要是根搜索算法,引用计数法:堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时,引用计数器置为1。当对象被赋给任意变量时,引用计数器每次加1当对象出了作用域后(该对象丢弃不再使用),引用计数器减1,一旦引用计数器为0,对象就不可用从而可以被回收。 根搜索算法:通过一系列的名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。目前的收集器主要有三种:串行收集器:使用单线程处理所有垃圾回收工作,因为无需多线程交互,所以效率比较高并行收集器:对年轻代进行并行垃圾回收,因此可以减少垃圾回收时间。一般在多线程多处理器机器上使用并发收集器:可以保证大部分工作都并发进行(应用不停止),垃圾回收只暂停很少的时间,此收集器适合对响应时间要求比较高的中、大规模应用五、垃圾收集器的回收算法Copying算法:算法:复制采用的方式为从根集合扫描出存活的对象,并将找到的存活对象复制到一块新的完全未使用的空间中。 过程: 此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。次算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不过出现“碎片”问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间。Mark-Sweep算法: 算法:标记-清除采用的方式为从根集合开始扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未标记的对象,并进行回收。 过程: 第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。它停止所有工作,收集器从根开始访问每一个活跃的节点,标记它所访问的每一个节点。走过所有引用后,收集就完成了,然后就对堆进行清除(即对堆中的每一个对象进行检查),所有没有标记的对象都作为垃圾回收并返回空闲列表。Mark-Compact算法: 算法:标记阶段与“Mark-Sweep”算法相同,但在清除阶段有所不同。在回收不存活对象所占用的内存空间后,会将其他所有存活对象都往左端空闲的空间进行移动,并更新引用其对象指针。过程:此算法结合了“标记-清除”和“复制”两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象“压缩”到堆的其中一块,按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。Sun JDK GC策略:新生代算法实现:Copying,Copying,Copying旧生代算发实现:Mark-Sweep-Compact,Mark –Compact,Mark –Sweep!!六、JvisuaVM 工具如果我们想优化自己的程序,那么我们就必须清楚的了解不同代码程序所消耗的性能多少,作为JDK的一部分,这个工具给我们提供了很大的帮助。这个工具可以在JDK的bin目录下找到,功能很强大,可以注意利用

auto_answer 2019-12-02 01:56:35 0 浏览量 回答数 0

问题

SSH面试题

琴瑟 2019-12-01 21:46:22 3489 浏览量 回答数 0

回答

最优的解决方案就是不用struts2了,改用springmvc,我保证,你用了之后就会再也不想用回来struts2的######真的吗?谢谢。######要获取session不应该使用这种方式,在省城bean的时候这个方法返回的还是空指针,要获取session应该是实现相应的接口,完成依赖注入######回复 @颖辉小居 : 没毛病啊,不就是存值取值嘛,这里面的值和httpsession的值是对应的。@controller注解原先是给springmvc使用的,默认是单例,但是struts2用的时候不要单例,每次请求新建######回复 @阿信sxq : 这个拿到的是map不是HttpSession @Override public void setSession(Map<String, Object> session) { this.session=session; }######回复 @阿信sxq : 谢谢,还有一个问题:spring配置action时该使用单例还是其他的作用域?######回复 @颖辉小居 : 实现“org.apache.struts2.interceptor.SessionAware“即可######可以说的详细点吗?######自己顶 ######异常原因分析:因为action加了注解,而容器使用的是ApplicationContext(默认启动容器立即加载Bean)。在action中使用了父类BaseAction的属性session,所以启动Spring容器时就会调用session的初始化方法ServletActionContext.getRequest() .getSession();此时,没有用户访问,也就没有请求,所以request为空,调用.getSession()方法时报空指针。 ######新的疑问:spring容器applicationContext默认创建Bean是单例作用域。Struts2的action是多例的,如果给action加上注解被Spring管理。会不会在作用域上又冲突?######第三种办法:不在action上加Spring注解(即不被Spring管理)。Struts2会自动为每一次请求创建一个action实例(线程安全),未发现什么问题。######第二种办法IOC注入: BaseAction实现接口ServletRequestAware 并实现方法setServletRequest。可以注入HttpRequest实例,通过request.getSession()获得HttpSession######找到一个解决办法给ACTION加注解@Lazy(true),但是感觉这个不是最好的办法。######想不到还有人在使用struts。。。。。

kun坤 2020-06-06 20:06:16 0 浏览量 回答数 0

回答

最优的解决方案就是不用struts2了,改用springmvc,我保证,你用了之后就会再也不想用回来struts2的######真的吗?谢谢。######要获取session不应该使用这种方式,在省城bean的时候这个方法返回的还是空指针,要获取session应该是实现相应的接口,完成依赖注入######回复 @颖辉小居 : 没毛病啊,不就是存值取值嘛,这里面的值和httpsession的值是对应的。@controller注解原先是给springmvc使用的,默认是单例,但是struts2用的时候不要单例,每次请求新建######回复 @阿信sxq : 这个拿到的是map不是HttpSession @Override public void setSession(Map<String, Object> session) { this.session=session; }######回复 @阿信sxq : 谢谢,还有一个问题:spring配置action时该使用单例还是其他的作用域?######回复 @颖辉小居 : 实现“org.apache.struts2.interceptor.SessionAware“即可######可以说的详细点吗?######自己顶 ######异常原因分析:因为action加了注解,而容器使用的是ApplicationContext(默认启动容器立即加载Bean)。在action中使用了父类BaseAction的属性session,所以启动Spring容器时就会调用session的初始化方法ServletActionContext.getRequest() .getSession();此时,没有用户访问,也就没有请求,所以request为空,调用.getSession()方法时报空指针。 ######新的疑问:spring容器applicationContext默认创建Bean是单例作用域。Struts2的action是多例的,如果给action加上注解被Spring管理。会不会在作用域上又冲突?######第三种办法:不在action上加Spring注解(即不被Spring管理)。Struts2会自动为每一次请求创建一个action实例(线程安全),未发现什么问题。######第二种办法IOC注入: BaseAction实现接口ServletRequestAware 并实现方法setServletRequest。可以注入HttpRequest实例,通过request.getSession()获得HttpSession######找到一个解决办法给ACTION加注解@Lazy(true),但是感觉这个不是最好的办法。######想不到还有人在使用struts。。。。。

kun坤 2020-05-27 17:25:05 0 浏览量 回答数 0

回答

最优的解决方案就是不用struts2了,改用springmvc,我保证,你用了之后就会再也不想用回来struts2的######真的吗?谢谢。######要获取session不应该使用这种方式,在省城bean的时候这个方法返回的还是空指针,要获取session应该是实现相应的接口,完成依赖注入######回复 @颖辉小居 : 没毛病啊,不就是存值取值嘛,这里面的值和httpsession的值是对应的。@controller注解原先是给springmvc使用的,默认是单例,但是struts2用的时候不要单例,每次请求新建######回复 @阿信sxq : 这个拿到的是map不是HttpSession @Override public void setSession(Map<String, Object> session) { this.session=session; }######回复 @阿信sxq : 谢谢,还有一个问题:spring配置action时该使用单例还是其他的作用域?######回复 @颖辉小居 : 实现“org.apache.struts2.interceptor.SessionAware“即可######可以说的详细点吗?######自己顶 ######异常原因分析:因为action加了注解,而容器使用的是ApplicationContext(默认启动容器立即加载Bean)。在action中使用了父类BaseAction的属性session,所以启动Spring容器时就会调用session的初始化方法ServletActionContext.getRequest() .getSession();此时,没有用户访问,也就没有请求,所以request为空,调用.getSession()方法时报空指针。 ######新的疑问:spring容器applicationContext默认创建Bean是单例作用域。Struts2的action是多例的,如果给action加上注解被Spring管理。会不会在作用域上又冲突?######第三种办法:不在action上加Spring注解(即不被Spring管理)。Struts2会自动为每一次请求创建一个action实例(线程安全),未发现什么问题。######第二种办法IOC注入: BaseAction实现接口ServletRequestAware 并实现方法setServletRequest。可以注入HttpRequest实例,通过request.getSession()获得HttpSession######找到一个解决办法给ACTION加注解@Lazy(true),但是感觉这个不是最好的办法。######想不到还有人在使用struts。。。。。

montos 2020-05-31 08:12:29 0 浏览量 回答数 0

问题

【分享】WeX5的正确打开方式(2)

小太阳1号 2019-12-01 21:17:14 3935 浏览量 回答数 1

回答

在Linux服务器之间建立信任关系,是很多线上服务系统的基础性工作,这样能便于程序在多台服务器之间自动传输数据,或者方便用户不输入密码就可以在不同的主机间完成登录或者各种操作。 网上关于建立Linux信任关系(ssh trust)的中文文章有一些,但是写得都不太详细,这里汇总了方方面面的资料,把多机信任关系建立方法说说清楚(文/陈运文) 一 建立信任关系的基本操作 基本场景是想从一台Server服务器直接登录另一台,或者将Server服务器的数据不需密码验证直接拷贝至Client服务器,以下我们简称Server服务器为S(待发送的数据文件在这台服务器上),Client服务为C,信任关系的最简单操作方法如下: 1 在S服务器上,进入当前用户根目录下的隐藏目录 .ssh,命令如下: cd ~/.ssh (注:目录名前的点好”.”表示该文件夹是一个特殊的隐藏文件夹,ls命令下默认是看不到的,通过 ls –a 命令观察到) 2 生成S服务器的私钥和公钥: ssh-keygen -t rsa (注:rsa是一种加密算法的名称,此处也可以使用dsa,关于rsa和dsa算法的介绍可见本文后半章节) ssh-keygen生成密钥用于信任关系生成 -此时会显示Generating public/private key pair. 并提示生成的公钥私钥文件的存放路径和文件名,默认是放在 /home/username/.ssh/id_rsa 这样的文件里的,通常不用改,回车就可以 然后Enter passphrase(empty for no passphrase): 通常直接回车,默认不需要口令 Enter same passphrase again: 也直接回车 然后会显式密钥fingerprint生成好的提示,并给出一个RSA加密协议的方框图形。此时在.ssh目录下ls,就可以看到生成好的私钥文件id_rsa和公钥文件id_rsa.pub了 以下是各种补充说明: 注1:如果此时提示 id_rsaalready exists,Overwrite(y/n) 则说明之前已经有人建好了密钥,此时选择n 忽略本次操作就行,可以直接用之前生成好的文件;当然选y覆盖一下也无妨 注2:公钥用于加密,它是向所有人公开的(pub是公开的单词public的缩写);私钥用于解密,只有密文的接收者持有。 3 在Server服务器上加载私钥文件 仍然在.ssh目录下,执行命令: ssh-add id_rsa 系统如果提示:Identity added: id_rsa (id_rsa) 就表明加载成功了 下面有几个异常情况处理: –如果系统提示:could not open a connection to your authentication agent 则需要执行一下命令: ssh-agent bash 然后再执行上述的ssh-add id_rsa命令 –如果系统提示id_rsa: No such file or directory 这是系统无法找到私钥文件id_rsa,需要看看当前路径是不是不在.ssh目录,或者私钥文件改了名字,例如如果建立的时候改成 aa_rsa,则这边命令中也需要相应改一下 -如果系统提示 command not found,那肯定是你命令敲错字符了J -提示Agent admitted failure to sign using the key,私钥没有加载成功,重试ssh-add -注意id_rsa/id_rsa.pub文件不要删除,存放在.ssh目录下 4 把公钥拷贝至Client服务器上 很简单,例如 scp id_rsa.pub user@10.11.xx.xx:~ 5 ssh登录到Client服务器上,然后在Client服务器上,把公钥的内容追加到authorized_keys文件末尾(这个文件也在隐藏文件夹.ssh下,没有的话可以建立,没有关系) cat id_rsa.pub >> ~/.ssh/authorized_keys 以下是各种补充说明,遇到问题时可以参考: 注1:这里不推荐用文件覆盖的方式,有些教程直接scp id_rsa.pub 到Client服务器的authorized_keys文件,会导致之前建的其他信任关系的数据被破坏,追加到末尾是更稳妥的方式; 注2: cat 完以后,Client服务器上刚才拷贝过来的id_rsa.pub文件就不需要了,可以删除或移动到其它地方) 注3:ssh-keygen 命令通过-b参数可以指定生成的密钥文件的长度,如果不指定则默认为1024,如果ssh-keygen –b 4096(最长4096),则加密程度提高,但是生成和验证时间会增加。对一般的应用来说,默认长度已经足够胜任了。如果是rsa加密方式,那么最短长度为768 byte 注4:authorized_keys文件的权限问题。如果按上述步骤建立关系后,仍然要验证密码,并且没有其他报错,那么需要检查一下authorized_keys文件的权限,需要作下修改: chmod g-w authorized_keys OK,现在试试在Server端拷贝一个文件到Client服务器,应该无需交互直接就传过去了。 但是此时从Client传数据到Server服务器,仍然是需要密码验证的。如果需要两台服务器间能直接互传数据,则反过来按上述步骤操作一下就可以了 二 删除服务器间信任关系的方法 如果想取消两台服务器之间的信任关系,直接删除公钥或私钥是没有用的,需要在Client服务器上,打开 ~/.ssh/ authorized_keys 文件,找到对应的服务器的公钥字段并删除 每个段落的开头是ssh-rsa字样,段尾是Server服务器的帐号和ip(如下图红框),需要细心的找一下后删除整段 密钥文件内容和删除Linux服务器间信任关系的方法 三 各种可能遇到的情况和处理方法 –提示 port 22: Connection refused 可能的原因:没有正确安装最新的openssh-server,安装方法如下 sudo apt-get install openssh-server 不支持apt安装的,可以手工下载: wget ftp.ssh.com/pub/ssh/ssh-3.2.9.1.tar.gz –关于目录和文件的权限设置 .ssh目录的权限必须是700,同时本机的私钥的权限必须设置成600: chmod 600 id_rsa 否则ssh服务器会拒绝登录 四 关于RSA和DSA加密算法 在ssh-keygen命令中,-t参数后指定的是加密算法,可以选择rsa或者dsa RSA 取名自算法的三位提出者Ron Rivest, Adi Shamir, and Leonard Adleman的姓名首字母,作为一种非对称加密算法,RSA的安全性基于及其困难的大整数分解(两个素数的乘积的还原问题)。关于RSA算法原理的文章很多,感兴趣的朋友可以找来读一读。 DSA = Digital Signature Algorithm,基于有限域离散对数难题,是Schnorr和ElGamal签名算法的变种,一般用于数字签名和认证,被美国标准局(NIST)采纳为数字签名标准DSS(Digital Signature Standard),based on discrete logarithms computation. DES = Digital Encryption Standard. Obsolete standard. RSA算法好在网络容易实现密钥管理,便进行数字签名,算法复杂,加/解速度慢,采用非对称加密。在实际用于信任关系建立中,这两种方法的差异很微小,可以挑选其一使用。 五 关于SSH协议的介绍 SSH全称Secure SHell,顾名思义就是非常安全的shell的意思,SSH协议是IETF(Internet Engineering Task Force)的Network Working Group所制定的一种协议。SSH的主要目的是用来取代传统的telnet和R系列命令(rlogin,rsh,rexec等)远程登陆和远程执行命令的工具,实现对远程登陆和远程执行命令加密。防止由于网络监听而出现的密码泄漏,对系统构成威胁。 ssh协议目前有SSH1和SSH2,SSH2协议兼容SSH1。目前实现SSH1和SSH2协议的主要软件有OpenSSH和SSH Communications Security Corporation 公司的SSH Communications 软件。前者是OpenBSD组织开发的一款免费的SSH软件,后者是商业软件,因此在linux、FreeBSD、OpenBSD、NetBSD等免费类UNIX系统种,通畅都使用OpenSSH作为SSH协议的实现软件。因此,本文重点介绍一下OpenSSH的使用。需要注意的是OpenSSH和SSH Communications的登陆公钥/私钥的格式是不同的,如果想用SSH Communications产生的私钥/公钥对来登入到使用OpenSSH的linux系统需要对公钥/私钥进行格式转换。 第一次登陆后,ssh就会把登陆的ssh指纹存放在用户home目录的.ssh目录的know_hosts文件中,如果远程系统重装过系统,ssh指纹已经改变,你需要把 .ssh 目录下的know_hosts中的相应指纹删除,再登陆回答yes,方可登陆。请注意.ssh目录是开头是”.”的隐藏目录,需要ls –a参数才能看到。而且这个目录的权限必须是700,并且用户的home目录也不能给其他用户写权限,否则ssh服务器会拒绝登陆。如果发生不能登陆的问题,请察看服务器上的日志文件/var/log/secure。通常能很快找到不能登陆的原因。 六 关于ssh_config和sshd_config文件配置的说明 /etc/ssh/ssh_config: Host * 选项“Host”只对能够匹配后面字串的计算机有效。“*”表示所有的计算机。 ForwardAgent no “ForwardAgent”设置连接是否经过验证代理(如果存在)转发给远程计算机。 ForwardX11 no “ForwardX11”设置X11连接是否被自动重定向到安全的通道和显示集(DISPLAY set)。 RhostsAuthentication no “RhostsAuthentication”设置是否使用基于rhosts的安全验证。 RhostsRSAAuthentication no “RhostsRSAAuthentication”设置是否使用用RSA算法的基于rhosts的安全验证。 RSAAuthentication yes “RSAAuthentication”设置是否使用RSA算法进行安全验证。 PasswordAuthentication yes “PasswordAuthentication”设置是否使用口令验证。 FallBackToRsh no “FallBackToRsh”设置如果用ssh连接出现错误是否自动使用rsh。 UseRsh no “UseRsh”设置是否在这台计算机上使用“rlogin/rsh”。 BatchMode no “BatchMode”如果设为“yes”,passphrase/password(交互式输入口令)的提示将被禁止。当不能交互式输入口令的时候,这个选项对脚本文件和批处理任务十分有用。 CheckHostIP yes “CheckHostIP”设置ssh是否查看连接到服务器的主机的IP地址以防止DNS欺骗。建议设置为“yes”。 StrictHostKeyChecking no “StrictHostKeyChecking”如果设置成“yes”,ssh就不会自动把计算机的密匙加入“$HOME/.ssh/known_hosts”文件,并且一旦计算机的密匙发生了变化,就拒绝连接。 IdentityFile ~/.ssh/identity “IdentityFile”设置从哪个文件读取用户的RSA安全验证标识。 Port 22 “Port”设置连接到远程主机的端口。 Cipher blowfish “Cipher”设置加密用的密码。 EscapeChar ~ “EscapeChar”设置escape字符。 /etc/ssh/sshd_config: Port 22 “Port”设置sshd监听的端口号。 ListenAddress 192.168.1.1 “ListenAddress”设置sshd服务器绑定的IP地址。 HostKey /etc/ssh/ssh_host_key “HostKey”设置包含计算机私人密匙的文件。 ServerKeyBits 1024 “ServerKeyBits”定义服务器密匙的位数。 LoginGraceTime 600 “LoginGraceTime”设置如果用户不能成功登录,在切断连接之前服务器需要等待的时间(以秒为单位)。 KeyRegenerationInterval 3600 “KeyRegenerationInterval”设置在多少秒之后自动重新生成服务器的密匙(如果使用密匙)。重新生成密匙是为了防止用盗用的密匙解密被截获的信息。 PermitRootLogin no “PermitRootLogin”设置root能不能用ssh登录。这个选项一定不要设成“yes”。 IgnoreRhosts yes “IgnoreRhosts”设置验证的时候是否使用“rhosts”和“shosts”文件。 IgnoreUserKnownHosts yes “IgnoreUserKnownHosts”设置ssh daemon是否在进行RhostsRSAAuthentication安全验证的时候忽略用户的“$HOME/.ssh/known_hosts” StrictModes yes “StrictModes”设置ssh在接收登录请求之前是否检查用户家目录和rhosts文件的权限和所有权。这通常是必要的,因为新手经常会把自己的目录和文件设成任何人都有写权限。 X11Forwarding no “X11Forwarding”设置是否允许X11转发。 PrintMotd yes “PrintMotd”设置sshd是否在用户登录的时候显示“/etc/motd”中的信息。 SyslogFacility AUTH “SyslogFacility”设置在记录来自sshd的消息的时候,是否给出“facility code”。 LogLevel INFO “LogLevel”设置记录sshd日志消息的层次。INFO是一个好的选择。查看sshd的man帮助页,已获取更多的信息。 RhostsAuthentication no “RhostsAuthentication”设置只用rhosts或“/etc/hosts.equiv”进行安全验证是否已经足够了。 RhostsRSAAuthentication no “RhostsRSA”设置是否允许用rhosts或“/etc/hosts.equiv”加上RSA进行安全验证。 RSAAuthentication yes “RSAAuthentication”设置是否允许只有RSA安全验证。 PasswordAuthentication yes “PasswordAuthentication”设置是否允许口令验证。 PermitEmptyPasswords no “PermitEmptyPasswords”设置是否允许用口令为空的帐号登录。 AllowUsers admin “AllowUsers”的后面可以跟着任意的数量的用户名的匹配串(patterns)或user@host这样的匹配串,这些字符串用空格隔开。主机名可以是DNS名或IP地址。

boxti 2019-12-02 01:27:05 0 浏览量 回答数 0
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 云栖号物联网 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 云栖号弹性计算 阿里云云栖号 云栖号案例 云栖号直播