业务场景篇
Spring的概述
Spring是完全面向接口的设计,降低程序耦合性,主要是事务控制并创建bean实例对象。在ssh整合时,充当黏合剂的作用。IOC(Inversion of Control) 控制反转/依赖注入,又称DI(Dependency Injection) (依赖注入)
IOC的作用:产生对象实例,所以它是基于工厂设计模式的
Spring IOC的注入
通过属性进行注入,通过构造函数进行注入,
注入对象数组注入List集合
注入Map集合 注入Properties类型
Spring IOC自动绑定模式:
可以设置autowire按以下方式进行绑定
按byType只要类型一致会自动寻找,
按byName自动按属性名称进行自动查找匹配.
AOP面向方面(切面)编程
AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向方面(切面)编程。
注:OOP(Object-Oriented Programming )面向对象编程
AOP主要应用于日志记录,性能统计,安全控制,事务处理(项目中使用的)等方面。
Spring中实现AOP技术:
在Spring中可以通过代理模式来实现AOP
代理模式分为
静态代理:一个接口,分别有一个真实实现和一个代理实现。
动态代理:通过代理类的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联。
动态代理有两种实现方式,可以通过jdk的动态代理实现也可以通过cglib来实现而AOP默认是通过jdk的动态代理来实现的。jdk的动态代理必须要有接口的支持,而cglib不需要,它是基于类的。
Spring AOP事务的描述:
在spring-common.xml里通过<aop:config>里面先设定一个表达式,设定对service里那些方法 如:对add* ,delete*,update*等开头的方法进行事务拦截。我们需要配置事务的传播(propagation="REQUIRED")特性,通常把增,删,改以外的操作需要配置成只读事务(read-only="true").只读事务可以提高性能。之后引入tx:advice,在tx:advice引用 transactionManager(事务管理),在事务管理里再引入sessionFactory,sessionFactory注入 dataSource,最后通过<aop:config> 引入txAdvice。
Spring实现ioc控制反转描述:
原来需要我们自己进行bean的创建以及注入,而现在交给spring容器去完成bean的创建以及注入。
所谓的“控制反转”就是 对象控制权的转移,从程序代码本身转移到了外部容器。
官方解释:
控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
事务概述 √
在数据库中,所谓事务是指一组逻辑操作单元即一组sql语句。当这个单元中的一部分操作失败,整个事务回滚,只有全部正确才完成提交。
事务的ACID属性
1.原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2.一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。(数据不被破坏)
3.隔离性(Isolation)
事务的隔离性是指一个事务的执行不能被其他事务干扰.
4.持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的.即使系统重启数据也不会丢失;在JDBC中,事务默认是自动提交的,每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚
为了让多个SQL语句作为一个事务执行:
(1)执行语句前调用 Connection 对象的 setAutoCommit(false);
以取消自动提交事务
(2)在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务
(3)在出现异常时,调用 rollback(); 方法回滚事务。
权限概述
权限涉及到5张表:
用户表,角色表,权限表(菜单表),用户角色关联表,角色权限关联表
当用户登录时,根据用户名和密码到用户表验证信息是否合法,如果合法则获取用户信息,之后根据用户id再到用户角色关联表中得到相关连的角色id集合,之后根据角色id再到角色权限关联表中获取该角色所拥有的权限id集合,然后再根据权限id集合到权限表(菜单表)中获取具体的菜单,展现给当前登录用户,从而达到不同用用户看到不同的菜单权限。
我们通过ZTree来给角色赋权并且通过ZTree来展示菜单,以及通过ZTree来管 理菜单即增加和编辑菜单。
我们做的权限控制到url级别,为了防止用户不登录直接输入url访问的这个弊端,通过拦截器进行拦截验证。
OSCache业务场景
在我以前的项目中,我们考虑了系统性能问题,这个时候我们采用了Oscache缓存,刚开始把这个功能交给了项目组中的另外一个同事来做的,但是他做完的时候他发现缓存中明明已经缓存了数据,但是在取得时候发现没有数据,我们项目经理让我去帮忙看看这个问题,我阅读完他的代码之后,我发现了他每次缓存的时候都是调用一个新的缓存对象的方法,结果出现了明明已经走了缓存的方法而取不到数据的问题,通过我多年的工作经验,我就想到了应该用单例模式去封装一个单例工具类来调用oscache。但是,在后来的测试过程中,发现当并发访问的时候也会出现上述的问题,这个时候我直接采取的DCL(双重判定锁)单例模式封装了工具类,既解决了线程安全问题,相对的性能问题也考虑到了,这个问题才得到了完善的解决。
线程概述
线程的状态以及状态之间的相互转换:
1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
实现线程的两种方式:
是继承Thread类或实现Runnable接口,但不管怎样,当new了这个对象后,线程就已经进入了初始状态
wait和sleep的区别:
线程访问:
锁池状态,之后等待锁释放,然后访问代码
wait
等待队列(释放资源)--->调用notify或者notifyall之后锁池状态--->( 等待锁释放)--->可运行状态--->运行状态---->访问代码
sleep,join
不释放资源-->结束后直接进入可运行状态--->运行状态---->访问代码
一个java控制台程序,默认运行两个线程,一个主线程,一个垃圾回收线程。
线程与进程的区别:
1.线程(Thread)与进程(Process)
进程定义的是应用程序与应用程序之间的边界,通常来说一个进程就代表一个与之对应 的应用程序。不同的进程之间不能共享代码和数据空间,而同一进程的不同线程可以共 享代码和数据空间。
2.一个进程可以包括若干个线程,同时创建多个线程来完成某项任务,便是多线程。
Ajax请求Session超时问题
我在做项目时有时会遇到session超时问题,如果session超时,平常请求没有什么问题,通过拦截器可以正确跳到登陆页面,可是你如果用ajax请求的话这就出现问题了,因为ajax是异步的,局部刷新,所以登陆界面不会再全页面中显示,他只会显示到页面的一部分当中。所以根据我这几年的经验找到了我认为比较好的一种方法。因为那我用的框架是和struts2集成的,所以就在拦截器中进行设置:
首先判断session是否为空就是判断session是否超时,如果超时就取出请求的head头信息request.getHeader("x-requested-with"),如果不为空就和XMLHttpRequest(Ajax标识)进行比较 (request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest"))) 如果相等说明此请求是ajax请求。
如果是ajax请求就可以用response.setHeader("键","值")来设置一个标识来告诉用户这是ajax请求并且session超时时发出的,这样我就可以在回调函数中取出自己设置的那个唯一标识:XMLHttpRequest.getResponseHeader("");如果取出的值是和自己在后台中设置的值一样的话,就证明session已经超时,这样就可以设置window.location.replace("登陆界面"),来跳转到登陆界面了。
这样做虽然解决了问题,但是,会在每个回调函数中写入那些代码,这样的话代码就会显得特别零散,所以就想能不能定义一个全局的设置所以就找到了jqery的ajaxSetUp方法,通过ajaxSetUp对jqery的ajax进行全局的判断(ajaxSetUp就相当于ajax的拦截器),通过设置ajaxSetUp里的complete,它就相当于回调函数,这样那就弥补了上一方法的不足。
我做项目时还用到$(document).ajaxStart(),这是ajax请求时的事件;$(document).ajaxSuccess(),这是AJAX请求成功后的事件。我一般用他们来显示遮罩层和隐藏遮罩层用的加遮罩层是为了不让用户重复提交,更提高了用户体验度,让用户知道已经提交了。
java线程池概述
java线程池的工作原理和数据库连接池的差不多,因为每次重新创建线程都是很耗资源的操作,所以我们可以建立一个线程池,这样当需要用到线程进行某些操作时,就可以直接去线程池里面找到空闲的线程,这样就可以直接使用,而不用等到用到的时候再去创建,用完之后可以把该线程重新放入线程池供其他请求使用从而提高应用程序的性能。
线程池的核心流程:
1.构建一个 ThreadPoolExecutor 并指定默认要创建的线程的数量
2.通过 threadPool.execute()
去添加一个个要执行的线程即实现了Runable接口的java类
3.在实现了Runable接口的java类的run方法中写入具体的业务代码
线程池的业务场景:
我在工作的时候,当时一个同事给我提了一个需求,目前有大量的图片需要处理生产缩略图并进行加水印,因为按照普通的处理方法一个个的进行处理太慢了,问我有没有好的解决方案,这个时候我就想到了java中的线程池,我构建了一个线程数为5个线程池,然后采用分段批量提取的方式每500条为一组数据进行图片信息的提取,然后再把这些通过Threadpool的execute方法交给线程池中的线程进行处理,即充分使用CPU硬件资源又加快了大数据情况下程序的处理效率。
我当时在工作的过程中,认识一个做电商的朋友,他们当时公司才起步,很多技术都不成熟,所以就常常和我探讨一些技术问题,有次他向我请教一个问题,问我如何才能提高网站的性能,我根据自己在项目中的经验以及自己以前阅读的关于优化方面的资料给他提出了很多建议,如用lucene进行全文检索,用memcached进行分布式缓存,以及通过spring定时器结合freeMarker模板引擎来生成静态页面,由于要生成的页面的数量比较多,考虑到程序的性能,我建议他结合java的线程池进行工作,这样就可以充分使用了CPU硬件资源又加快了大数据情况下程序的处理效率。
如果你依然觉得有些茫然,不如加入我的Java架构师之路:766529531 跟有多年Java开发经验的资深工程师聊一聊。也可获取免费的视频学习资料以及电子书学习资料喔!
OSCache概述
oscache是一个高性能的j2ee框架,可以和任何java代码进行集成,并且还可以通过标签对页面内容进行缓存,还以缓存请求。我们通常将那些频繁访问但是又不是经常改变的数据进行缓存。为了保证缓存数据的有效性,在数据发生改变的时候,我们要刷新缓存,避免脏数据的出现。刷新缓存的策略有两种,一种是定时刷新,一种手动刷新。缓存数据的时机通常也分为两种,即在tomcat(web容器)启动时候加载数据进行缓存,另外也可以在用户第一次访问数据的时候进行缓存,这个相当于缓存的立即加载和按需加载。
缓存的层次如下:jsp-->action-->service-->dao,缓存越靠前对性能的提升越大,一个action里面可以有多个service,一个service中可以有多个dao或者多个service,任何类之间都可以进行相互调用,可以通过构造函数传参,set,get传参或者是方法传 参将相关的类连接起来。
OSCache+autocomplete+单例业务场景
在我以前做某项目的过程中,其中我们在做产品列表的查询的时候为了提高用户的体验度,我们使用了autocomplete插件来代替select进行品牌的选择,才开始的时候每次都要根据用户输入的信息去查询数据库进行模糊匹配返回结果,后来我们考虑到系统的性能,因此我们采用了oscache缓存,才开始这个功能是交给我们项目组中的另外一个同事来做的,但是他做完后,我们在使用这个工具类的时候,发现有时缓存中明明已经有时我们需要的数据,但是从缓存里面取的时候,发现没有,之后项目经理让我去帮这个同事看看这个问题,我经过阅读他的代码发现,它里面在使用缓存的时候,针对于每次方法的调用都产生一个新的实例,结果导致了上面的问题,这个时候我想起了可以使用设计模式中的单例模式来解决这个问题,才开始我直接采用了普通的单列模式,但是后来在测试的过程中,发现当用户并发量大的时候还是会出现上面的问题,之后我再次考虑了代码,最后发现是因为没有给单列模式加锁的原因,从而导致了大用户并发的时候,线程安全的问题,之后我便在方法上加上了synchronized关键字,解决上述的问题,但是后来测试人员反馈,觉的这段的性能有问题,我考虑之后便采用在方法体内加锁并结合双重判定的方式解决了上面的问题。我们是将数据在tomcat启动的时候加载到缓存中,之后用户进行查询的时候直接从缓存中获取数据,根据前缀匹配进行查询,将结果返回给用户。这样在提高用户体验度的同时也提高性能。
缓存概述
应用程序为了提高性能,可以通过使用缓存来达到目的,缓存的存储介质可以内存或者硬盘,通常将数据存储在内存里,确切的说是jvm的内存中,缓存是基于Map这种思想构建的,以键值对的方式进行存取,之所以还可以将缓存的数据存储在硬盘中,是因为内存资源相当有限和宝贵,所以当内存资源不足的时候,就可以将其存储到硬盘中,虽然硬盘的存取速度比内存要慢,但是因为减少了网络通信量,所以还是提高程序的性能。缓存可以分为客户端缓存和服务器端缓存,所谓的客户端缓存通常指的是IE浏览器的缓存,服务器端缓存指的web服务器的缓存,通常可以通过第三方组件实现,如oscache,memcache
我们通常将那些频繁访问但是又不是经常改变的数据进行缓存。为了保证缓存数据的有效性,在数据发生改变的时候,我们要刷新缓存,避免脏数据的出现。刷新缓存的策略有两种,一种是定时刷新,一种手动刷新。
缓存的层次如下:jsp-->action-->service(通常放置在service)-->dao,缓存越靠前对性能的提升越大
缓存的策略:(缓存空间不足需要进行清理的时候使用)
LRU:最近最少使用原则.(理解:存储书)
FIFO:先进先出的缓存策略.(理解:排队)
你来说说缓存?说说你对缓存的理解(如果遇到重复的,就可以省略)
我们在项目中使用缓存的目的是为了提高应用程序的性能,减少访问数据库的次数,从而提高应用程序的吞吐量。我们通常将权限,菜单,组织机构这些频繁访问但是不经常改变的基础数据进行缓存,其中我在做()某某项目的时候就通过oscache对ZTree的树形菜单进行了缓存,并且在做的时候和单列设计模式进行结合,考虑到多线程下的安全问题,还对单例模式加入了双重判定锁的检查方式。
实现页面静态化业务场景
我们在做某项目时,涉及到程序访问的性能问题,这时候我们想到可以通过静态化来提高用户访问时候的性能,所以我们就采用了freemarker模板引擎,考虑到页面也是要有动态的变化的,所以我们采用spring定时器在每天晚上2点钟的时候定时再次生成html静态页面,考虑发布时候的性能问题,我们又采取线程池技术,让多个线程同时发布,从而缩减发布时间。
servlet线程安全描述
servlet是单列的,对于所有请求都使用一个实例,所以如果有全局变量被多线程使用的时候,就会出现线程安全问题。
解决这个问题有三种方案:
1.实现singleThreadModel接口,这样对于每次请求都会创建一个新的servlet实例,这样就会消耗服务端内存,降低性能,但是这个接口已经过时,不推荐使用。
2.可以通过加锁(synchroniezd关键字)来避免线程安全问题。这个时候虽然还是单列,但是对于多线程的访问,每次只能有一个请求进行方法体内执行,只有执行完毕后,其他线程才允许访问,降低吞吐量。
3.避免使用全局变量,使用局部变量可以避免线程安全问题,强烈推荐使用此方法来解决servlet线程安全的问题。
(jbpm4)工作流引擎描述:
JPBM是JBOSS旗下的一个开源的基于hibernate的工作流引擎。工作流就是在日常生活中,我们一些常见的如请假流程、采购流程、入职流程,通俗的来讲就是一些在现实生活中的流程以信息化以程序的方式实现。
一个工作流首先需要进行流程定义,流程定义是由节点和跳转组成的,节点又可以称为环节、活动节点、活动环节,并且节点也可以分为两大类型:人工节点和自动节点,人工节点有start开始节点、end结束节点、task任务节点,自动节点有decision判断节点、fork分支节点、join聚合节点和state状态节点,并且一个流程有且只有一个开始节点,但可以有多个结束节点。
流程定义是静止的,它在运行状态时会转换成流程实例,一个流程定义可以对应多个流程实例。流程运行后,会产生两个文件,*.jdpl.xml文件和*.png图片文件,也会生成18张数据库表,常用且核心的表有JBPM4_LOB 存储表,主要存储xml文件和png图片、JBPM4_TASK 任务表、JBPM4_EXECUTION 流程实例表、JBPM4_VARIABLE变量表。
图形化的灵活定制(主动说)
可以根据需求进行流程图的改变的,即定义的流程图是可以根据需要改变的,而不是死的。
可以进行图形化的监控(主动说)
输出图片
获取活动节点的坐标
进行叠加
判断节点:(主动说,也可以了解)
实现implements DecisionHandler接口并重写decide方法,
返回的字符串要和xml中配置的transition的name保持一致。
分支判定节点
JBPM有五大核心类:
ProcessEngine:主要获取各种的Service
RepositoryService:主要发布流程定义
ExecutionService:主要操作流程实例
TaskService:主要操作人工服务
HistoryService:主要操作历史服务。
核心方法:
读取jbpm定义的文件生成zip包存到lob表中:createDeployment()
获取流程定义列表:createProcessDefinitionQuery
根据定义的key或id来启动流程实例:startProcessInstanceByKey(id)
获取待办任务列表:findPersonalTasks(userName)
完成指定任务列表:completeTask(*.getActivityId())
获取历史任务列表:createHistoryTaskQuery()
获取流程实例的ID:task.getExecutionId()
(了解的表)
JBPM4_HIST_ACTINST流程活动(节点) 实例表
JBPM4_HIST_DETAIL流程历史详细表
JBPM4_HIST_PROCINST流程实例历史表
JBPM4_HIST_TASK流程任务实例历史表
JBPM4_HIST_VAR流程变量( 上下文) 历史表
JPBM业务场景
首先进行请假的流程定义,我们流程的定义是(员工提交请假单---》经理审批---》总监审批---》总经理审批---》结束),通过repositoryService将其发布部署到jbpm4_lob表中,
之后获取流程定义列表,选中请假的流程定义,员工开始进行请假单的填写,保存并通过executionService开启流程实例,然后用taskService获取经理的待办任务列表,选中待办任务,进行审批,通过调用taskService.completeTask()进入到总监审批环节,然后用总监进行登录,同样获取待办任务列表,然后调用taskService.completeTask()进入总经理审批环节,总经理审批之后,结束流程。在这个过程中我们还可以根据historyService查看当前登录人已办的任务列表。
Ant描述
Ant是apache旗下的对项目进行自动打包、编译、部署的构建工具,他主要具有 轻量级并且跨平台的特性,而且基于jvm,默认文件名为build.xml
Ant主要的标签:
Project根标签,target任务标签,property属性标签,自定义键/值 供多次使用,java执行编译后的java文件,javac编译java文件,war打成war包,其它标签:copy,delete,mkdir,move,echo等。
FreeMarker描述
FreeMarker是一个用Java语言编写的模板引擎,它是基于模板来生成文本输出的通用工具。Freemarker可以生成HTML, XML,JSP或Java等多种文本输出。
工作原理:定义模板文件,嵌入数据源,通过模板显示准备的数据
(数据 + 模板 = 输出)
我们在使用模板中发现freemarker具有许多优点,它彻底的分离表现层和业务逻辑,模板只负责数据在页面中的表现,不涉及任何的逻辑代码,所以使得开发过程中的人员分工更加明确,作为界面开发人员,只需专心创建HTML文件、图像以及Web页面的其他可视化方面,不用理会数据;而程序开发人员则专注于系统实现,负责为页面准备要显示的数据。
如果使用jsp来展示,开发阶段进行功能调适时,需要频繁的修改JSP,每次修改都要编译和转换,浪费了大量时间,FreeMarker模板技术不存在编译和转换的问题,在开发过程中,我们在不必在等待界面设计开发人员完成页面原型后再来开发程序。由此使用freemarker还可以大大提高开发效率。
webService描述
(主动说)
webservice是SOA(面向服务编程)的一种实现,主要是用来实现异构平台通信也就是不同平台不同项目之间的数据传输,从而避免了信息孤岛的问题,它之所以能够进行异构平台通信是因为它是完全基于xml的,所以说,webService是跨平台,跨语言,跨框架的,在java中通常有三种技术框架分别是xfire,cxf,axis2。
我们为了保证
webservice的安全性,采用了基于
WS-Security标准的安全验证(使用回调函数)。
(没必要主动说)
webservice的三要素分别是:
wsdl(webservice description language)用来描述发布的接口(服务)
soap(simple object access protocol)是xml和http的结合,是webservice数据通信的协议
uddi用来管理,查询webService的服务
(没必要主动说)
webservice的具体三种实现方式(框架)或者三种实现框架的区别
1. Axis2:可以用多种语言开发,是一个重量级框架,功能非常强大,但是它的性能比较低。
2. Xfire:它相比Axis2来说是一个轻量级框架,它的性能要比Axis2高。
3. cxf:是Xfire的升级版,就好比是,struts2是webwork的升级,然后cxf和spring集成起来非常方便,简易,性能方面也要比Xfire高。
【注】jdk6自带的webservice jws
(主动说)
业务场景
我在以前做项目的时候,其中遇到一个功能,需要进行两个项目之间的数据的传输,项目经理让我去完成这个任务,我根据以往的项目经验,想到两种解决方案,第一种就是开放另外一个项目的数据库的权限给我,然后我直接通过访问另外一个项目的数据库,来得到需要的信息,但后来我分析了下,觉的这种方式不安全,而且因为当时这个项目是另外一家公司负责在做,所以数据库里面的表结构,
以及以后牵涉
到的责任问题都很多,所以我就采用了第二种方案,即通过webservices的方式,进行异构系统之间数据信息的传递,webservices的具体实现,有xfire,cxf,axis2,我根据以往的项目经验,了解到cxf是xfire的升级版本,适用于java语言,xfire/cxf性能比axis2要高,并且和spring整合起来也比较方便,而axis2支持更多的语言,性能相对于cxf要低,通过上面分析,结合我们目前的两个项目都是基于java语言的,所以我采用cxf这种方式实现了两个项目之间数据的传递,我们为了保证webservice的安全性我们采用了基于WS-Security标准的安全验证(使用CXF回调函数)。
(没必要主动说)
webservice服务端配置流程
首先在web.xml中引入cxfServlet核心类,指定对以/cxf开头的url路径提供webservice服务,之后我们在要发布成webservice接口上添加@Webservice 注解,而且还要在实现类上添加同样的webservice注解并且要说明实现了哪个接口,之后在spring-webservice.xml中发布webservice服务,通过jaxws:endpoint这个标签,并且在标签配置implementor和address来表明实现服务的类,以及发布的地址,最后在浏览器中输入相关的webservice地址?wsdl来验证服务是否发布成功。
(没必要主动说)
webservice客户端的配置
首先通过wsdl2java根据发布的webservice服务端地址的wsdl生成客户端调用的中间桥梁java类,将生成的java类拷贝到客户端项目中,配置spring-client.xml文件,通过jaxws:client定义一个bean,并通过address属性指明要访问的webservice的服务地址,通过serviceClass指明充当中间桥梁的服务类,之后获取该bean,就可以通过它来访问发布的webservice接口中的方法。
oracle索引概述
索引呢是与表相关的一个可选结构,可以提高sql语句的检索效率,相当于我们的字典目录 ,可以快速进行定位 ,所以可以减少磁盘I/O, 但是因为索引在物理与逻辑上都是独立于表的数据 它会占用一定的物理空间(额外磁盘空间) 所以并不是索引越多越好,而我们应该根据业务需求去创建索引,而且进行增删改操作时 oracle又要自动维护索引 所以在一定程度上也降低了维护速度,而且我们在创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加,我们一般创建索引呢 是这样创建的 create index 索引名 on 表名(字段),索引又分为普通索引 唯一索引(unique) 单个索引 复合索引(又叫组合索引,在索引建立语句中同时可包含多个字段名),顺序索引,散列索引,位图索引。
oracle存储过程
存储过程就是封装一些sql的集合,也就是一条条的sql语句,过程的优点就是简化了sql命令加上它是预编译的,所以它的执行效率和性能较高,再者,如果不调用过程的话就要和数据库发生多次交互,调用过程只需传一个命令所有的那些执行逻辑都在数据库端执行,所以说它降低了网络的通信量,其次,存储过程大大提高了安全性,这就是优点
缺点呢,就是不同的数据库对过程支持的关键字支持的关键字都是不一样的,所以它的移植性是非常差的,再者,它的维护性难度也比较大,因为它没有专业的调试和维护工具,所以说它维护起来比较麻烦,这就是存储过程的基本概述.
Junit业务场景
在我们开发项目的时候为了提高代码的性能和保证逻辑正确性,在我们编写代码后往往都要进行单元测试,来验证代码,当时我们公司开发人员全部使用的main方法来进行验证,但是使用mian的最大缺点就是不能将多个类同时进行验证,验证的结果不直观,测试复杂(每个类都要写main方法,单个运行),一定程度上浪费时间,所有我和项目经理提议使用专业测试工具Junit来进行测试,因为Junit是一个Java语言的单元测试框架 ,测试简单,不仅可以提供工作效率和代码的质量,也提高团队的合作能力,我提议后我们进行了Junit的培训使用Junit4加注解的方式来测试。
Apache+Tomcat实现负载均衡及seesion复制
当我们tomcat访问量大,线程连接数不够时,我们考虑到了tomcat的负载均衡来分担过多的访问.性能方面负载均衡也能利用多台tomcat来增大内存量,
流程,准备工作apache,Jk_mod,tomcat,在apache的conf/httpd.conf文件中 使用include 标签引入我们自定义的一个mood_jl.conf,在modules中引入下载的k_mod-apache-X.X.XX.so文件,在其中引入我们的.so,及work.properties文件,及指定负载分配控制器controller,在work.properties文件中worker.list=controller,tomcat1,tomcat2指定service,worker.tomcat1.port Ajp端口号,type 是ajp,host为指定ip,lbfactor 指定分配权重值越大分担请求越多,worker.controller.type=lbworker.controller.balanced_workers=tomcat1,tomcat2 指定分担请求的tomcat Session的复制在tomcat中service.xml中Engine标签加入 jvmRoute 值为work,properties中指定的tomcat名称,然后打开<Cluster标签的注释,最后在应用中程序的web.xml文件中增加<distributable/>。
我们在做这个项目时,我们考虑到服务器性能的问题,我们最开始想到使用纵向扩展,来增加硬件的配置提高其性能,但这样做比较耗费资金,而且服务器内存空间也是有限的;所以后来就想到使用横向扩展来达到这一目的
当时我们的apache是通过jk借助于ajp协议与tomcat进行通信的,在我们不进行负载均衡之前,那所有的请求都由一台tomcat进行处理,这样会使我们的tomcat所承受的压力增大,而我们进行负载均衡之后,同样数量的请求经过apache和jk将其分发到多台tomcat进行处理,从而降低每台tomcat所承受的压力,而且当其中一台机器宕机时,其他机器还可以继续提供服务,保证服务不间断。
在这个过程中,我们遇到了session问题,然后我此昂到用session复制来解决这个问题;
在apache的配置文件中增加session粘带特性:
worker.lb.sticky_session=1
worker.lb.sticky_session_force=0
Tomcat的配置
修改server.xml文件:
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">增加jvmRoute=”tomcat2” *. jvmRoute赋的值为worker.properties中配置的相应的server名一致
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> 将此配置的注释去掉修改应用的web.xml文件在应用中的web.xml文件中增加。
如果这样做,当第一次访问的时候,会把所以数据全部缓存到第一台服务器上,通过web配置文件,会把第一台缓存的数据全部复制到第二胎服务器上,这样做就加大网路通信量,导致阻塞,所以我们就想到了可以通过memcached分布式缓存来存取session从而解决上述问题。
如果你依然觉得有些茫然,不如加入我的Java架构师之路:766529531 跟有多年Java开发经验的资深工程师聊一聊。也可获取免费的视频学习资料以及电子书学习资料喔!
Ant业务场景
Ant是基于java语言编写的,因此具有跨平台的特性,此外还具有简洁方便,灵活配置的特性,因此我就在XX项目中使用ant进行项目的编译,打包,部署操作。使用ant之后,如果我们在客户那里修改代码后,就可以直接使用ant进行编译,打包,部署,而不需要为了编译,打包,部署专门在客户那里安装eclipse.此外使用ant也可以直接和svn进行交互,下载源码的同时进行编译,打包,部署。
maven业务场景
前段时间在研究maven,知道maven是一个项目管理工具,其核心特点就是通过maven可以进行包的依赖管理,保证jar包版本的一致性,以及可以使多个项目共享jar包,从而能够在开发大型j2ee应用的时候,减小项目的大小,并且和ant比起来,maven根据“约定优于配置”的特性,可以对其项目的编译打包部署进行了更为抽象的封装,使得自己不需要像ant那样进行详细配置文件的编写,直接使用系统预定好的mvn clean,compile,test,package等命令进行项目的操作。于是我就在XX项目中采用了maven,为了保证团队中的成员能够节省下载jar包所需要的时间,于是我就采用nexus搭建了在局域网内的maven私服,然后通过配置settings.xml中建立mirror镜像,将所有下载jar包的请求都转发maven私服上,之后通过在pom.xml即(project object model)中配置项目所依赖的jar包,从而达到在构建项目的时候,先从本地仓库中查找,如果不存在从内部私服查找,如果不存在最后再从外网central服务器查找的机制,达到了节省下载带宽,提高开发效率,以及jar包重用的目的。
ant业务场景
ant是基于java语言编写的,因此具有跨平台的特性,此外还具有简洁方便,灵活配置的特性,因此我就在XX项目中使用ant进行项目的编译,打包,部署操作。使用ant之后,如果我们在客户那里修改代码后,就可以直接使用ant进行编译,打包,部署,而不需要为了编译,打包,部署专门在客户那里安装eclipse.此外使用ant也可以直接和svn进行交互,下载源码的同时进行编译,打包,部署。
maven的常用命令
mvn eclipse:clean eclipse:eclipse -Dwtpversion=2.0
mvn clean package
maven的生命周期是独立的,但是生命周期下的阶段是相互关联并且延续的。
maven的生命周期
clean(清理):clean;default(默认):compile,test,packageinstall;site(站点)
Servlet的概述:
Servlet是一个web容器,我们通常用的servlet是httpservlet,而httpservlet又是继承于genericservlet,而genericservlet又实现了servlet接口
servlet的生命周期是 :先进行实例化,然后是初始化,然后是提高服务,然后销毁,最后不可用,在这五个生命周期,其中,初始化是调用的init方法,这个方法只有一个,而提高服务的时候调用的是service方法,而我们具体在我们所写的这个方法中,因为我们继承了httpservlet,其实就是对应了doGet(),doPost(),这种方法,然后据我了解,servlet是单例的。非线程安全的,我们通常有一下几种方案来解决:
第一种,继承SingleThreadModel但是这样每次都会创建一个新的servlet实例,但这样消耗服务器的内存,降低了性能,并且这个接口现在已经过时了,不推荐使用。
第二种:我们尽量避免使用全局变量,就我个人而言,我比较喜欢使用这种方法。
第三种,我们可以通过使用ThreadLocal, 内部结构是一个Map结构,用当前线程作为key,他会创建多个副本。get,set方法
第四种,我们当然还可以来加锁,进行解决线程问题。
而且我还知道,向我们这种常用的MVC框架,struts1,spring这些MVC框架,都是基于servlet发展而来的,就比如struts1 的核心总控制器是ActionServlet,而springMVC的前端总控制器是dispatchServlet,在项目我们曾经用serlet来生成 图片验证码的,防止用户进行暴力破解
(别人问了,再回答)
servlet的配置文件 web.xml
<servlet>
<servlet-name>ImageCodeServlet</servlet-name>
<servlet-class>org.leopard.code.ImageCodeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ImageCodeServlet</servlet-name>
<url-pattern>/d</url-pattern>
</servlet-mapping>
描述:
我在web.xml中,我首先需要写一个servlet标签,servlet标签中有两个子标签,一个叫servlet-name,这个name可以随便起,但是要保证唯一性,除此之外,在这个servlet-name下有一个servlet-class,这个servlet-class对应的就是我后台提高服务的servlet,除此之外还有一个servlet-mapping,这个里边首先有一个servl-name。,这个servl-name首先要保证和上边的servlet-name保持一致,除此之外还有一个url-pattern,这是一个虚拟路径,是用来发送请求的url地址
bugfree的操作步骤
我们在使用bugfree的时候我们首先登陆的时候是以测试员的身份登陆的,也就是系统管理员用户;测试员在登陆后首先应该给要测试的项目的相关负责人,每人创建一个账号(也就是在登陆后的页面的后台管理中创建用户),用户都新建完成之后就新建组,把要测试的项目的用户添加到组中。最后就新建项目并且新建该项目的模块。新建完项目之后就是开始测试程序,在程序中遇到bug以后就把错误截图,在到bugfree中新建bug填写相关的信息和要指派的人(出错模块的负责人)和把刚才的错误截图作为附件一并传送过去。
开发人员每天早上上班的第一件事就是用自己的用户登录bugfree,然后输入查询条件看看前一天有没有指派给自己的bug需要解决的如果有就进行解决。
开发人员把对应的bug解决之后就去bugfree上把bug对应的状态改成已解决状态,然后进行保存提交,这样bug的状态就变成已解决状态。测试人员上线查看已解决状态的bug并再次进行测试,如果经过测试bug的问题已解决,就可以把bug关闭;如果经过测试,发现仍然存在bug,就把bug激活;这样等开发人员再次登录的时候就可以再次看到这个未解决的bug,再次进行解决,如此反复直到bug全部解决,因为bugfree对bug的修改都有保留,所有我们可以看到bug的一步步的完善,直到最后把bug关闭。
Bug的三种状态:未解决(Active)(测试人员)、已解决(Resolved)(开发人员)、关闭(Closed)(测试人员)
Axis2 的配置
axis2服务端配置流程
1.引入相关的jar包并且在web.xml中配置axis2的核心控制器 axisServlet
2.在web-inf下建立相关的三层文件夹结构:
services-->自定义文件夹名-->META-INF-->servies.xml
3.在servies.xml中配置service的name以及对应的springBeanName
4.在浏览器中输入webservice的服务端地址并加上?wsdl来进行测试,看是否发布成功
axis2客户端配置流程
1.通过wsdl2java根据webservice服务端的url生成客户端代码
2.将代码引入项目的文件夹中进行正常访问
二十六、spring定时器
每隔固定的时间执行
1.建立一个triggers触发器集合
2.建立SimpleTriggerBean并且指定每次间隔的时间以及执行的次数以及要执行的目标
3.通过 targetObject以及targetMethod找到要执行的具体类的具体方法,目标对象是一个普通的java类
每到指定的时间执行
1.建立一个triggers触发器集合.
2.建立CronTriggerBean指定cron表达式以及要执行的目标
3.通过 targetObject以及targetMethod找到要执行的具体类的具体方法,目标对象是一个普通的java类
Ext概述
据我了解Ext是一个用js编写RIA框架,它可以和各种后台语言结合使用。我在项目中用Ext来完成的模块大概情况是这个样子,首先我通过layout等于border的这种方式来进行布局,分为上下左右中,然后在左边用exttree来进行菜单的展示,之后在中间区域通过tabs来加入选项卡,而在选项卡中就是一个个的grid以及form,其中我在做grid的时候,首先通过store来存取后台返回的符合model格式数据集,store是通过proxy和后台的contoller进行交互,之后把store赋值给grid的store属性并且通过renderTO在指定的位置进行渲染展示。
Grid问题:
当时我在做grid的时候,发现数据没有展示出来,我通过f12进行跟踪,发现压根就没有发送请求,后来我分析了下,发现因为没有调用store的loadPage方法,所以导致了这个问题。除此之外在我们做项目的过程中,我手底下带的一个人同样在负责grid的时候,数据可以正常展示,但分页信息没有展示,通过跟踪他的代码发现是因为他没有把store属性赋值给分页工具条,所以才导致了这个问题。
tabs选项卡:
当我在做tab选项卡这一模块的时候,我首先在加载页面的时候用TabPanel创建了一个tab页面,让它展示在中间位置,然后点击左边Tree菜单调用add方法动态添加一个个的tab选项卡,但是做的过程中出现了相同的选项卡会重复添加的问题,我查了一些相关资料,最后通过tab的id或者一个唯一标识判断tab是否选中,如果选中则调用setActiveTab来激活该选项卡,让它选中,否则就添加一个tab。最后达到了tab不存在就添加,存在就选中的效果。
了解:
Ext4.0也支持前端的MVC开发模式:
为啥没采用mvc的开发模式?
我们当时因为时间方面的原因,项目经理就决定用普通的这种开发模式进行开发,并没有采用Ext4.0这种mvc模式的特性。但我认为他们的核心操作流程是一致的所以对我来说去学习和使用这种方式并没有什么难度。
lucene的概述
lucene是一个全文检索引擎,在进行模糊匹配的时候,他可以用来替代数据库中的like,从而在匹配准确性以及性能进行大幅度的提高。我在做XX项目的XX模块的时候,就是用lucene来进行全文检索用IK分词器来进行分词。从而实现了高亮显示关键词,分页,排序,多字段,多条件的高性能搜索。在从数据中取数据生成索引的时候,因为表中的数据量比较大,防止一次取出所导致内存溢出问题,我采用了分段批量提取的方式进行,除此之外我们对后续增加的数据根据优先级的不同采取不同的策略,对于那些需要及时显示的数据我们通过spring定时器在短时间内(30分钟)进行增量索引的生成,对于那些不需要及时展示的数据,我们通过spring定时器在每天晚上凌晨的时候进行索引的重新生成。
线程池作用
1.减少了创建和销毁线程的次数,每个线程都可以被重复利用,可执行多个任务。
2.可以根据系统的承受能力,调整线程池中线程的数目,防止因为消耗过多的内存,而导致服务器宕机(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后宕机)。通常我们使用的线程池是实现了ExecutorService的ThreadPoolExecutor。
jbpm是如何和spring进行整合
1.通过在spring-common.xml配置文件中配置springHelper,通过springHelper创建processEngine,再通过processEngine获取各种工作流的Service,如repositoryService,executionService,historyService,taskService
2.在src根目录下新建jbpm.cfg.xml文件
Tomcat优化
增大内存(堆,持久代)并开启server模式
我在做XXX项目时,用到了poi导入和导出数据,由于公司的业务比较繁多,数据量很大,测试时报内存溢出,经过我的分析再结合上网查阅资料,发现可能是tomcat内存不足,需要增大,修改配置文件后测试不再报错.
tomcat增大内存的方式通过修改tomcat配置文件
window下, 在bin/catalina.bat文件中最前面添加:
set JAVA_OPTS=-XX:PermSize=64M -XX:MaxPermSize=128m –Xms1024m -Xmx1024m
linux下,在catalina.sh最前面增加:
JAVA_OPTS="-XX:PermSize=64M -XX:MaxPermSize=128m –Xms1024m -Xmx1024m "
-client –service
当我们在cmd中运行-java时,黑窗口会出现-client -service这两参数.其作用是设置虚拟机运行模式;client模式启动比较快,但运行时性能和内存管理效率不如server模式,通常用于客户端应用程序。server模式启动比client慢,但可获得更高的运行性能。Windows默认为client,如果要使用server模式,就需要在启动虚拟机时加-server参数,以获得更高性能,对服务器端应用,推荐采用server模式,尤其是多个CPU的系统。在Linux,Solaris上,默认值为server模式.
JDK版本
影响虚拟机还有JDK的版本,JDK分为32位,64位两种版本,32位装在32位系统,64位系统可以装32位和64位JDK.64位JDK性能优于32位JDK.
测试的命令java -xmx数值m –version报错配置大小失败,反之成功
增加Tomcat最大连接数
使用场景
我在做完一个XXX项目后,测试时发现并发数量增加到一定程度就会很卡,于是我想到了是不是tomcat最大连接数设置有限制.果不其然,配置文件中最大值才500,于是我更改了最大连接数,根据业务我修改了连接数为2000,完美的解决了这个问题;
修改方法在conf/service.xml中默认值
<Connector port="8080" maxHttpHeaderSize="8192" maxThreads="1500"
minSpareThreads="30" maxSpareThreads="75" enableLookups="false"
redirectPort="8443" acceptCount="100" connectionTimeout="20000"
disableUploadTimeout="true" />,修改maxthreads的值即可
tomcat进行gzip压缩从而降低网络传输量
tomcat压缩设置tomcat压缩gzip启用
HTTP压缩可以大大提高浏览网站的速度,它的原理是,在客户端请求服务器对应资源后,从服务器端将资源文件压缩,再输出到客户端,由客户端的浏览器负责解压缩并浏览。相对于普通的浏览过程HTML ,CSS,Javascript , Text,它可以节省60%左右的流量。更为重要的是,它可以对动态生成的,包括CGI、PHP , JSP , ASP , Servlet,SHTML等输出的网页也能进行压缩,压缩效率也很高。
启用tomcat 的gzip压缩
要使用gzip压缩功能,你需要在Connector节点中加上如下属性
compression="on"打开压缩功能
compressionMinSize="50"启用压缩的输出内容大小,默认为2KB
noCompressionUserAgents="gozilla, traviata"对于以下的浏览器,不启用压缩
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" 哪些资源类型需要压缩
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" executor="tomcatThreadPool" URIEncoding="utf-8"
compression="on"
compressionMinSize="50" noCompressionUserAgents="gozilla, traviata"
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" />
如果你依然觉得有些茫然,不如加入我的Java架构师之路:766529531 跟有多年Java开发经验的资深工程师聊一聊。也可获取免费的视频学习资料以及电子书学习资料喔!
memcached的介绍
memcached是一个用C语言开发的分布式的缓存,内部基于类似hashMap的结构。它的优点是协议简单,内置内存存储,并且他的分布式算法是在客户端完成的,不需要服务器端进行通信,我们当时在做项目的时候因为考虑到项目的高可用性高扩展性,因此在服务器部署方面采用了apache+jk+tomcat这种负载均衡的方式,但是也带来了一个问题就是session共享的问题,虽然可以通过session复制来解决这个问题,但是在性能方面存在缺陷,所以最后我们采用了用memcached来存储session,这样既解决了session共享问题,也解决了session复制那种方式所产生的性能问题。
了解(不必主动说,但别人问的话一定要知道)
memcached是以KEY-VALUE的方式进行数据存储的,KEY的大小限制:Key(max)<=250个字符;
VALUE在存储时有限制:Value(max)<= 1M;
根据最近最少使用原则删除对象即LRU.
memcached默认过期时间:ExpiresTime(max)= 30(days)