Hibernate
1.Hibernate 的初始化.
读取Hibernate 的配置信息-〉创建Session Factory
1)创建Configeration类的实例。它的构造方法:将配置信息(Hibernate config.xml)读入到内存。 一个Configeration 实例代表Hibernate 所有Java类到Sql数据库映射的集合。
2)创建SessionFactory实例把Configeration 对象中的所有配置信息拷贝到SessionFactory的缓存中。 SessionFactory的实例代表一个数据库存储员源,创建后不再与Configeration 对象关联。 缓存(cache):指Java对象的属性(通常是一些集合类型的属性--占用内存空间。
SessionFactory的缓存中:Hibernate 配置信息。OR映射元数据。 缓存-大:重量级对象 小:轻量级对象
3)调用SessionFactory创建Session的方法
1】用户自行提供JDBC连接。
Connection con=dataSource.getConnection(); Session s=sessionFactory.openSession(con);
2】让SessionFactory提供连接
Session s=sessionFactory.openSession();
4)通过Session 接口提供的各种方法来操纵数据库访问。
Hibernate 的缓存体系
一级缓存:Session 有一个内置的缓存,其中存放了被当前工作单元加载的对象。
每个Session 都有自己独立的缓存,且只能被当前工作单元访问。
二级缓存: SessionFactory的外置的可插拔的缓存插件。其中的数据可被多个Session共享访问。SessionFactory的内置缓存:存放了映射元数据,预定义的Sql语句。
Hibernate 中Java对象的状态
1.临时状态 (transient)
特征:
1】不处于Session 缓存中 2】数据库中没有对象记录
Java如何进入临时状态
1】通过new语句刚创建一个对象时
2】当调用Session 的delete()方法,从Session 缓存中删除一个对象时。
2.持久化状态(persisted)
特征:
1】处于Session 缓存中 2】持久化对象数据库中设有对象记录
3】Session 在特定时刻会保持二者同步
Java如何进入持久化状态
1】Session 的save()把临时-》持久化状态
2】Session 的load(),get()方法返回的对象
3】Session 的find()返回的list集合中存放的对象
4】Session 的update(),saveOrupdate()使游离-》持久化
3.游离状态(detached)
特征:
1】不再位于Session 缓存中
2】游离对象由持久化状态转变而来,数据库中可能还有对应记录。
Java如何进入持久化状态-》游离状态
1】Session 的close()方法
2】Session 的evict()方法,从缓存中删除一个对象。提高性能。少用。
hibernate 的缓存Hibernate的缓存包括Session的缓存和SessionFactory的缓存,其中SessionFactory的缓存又可以分为两类:内置缓存和外置缓存。Session的缓存是内置的,不能被卸载,也被称为Hibernate的第一级缓存。SessionFactory的内置缓存和Session的缓存在实现方式上比较相似,前者是SessionFactory对象的一些集合属性包含的数据,后者是指Session的一些集合属性包含的数据。SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的拷贝,而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来,SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。SessionFactory的外置缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的拷贝,外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的第二级缓存。
缓存的范围决定了缓存的生命周期以及可以被谁访问。缓存的范围分为三类。
1 事务范围:缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当事务结束时,缓存也就结束生命周期。在此范围下,缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存,缓存内的数据通常采用相互关联的的对象形式。
2 进程范围:缓存被进程内的所有事务共享。这些事务有可能是并发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期,进程结束时,缓存也就结束了生命周期。进程范围的缓存可能会存放大量的数据,所以存放的介质可以是内存或硬盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据形式。松散的对象数据形式有点类似于对象的序列化数据,但是对象分解为松散的算法比对象序列化的算法要求更快。
3 集群范围:在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中的数据通常采用对象的松散数据形式。
如前所述,Hibernate提供了两级缓存,第一级是Session的缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。第一级缓存是必需的,不允许而且事实上也无法比卸除。在第一级缓存中,持久化类的每个实例都具有唯一的OID。
第二级缓存是一个可插拔的的缓存插件,它是由SessionFactory负责管理。由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此第二级缓存是进程范围或者集群范围的缓存。这个缓存中存放的对象的松散数据。第二级对象有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。缓存适配器用于把具体的缓存实现软件与Hibernate集成。第二级缓存是可选的,可以在每个类或每个集合的粒度上配置第二级缓存。
Hibernate的二级缓存策略的一般过程如下:
1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。
2) 把获得的所有数据对象根据ID放入到第二级缓存中。
3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。
4) 删除、更新、增加数据的时候,同时更新缓存。
Hibernate的二级缓存策略,是针对于ID查询的缓存策略,对于条件查询则毫无作用。为此,Hibernate提供了针对条件查询的Query缓存。
Hibernate的Query缓存策略的过程如下:
1) Hibernate首先根据这些信息组成一个Query Key,Query Key包括条件查询的请求一般信息:SQL, SQL需要的参数,记录范围(起始位置rowStart,最大记录个数maxRows),等。
2) Hibernate根据这个Query Key到Query缓存中查找对应的结果列表。如果存在,那么返回这个结果列表;如果不存在,查询数据库,获取结果列表,把整个结果列表根据Query Key放入到Query缓存中。
3) Query Key中的SQL涉及到一些表名,如果这些表的任何数据发生修改、删除、增加等操作,这些相关的Query Key都要从缓存中清空。
Spring
一、 IoC(Inversion of control): 控制反转
1、IoC:
概念:控制权由对象本身转向容器;由容器根据配置文件去创建实例并创建各个实例之间的
依赖关系 核心:bean工厂;在Spring中,bean工厂创建的各个实例称作bean
二、AOP(Aspect-Oriented Programming): 面向方面编程
1、 代理的两种方式:
静态代理: ? 针对每个具体类分别编写代理类; ? 针对一个接口编写一个代理类;
动态代理: 针对一个方面编写一个InvocationHandler,然后借用JDK反射包中的Proxy类为各种接口动态生成相应的代理类
2、 AOP的主要原理:动态代理
Spring工作原理
Spring 已经用过一段时间了,感觉Spring是个很不错的框架。内部最核心的就是IOC了,
动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的射
反射其实就是在运行时动态的去创建、调用对象,Spring就是在运行时,跟xml Spring的配置 文件来动态的创建对象,和调用对象里的方法的 。
Spring还有一个核心就是AOP这个就是面向切面编程,可以为某一类对象 进行监督和控制(也就是 在调用这类对象的具体方法的前后去调用你指定的 模块)从而达到对一个模块扩充的功能。这些都是通过 配置类达到的。
Spring目的:就是让对象与对象(模块与模块)之间的关系没有通过代码来关联,都是通过配置类说明 管理的(Spring根据这些配置 内部通过反射去动态的组装对象)
要记住:Spring是一个容器,凡是在容器里的对象才会有Spring所提供的这些服务和功能。 Spring里用的最经典的一个设计模式就是:模板方法模式。(这里我都不介绍了,是一个很常用的设计模式) Spring里的配置是很多的,很难都记住,但是Spring里的精华也无非就是以上的两点,把以上两点跟理解了 也就基本上掌握了Spring.
二、
Spring工作原理及使用理由 2009年06月27日 星期六 上午 11:50 10. spring工作机制及为什么要用?
1.springmvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作。
2.DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller.
3.DispatcherServlet请请求提交到目标Controller
4.Controller进行业务逻辑处理后,会返回一个ModelAndView
5.Dispathcher查询一个或多个ViewResolver视图解析器,找到ModelAndView对象指定的视图对象
6.视图对象负责渲染返回给客户端。
为什么用:
AOP 让开发人员可以创建非行为性的关注点,称为横切关注点,并将它们插入到应用程序代码中。使用 AOP后,公共服务(比如日志、持久性、事务等)就可以分解成方面并应用到域对象上,同时不会增加域对象的对象模型的复杂性。
IOC 允许创建一个可以构造对象的应用环境,然后向这些对象传递它们的协作对象。正如单词 倒置 所表明的,IOC 就像反过来的JNDI。没有使用一堆抽象工厂、服务定位器、单元素(singleton)和直接构造(straightconstruction),每一个对象都是用其协作对象构造的。因此是由容器管理协作对象(collaborator)。
Spring即使一个AOP框架,也是一IOC容器。 Spring 最好的地方是它有助于您替换对象。有了Spring,只要用JavaBean属性和配置文件加入依赖性(协作对象)。然后可以很容易地在需要时替换具有类似接口的协作对象。
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring模块构建在核心容器之上,核心容器定义了创建、配置和管理bean 的方式,如图 1 所示。
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
核心容器:核心容器提供 Spring框架的基本功能。核心容器的主要组件是BeanFactory,它是工厂模式的实现。BeanFactory使用控制反转(IOC)模式将应用程序的配置和依赖性规
Struts
一、
struts的工作原理可分为如下8步。
1.读取配置(初始化ModuleConfig对象)
Struts框架总控制器(ActionServlet)是一个Servlet,在web.xml中被配置成一个自动启动的Servlet。读取配置文件struts-config.xml的配置信息,为不同的Struts模块初始化相应的ModuleConfig对象。
2.用户请求
用户提交表单或调用URL向WEB应用程序服务器提交一个请求,请求的数据用HTTP协议上传给WEB服务器。
3.填充FormBean
(*.do请求)从ActionConfig中找出对应该请求的Action子类,如有对应的Action且这个Action又一个相应的ActionForm,ActionForm被实例化并用HTTP请求的数据填充其属性,并保存在ServletContext中,这样他们就可以被其它Action对象或JSP调用。如果没有对应的Action,控制器则直接转发给JSP或静态页面。
4.派发请求
控制器根据配置信息ActionConfig将请求派发到具体的Action,相应的FormBean一并传给这个Action的execute()方法。
5.处理业务
Action一般只包含一个execute方法,它负责执行相应的业务逻辑。执行完毕后返回一个ActionFoward对象,控制器通过该ActionFoward对象来进行转发工作。
6.返回响应
Action根据业务处理的不同结果返回一个响应对象给总控制器,该目标响应对相对应一个具体的JSP页面或另一个Action。
7.查找响应
总控制器根据业务功能Action返回的目标响应对象找到对应的资源对象,通常是一个具体的JSP页面。
8.响应用户
JSP将结果展现给用户。
二、
struts 简介 工作原理
Struts是一个基于Sun J2EE平台的MVC框架,主要是采用Servlet和JSP技术来实现的。由于Struts能充分满足应用开发的需求,简单易用,敏捷迅速,在过去的一年中颇受关注。Struts把Servlet、JSP、自定义标签和信息资源(message resources)整合到一个统一的框架中,开发人员利用其进行开发时不用再自己编码实现全套MVC模式,极大的节省了时间,所以说Struts是一个非常不错的应用框架。
2. Struts的工作原理
谈到Struts,我们就不得不提到MVC设计模式。MVC即Model-View-Controller的缩写,它是web应用当中的常用的设计模式。MVC 减弱了业务逻辑接口和数据接口之间的耦合,以及让视图层更富于变化。
Struts是MVC的一种实现,它很好的结合了Jsp,Java Servlet,Java Bean ,Taglib等技术。那么我们来看看Struts框架的工作原理:
控制:在Struts中,ActionServlet起着一个控制器(Controller)的作用。ActionServlet是一个通用的控制组件。这个控制组件提供了处理所有发送到Struts的HTTP请求的入口点。它截取和分发这些请求到相应的动作类(这些动作类都是Action类的子类)。另外控制组件也负责用相应的请求参数填充 Action Form(通常称之为FromBean),并传给动作类(通常称之为ActionBean)。动作类实现核心商业逻辑,它可以访问java bean 或调用EJB。所有这些控制逻辑利用Struts-config.xml文件来配置。
视图:主要是由Jsp来控制页面输出的。它接收到Action Form中的数据,利用html,taglib,bean,logic等显示数据。
模型:在Struts中,主要存在三种bean,分别是:Action,ActionForm,EJB或者Java Bean。ActionForm用来封装客户请求信息,Action取得ActionForm中的数据,再由EJB或者Java Bean进行处理。
3 Struts 优点与缺点
优点:1.利用Struts提供的taglib可以大大节约开发时间。2. 表现与逻辑分离。 3.维护扩展比较方便。 4 便于团队开发
缺点:大量的使用标签,对于初学者难度较大。
三、
Struts ActionServlet控制器对象
ActionServlet继承自javax.servlet.http.HttpServlet类,其在Struts framework中扮演的角色是中心控制器。它提供一个中心位置来处理全部的终端请求。控制器ActionServlet主要负责将HTTP的客户请求信息组装后,根据配置文件的指定描述,转发到适当的处理器。 按照Servelt的标准,所有得Servlet必须在web配置文件(web.xml)声明。同样,ActoinServlet必须在Web Application配置文件(web.xml)中描述,有关配置信息如下。
中心控制器为所有的表示层请求提供了一个集中的访问点。这个控制器提供的抽象概念减轻了开发者建立公共应用系统服务的困难,如管理视图、会话及表单数据。它也提供一个通用机制如错误及异常处理,导航,国际化,数据验证,数据转换等。
当用户向服务器端提交请求的时候,实际上信息是首先发送到控制器ActionServlet,一旦控制器获得了请求,其就会将请求信息传交给一些辅助类(help classes)处理。这些辅助类知道如何去处理与请求信息所对应的业务操作。在Struts中,这个辅助类就是org.apache.struts.action.Action。通常开发者需要自己继承Aciton类,从而实现自己的Action实例。
Struts Action Classes ActionServlet把全部提交的请求都被控制器委托到RequestProcessor对象。RequestProcessor使用struts-config.xml文件检查请求URI找到动作Action标示符。
一个Action 类的角色,就像客户请求动作和业务逻辑处理之间的一个适配器(Adaptor),其功能就是将请求与业务逻辑分开。这样的分离,使得客户请求和Action类之间可以有多个点对点的映射。而且Action类通常还提供了其它的辅助功能,比如:认证(authorization)、日志(logging)和数据验证(validation)。
Action最为常用的是execute()方法。(注意,以前的perform方法在struts1.1中已经不再支持),还有一个execute()方法,请参考apidoc,在此不在说明。
当Controller收到客户的请求的时候,在将请求转移到一个Action实例时,如果这个实例不存在,控制器会首先创建,然后会调用这个Action实例的execute()方法。Struts Framework为应用系统中的每一个Action类只创建一个实例。因为所有的用户都使用这一个实例,所以你必须确定你的Action 类运行在一个多线程的环境中。下图显示了一个execute()方法如何被访问
Struts Action Mapping
上面讲到了一个客户请求是如何被控制器转发和处理的,但是,控制器如何知道什么样的信息转发到什么样的Action类呢?这就需要一些与动作和请求信息相对应的映射配置说明。在struts 中,这些配置映射信息是存储在特定的XML文件(比如struts-config.xml)。
这些配置信息在系统启动的时候被读入内存,供struts framework在运行期间使用。在内存中,每一个<action>元素都与org.apache.struts.action.ActionMapping类的一个实例对应。下表就显示了一个登陆的配置映射。
上面的配置表示:当可以通过/logonAction.do(此处假设配置的控制器映射为*.do)提交请求信息的时候,控制器将信息委托com.test.LogonAction处理。调用LogonAction实例的execute()方法。同时将Mapping实例和所对应的LogonForm Bean信息传入。其中name=LogonForm,使用的form-bean元素所声明的ActionForm Bean。有关form-bean的申明如下显示。
使用ActionForward导航
元素<forward>则表示了当Action实例的execute()方法运行完毕或,控制器根据Mapping可将响应信息转到适当的地方。如上面现实,如果客户登陆成功,则调用welcome forward,将成功信息返回到/welcome.jsp页面。在你的execute()方法的结尾可以使用下面的实例代码而返回welcome forward。当然你的welcome forward必须在action元素属性中定义,正如上面所声明的那样
基于执行请求处理器的execute(…)方法的结果,当传递一个值匹配指定于<forward>元素中name属性的值的时候,下一个视图可以在execute(…)方法中被开发者用方便的方法org.apache.struts.action.ActionMapping.findForward(…)选择。ActionMapping.findForward(…)方法既从它的本地范围又从全局范围提供一个ActionForward对象,该对象返回至RequestProcessor以RequestDispatcher.forward(…)或response.sendRedirect(…)调用下一个视图。当<forward>元素有redirect=“false”属性或redirect属性不存在的时候,RequestDispatcher.forward(…)被执行;当redirect=“true”是,将调用sendRedirect(…)方法。下例举例说明了redirect属性的用法:
<forward name="success" path="/Catalog.jsp" redirect="true"/>
如果redirect=true, URL建立如/contextPath/path因为HttpServletResponse.sendRedirect(…)中解释URL采用”/”开头相对于servlet容器根目录。
如果redirect=false, URI建立如/path因为ServletContext.getRequestDisptacher(…)采用虚拟目录相关URL。
在此稍稍说一下有关global-forwards的概念。其在配置文件中描述了整个应用系统可以使用的ActionForward,而不是仅仅是一个特定的Action。
Struts ActionForm Bean捕获表单数据
在上面讲解ActionServlet,Action Classes和Action Mapping的时候,我们都提到了ActionForm Bean的概念。一个应用系统的消息转移(或者说状态转移)的非持久性数据存储,是由ActionForm Bean的负责保持的
ActionForm派生的对象用于保存请求对象的参数,因此它们和用户紧密联系。
一个ActionForm类被RequestProcessor建立。这是发生在已完成向前进到一个URL,该URL为映射到控制器servlet而不是JSP和相应的动作映射指定的表单属性的。在这个情况下,如果没有在指定的活动范围内找到,RequestProcessor将尝试寻找可能导致创建一个新ActionForm对象的表单bean。该ActionForm对象在指定的活动范围内被用<action>元素的name属性找到;
RequestProcessor将随后重新安排表单属性,用请求时参数填充表单,随即调用表单对象的validate(…)方法以履行服务器端用户输入验证。仅当ActionMapping对象中validate属性被设为true时,validate(…)方法被调用;这就是默认的行为。request.getParameterValues(parameterName)被用于得到一个String[]对象,它用来表单填充;验证的结果应该是一个ActionErrors对象,用org.apache.struts.taglib.html.ErrorsTag来显示验证错误给用户。ActionForm也可以被用于为当前用户保存即将被一个视图引用的中间模型状态。
当一个表单对象被RequestProcessor找到,它被传递到请求处理器的execute(…)方法。一个ActionForm对象也可以被请求处理器建立。表单对象建立目的是提供中间模型状态给使用请求范围JSP; 这将确保对象不会在有效性过期后仍然存在。默认的,所有的表单都被保存为会话范围。会话中表单对象脱离有效性的存在可能导致浪费内存,同样的,请求处理器 必须跟踪保存在会话中的表单对象的生命周期。一个好的捕获表单数据的实践是为横跨多用户交互的相关表单用一个单独的表单bean。表单bean也可以在反馈的时候用来储存能够被自定义标签改变的中间模型状态。在视图中标签用法避免结合Java代码,因此要成一个好的任务划分,web生产组主要处理标志,而应用开发组主要处理Java代码。标签因素退出访问中间模型状态的逻辑;当访问嵌套的对象或当通过聚集列举时这个逻辑可能很复杂。
注意:在struts1.1中,ActionForm的校验功能,逐渐被剥离出来(当然依然可以使用)。使用了validator framework对整个应用系统的表单数据验证进行统一管理。相信信息请参考:http://home.earthlink.net/~dwinterfeldt
在ActionForm的使用中,Struts提倡使用到值对象(Value Object)。这样将客户或开发人员,对数据状态与对象状态能够更加清晰的理解和使用。
对于每一个客户请求,Struts framework在处理ActionForm的时候,一般需要经历如下几个步骤:
(1)检查Action的映射,确定Action中已经配置了对ActionForm的映射
(2)根据name属性,查找form bean的配置信息
(3)检查Action的formbean的使用范围,确定在此范围下,是否已经有此form bean的实例
(4)假如当前范围下,已经存在了此form bean的实例,而是对当前请求来说,是同一种类型的话,那么就重用。
(5)否则,就重新构建一个form bean的实例
(6)form bean的reset()方法备调用
(7)调用对应的setter方法,对状态属性赋值
(8)如果validatede的属性北设置为true,那么就调用form bean的validate()方法。
(9)如果validate()方法没有返回任何错误,控制器将ActionForm作为参数,传给Action实例的execute()方法并执行。
注意:直接从ActionFrom类继承的reset()和validate()方法,并不能实现什么处理功能,所以有必要自己重新覆盖。
Struts的其他组件
Struts framework本身提供了很多可扩展的组件或sub framework,方便的开发人员在其构架上构建web层的应用系统。比如upload,collections ,logging等等。让我们来看看两个比较重要的组件:validationg framework和struts taglib。有关其他组件请参考Struts用户手册(http://jakarta.apache.org/struts/userGuide)。
Validation Framework for Struts
在struts1.1中,新增了validation framework。增加了对form数据提交的验证。将原本需要在ActionFrom Bean的validate()进行的验证通过配置文件的描述进行验证。
有关其详细信息,请参考http://home.earthlink.net/~dwinterfeldt 。个人建议对于小型应用系统可以采用这种配置方式,但是对于应用系统中有大量web层表单应用的系统,并且业务需求变动比较大的,使用validation framework 可能会加重开发难度、系统维护难度。可以借鉴validation framework的Javascript Validator Tag。
Struts TagLib
struts提供了一组可扩展的自定义标签库(TagLib),可以简化创建用户界面的过程。目前包括:Bean Tags,HTML Tags,Logic Tags,Nested Tags,Template Tags 这几个Taglib。有关Struts Taglib的结构和使用,可以参考前面有关Cutomer Tag Lib的介绍,有关起详细资料,请参考
MVC
MVC模式 MVC模式是"Model-View-Controller"的缩写,中文翻译为"模式-视图-控制器"。MVC应用程序总是由这三个部分组成。Event(事件)导致Controller改变Model或View,或者同时改变两者。只要Controller改变了Models的数据或者属性,所有依赖的View都会自动更新。类似的,只要Controller改变了View,View会从潜在的Model中获取数据来刷新自己。MVC模式最早是smalltalk语言研究团提出的,应用于用户交互应用程序中。smalltalk语言和java语言有很多相似性,都是面向对象语言,很自然的SUN在petstore(宠物店)事例应用程序中就推荐MVC模式作为开发Web应用的架构模式。MVC模式是一种架构模式,其实需要其他模式协作完成。在J2EE模式目录中,通常采用service to worker模式实现,而service to worker模式可由集中控制器模式,派遣器模式和Page Helper模式组成。而Struts只实现了MVC的View和Controller两个部分,Model部分需要开发者自己来实现,Struts提供了抽象类Action使开发者能将Model应用于Struts框架中。
MVC模式是一个复杂的架构模式,其实现也显得非常复杂。但是,我们已经总结出了很多可靠的设计模式,多种设计模式结合在一起,使MVC模式的实现变得相对简单易行。Views可以看作一棵树,显然可以用Composite Pattern来实现。Views和Models之间的关系可以用Observer Pattern体现。Controller控制Views的显示,可以用Strategy Pattern实现。Model通常是一个调停者,可采用Mediator Pattern来实现。
现在让我们来了解一下MVC三个部分在J2EE架构中处于什么位置,这样有助于我们理解MVC模式的实现。MVC与J2EE架构的对应关系是:View处于Web Tier或者说是Client Tier,通常是JSP/Servlet,即页面显示部分。Controller也处于Web Tier,通常用Servlet来实现,即页面显示的逻辑部分实现。Model处于Middle Tier,通常用服务端的javaBean或者EJB实现,即业务逻辑部分的实现。
一、MVC设计思想
MVC英文即Model-View-Controller,即把一个应用的输入、处理、输出流程按照Model、View、Controller的方式进行分离,这样一个应用被分成三个层——模型层、视图层、控制层。
视图(View)代表用户交互界面,对于Web应用来说,可以概括为HTML界面,但有可能为XHTML、XML和Applet。随着应用的复杂性和规模性,界面的处理也变得具有挑战性。一个应用可能有很多不同的视图,MVC设计模式对于视图的处理仅限于视图上数据的采集和处理,以及用户的请求,而不包括在视图上的业务流程的处理。业务流程的处理交予模型(Model)处理。比如一个订单的视图只接受来自模型的数据并显示给用户,以及将用户界面的输入数据和请求传递给控制和模型。
模型(Model):就是业务流程/状态的处理以及业务规则的制定。业务流程的处理过程对其它层来说是黑箱操作,模型接受视图请求的数据,并返回最终的处理结果。业务模型的设计可以说是MVC最主要的核心。目前流行的EJB模型就是一个典型的应用例子,它从应用技术实现的角度对模型做了进一步的划分,以便充分利用现有的组件,但它不能作为应用设计模型的框架。它仅仅告诉你按这种模型设计就可以利用某些技术组件,从而减少了技术上的困难。对一个开发者来说,就可以专注于业务模型的设计。MVC设计模式告诉我们,把应用的模型按一定的规则抽取出来,抽取的层次很重要,这也是判断开发人员是否优秀的设计依据。抽象与具体不能隔得太远,也不能太近。MVC并没有提供模型的设计方法,而只告诉你应该组织管理这些模型,以便于模型的重构和提高重用性。我们可以用对象编程来做比喻,MVC定义了一个顶级类,告诉它的子类你只能做这些,但没法限制你能做这些。这点对编程的开发人员非常重要。
业务模型还有一个很重要的模型那就是数据模型。数据模型主要指实体对象的数据 保存(持续化)。比如将一张订单保存到数据库,从数据库获取订单。我们可以将这个模型单独列出,所有有关数据库的操作只限制在该模型中。
控制(Controller)可以理解为从用户接收请求, 将模型与视图匹配在一起,共同完成用户的请求。划分控制层的作用也很明显,它清楚地告诉你,它就是一个分发器,选择什么样的模型,选择什么样的视图,可以完成什么样的用户请求。控制层并不做任何的数据处理。例如,用户点击一个连接,控制层接受请求后, 并不处理业务信息,它只把用户的信息传递给模型,告诉模型做什么,选择符合要求的视图返回给用户。因此,一个模型可能对应多个视图,一个视图可能对应多个模型。
模型、视图与控制器的分离,使得一个模型可以具有多个显示视图。如果用户通过某个视图的控制器改变了模型的数据,所有其它依赖于这些数据的视图都应反映到这些变化。因此,无论何时发生了何种数据变化,控制器都会将变化通知所有的视图,导致显示的更新。这实际上是一种模型的变化-传播机制。模型、视图、控制器三者之间的关系和各自的主要功能,如图1所示。
二、MVC设计模式的实现
ASP.NET提供了一个很好的实现这种经典设计模式的类似环境。开发者通过在ASPX页面中开发用户接口来实现视图;控制器的功能在逻辑功能代码(.cs)中实现;模型通常对应应用系统的业务部分。在ASP.NET中实现这种设计而提供的一个多层系统,较经典的ASP结构实现的系统来说有明显的优点。将用户显示(视图)从动作(控制器)中分离出来,提高了代码的重用性。将数据(模型)从对其操作的动作(控制器)分离出来可以让你设计一个与后台存储数据无关的系统。就MVC结构的本质而言,它是一种解决耦合系统问题的方法。
MFC
微软所推出的MFC Document/View架构是早期对于MVC实现,MFC将程序分成CView以及CDocument两大类,其中的Document对应MVC中的 Model,View相当于MVC中的View+Controller,再加上CWinApp类,合成三大项。但是基本上MFC是一个失败的MVC作品。
由于MFC之下的Document/View定义过于模糊,未将Controller(MessageMap)部份取出,因此Controller可以置入View或Document,但不管置入哪一方面,都会与View或Document绑死,没有弹性。
Java
Java 平台企业版 (J2EE)和其他的各种框架不一样,J2EE为模型对象(Model Objects)定义了一个规范。
视图(View)
在J2EE应用程序中,视图(View)可能由Java Server Page(JSP)承担。生成视图的代码则可能是一个servlet的一部分,特别是在客户端服务端交互的时候。
控制器(Controller)
J2EE应用中,控制器可能是一个servlet,现在一般用Struts实现。
模型(Model)
模型则是由一个实体Bean来实现。
2.1 视图
视图是模型的表示,它提供用户交互界面。使用多个包含单显示页面的用户部件,复杂的Web页面可以展示来自多个数据源的内容,并且网页人员,美工能独自参与这些Web页面的开发和维护。
在ASP.NET下,视图的实现很简单。可以像开发WINDOWS界面一样直接在集成开发环境下通过拖动控件来完成页面开发本。本文中介绍每一个页面都采用复合视图的形式即:一个页面由多个子视图(用户部件)组成;子视图可以是最简单HTML 控件、服务器控件或多个控件嵌套构而成的Web自定义控件。页面都由模板定义,模板定义了页面的布局,用户部件的标签和数目,用户指定一个模板,平台根据这些信息自动创建页面。针对静态的模板内容,如页面上的站点导航,菜单,友好链接,这些使用缺省的模板内容配置;针对动态的模板内容(主要是业务内容),由于用户的请求不同,只能使用后期绑定,并且针对用户的不同,用户部件的显示内容进行过滤。使用由用户部件根据模板配置组成的组合页面,它增强了可重用性,并原型化了站点的布局。
视图部分大致处理流程如下:首先,页面模板定义了页面的布局;页面配置文件定义视图标签的具体内容(用户部件);然后,由页面布局策略类初始化并加载页面;每个用户部件根据它自己的配置进行初始化,加载校验器并设置参数,以及事件的委托等;用户提交后,通过了表示层的校验,用户部件把数据自动提交给业务实体即模型。
这一部分主要定义了WEB页面基类PageBase;页面布局策略类PageLayout,完成页面布局,用于加载用户部件到页面;用户部件基类UserControlBase即用户部件框架,用于动态加载检验部件,以及实现用户部件的个性化。为了实现WEB应用的灵活性,视图部分也用到了许多配置文件例如:置文件有模板配置、页面配置、路径配置、验证配置等。
2.2 控制器
为了能够控制和协调每个用户跨越多个请求的处理,控制机制应该以集中的方式进行管理。因此,为了达到集中管理的目的引入了控制器。应用程序的控制器集中从客户端接收请求(典型情况下是一个运行浏览器的用户),决定执行什么商业逻辑功能,然后将产生下一步用户界面的责任委派给一个适当的视图组件。
用控制器提供一个控制和处理请求的集中入口点,它负责接收、截取并处理用户请求;并将请求委托给分发者类,根据当前状态和业务操作的结果决定向客户呈现的视图。在这一部分主要定义了HttpReqDispatcher(分发者类)、HttpCapture(请求捕获者类)、Controller(控制器类)等,它们相互配合来完成控制器的功能。请求捕获者类捕获HTTP请求并转发给控制器类。控制器类是系统中处理所有请求的最初入口点。控制器完成一些必要的处理后把请求委托给分发者类;分发者类分发者负责视图的管理和导航,它管理将选择哪个视图提供给用户,并提供给分发资源控制。在这一部分分别采用了分发者、策略、工厂方法、适配器等设计模式。
为了使请求捕获者类自动捕获用户请求并进行处理,ASP.NET 提供低级别的请求/响应 API,使开发人员能够使用 .NET 框架类为传入的 HTTP 请求提供服务。为此,必须创作支持 System.Web.IHTTPHandler 接口和实现 ProcessRequest() 方法的类即:请求捕获者类,并在web.config 的 <httphandlers> 节中添加类。ASP.NET 收到的每个传入 HTTP 请求最终由实现 IHTTPHandler 的类的特定实例来处理。IHttpHandlerFactory 提供了处理 IHttpHandler 实例 URL 请求的实际解析的结构。HTTP 处理程序和工厂在 ASP.NET 配置中声明为 web.config 文件的一部分。ASP.NET 定义了一个 <httphandlers> 配置节,在其中可以添加和移除处理程序和工厂。子目录继承 HttpHandlerFactory 和 HttpHandler 的设置。 HTTP 处理程序和工厂是 ASP.NET 页框架的主体。工厂将每个请求分配给一个处理程序,后者处理该请求。 例如,在全局 machine.config 文件中,ASP.NET 将所有对 ASPx 文件的请求映射到 HttpCapture类:
<httphandlers>
...
...
</httphandlers>
2.3 模型
MVC系统中的模型从概念上可以分为两类――系统的内部状态和改变系统状态的动作。模型是你所有的商业逻辑代码片段所在。本文为模型提供了业务实体对象和业务处理对象:所有的业务处理对象都是从ProcessBase类派生的子类。业务处理对象封装了具体的处理逻辑,调用业务逻辑模型,并且把响应提交到合适的视图组件以产生响应。业务实体对象可以通过定义属性描述客户端表单数据。所有业务实体对象都EntityBase派生子类对象,业务处理对象可以直接对它进行读写,而不再需要和request、response对象进行数据交互。通过业务实体对象实现了对视图和模型之间交互的支持。实现时把"做什么"(业务处理)和"如何做"(业务实体)分离。这样可以实现业务逻辑的重用。由于各个应用的具体业务是不同的,这里不再列举其具体代码实例。
三、MVC设计模式的扩展
通过在ASP.NET中的MVC模式编写的,具有极其良好的可扩展性。它可以轻松实现以下功能:
①实现一个模型的多个视图;
②采用多个控制器;
③当模型改变时,所有视图将自动刷新;
④所有的控制器将相互独立工作。
这就是MVC模式的好处,只需在以前的程序上稍作修改或增加新的类,即可轻松增加许多程序功能。以前开发的许多类可以重用,而程序结构根本不再需要改变,各类之间相互独立,便于团体开发,提高开发效率。下面讨论如何实现一个模型、两个视图和一个控制器的程序。其中模型类及视图类根本不需要改变,与前面的完全一样,这就是面向对象编程的好处。对于控制器中的类,只需要增加另一个视图,并与模型发生关联即可。该模式下视图、控制器、模型三者之间的示意图如图2所示。
同样也可以实现其它形式的MVC例如:一个模型、两个视图和两个控制器。从上面可以看出,通过MVC模式实现的应用程序具有极其良好的可扩展性,是ASP.NET面向对象编程的未来方向。
四、MVC的优点
大部分用过程语言比如ASP、PHP开发出来的Web应用,初始的开发模板就是混合层的数据编程。例如,直接向数据库发送请求并用HTML显示,开发速度往往比较快,但由于数据页面的分离不是很直接,因而很难体现出业务模型的样子或者模型的重用性。产品设计弹性力度很小,很难满足用户的变化性需求。MVC要求对应用分层,虽然要花费额外的工作,但产品的结构清晰,产品的应用通过模型可以得到更好地体现。
首先,最重要的是应该有多个视图对应一个模型的能力。在目前用户需求的快速变化下,可能有多种方式访问应用的要求。例如,订单模型可能有本系统的订单,也有网上订单,或者其他系统的订单,但对于订单的处理都是一样,也就是说订单的处理是一致的。按MVC设计模式,一个订单模型以及多个视图即可解决问题。这样减少了代码的复制,即减少了代码的维护量,一旦模型发生改变,也易于维护。 其次,由于模型返回的数据不带任何显示格式,因而这些模型也可直接应用于接口的使用。
再次,由于一个应用被分离为三层,因此有时改变其中的一层就能满足应用的改变。一个应用的业务流程或者业务规则的改变只需改动MVC的模型层。
控制层的概念也很有效,由于它把不同的模型和不同的视图组合在一起完成不同的请求,因此,控制层可以说是包含了用户请求权限的概念。
最后,它还有利于软件工程化管理。由于不同的层各司其职,每一层不同的应用具有某些相同的特征,有利于通过工程化、工具化产生管理程序代码。
五、MVC的不足
MVC的不足体现在以下几个方面:
(1)增加了系统结构和实现的复杂性。对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。
(2)视图与控制器间的过于紧密的连接。视图与控制器是相互分离,但确实联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。
(3)视图对模型数据的低效率访问。依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。
(4) 目前,一般高级的界面工具或构造器不支持MVC模式。改造这些工具以适应MVC需要和建立分离的部件的代价是很高的,从而造成使用MVC的困难。
Servlet
Servlet容器工作原理
现在,我们从 servlet容器的角度来看看 servlet 编程。一个功能健全的 servlet容器对于每个 servlet 的 HTTP请求会完成以下事情:
1、当 servlet 第一次被调用的时候,加载了 servlet类并调用它的init方法(仅调用一次)
2、响应每次请求的时候 ,构建一个javax.servlet.ServletRequest 和 javax.servlet.ServletResponse实例。
3 、激活 servlet 的 service 方法,传递 ServletRequest 和 ServletResponse 对象。
4、当servlet 类关闭的时候,调用 servlet 的destroy 方法,并卸载 servlet 类。
发生在 servlet 容器内部的事就复杂多了。只是这个简单的 servlet 容器的功能不很健全,所以,这它只能运行非常简单的servelt ,并不能调用 servlet 的 init 和destroy 方法。然而,它也执行了以下动作:
1、等待 HTTP 请求。
2、构建 ServletRequest 和 ServletResponse 对象
3、如果请求的是一个staticResource,就会激活StaticResourceProcessor实例的 process方法,传递ServletRequest 和 ServletResponse 对象。
4、如果请求的是一个servlet ,载入该类,并激活它的service 方法,传递ServletRequest 和ServletResponse 对象。注意:在这个servlet 容器,每当 servlet被请求的时候该类就被载入。
在第一个应用程序中,servlet容器由六个类组成 。
HttpServer1 Request Response StaticResourceProcessor ServletProcessor1 Constants
这个程序的进入口(静态 main 方法)是HttpServer 类。这个方法创建了HttpServer实例,并调用它的await方法等待 HTTP 请示,然后创建一个 request 对象和 response对象,根据请求是否是staticResource还是 servlet 来分派它们到 StaticResourceProcessor实例或ServletProcessor实例。 Constants 类包含 static find WEB_ROOT,它是从其他类引用的。 WEB_ROOT 指明 PrimitiveServlet 位置 和容器服务的staticResource。
HttpServer1 实例等待 HTTP 请求,直到它收到一个 shutdown 命令。发布 shutdown命令和前文是一样的。
J2ee
J2EE是一套全然不同于传统应用开发的技术架构,包含许多组件,主要可简化且规范应用系统的开发与部署,进而提高可移植性、安全与再用价值。
J2EE核心是一组技术规范与指南,其中所包含的各类组件、服务架构及技术层次,均有共通的标准及规格,让各种依循J2EE架构的不同平台之间,存在良好的兼容性,解决过去企业后端使用的信息产品彼此之间无法兼容,导致企业内部或外部难以互通的窘境。
在J2EE架构下,开发人员可依循规范基础,进而开发企业级应用;而不同J2EE供货商,同会支持不同J2EE版本内所拟定的标准,以确保不同J2EE平台与产品之间的兼容性。换言之,植基J2EE架构的应用系统,基本上可部署在不同的应用服务器之上,无需或者只须要进行少量的代码修改,即能大幅提高应用系统的可移植性(Portability)。
J2EE主由升阳(SUN)与IBM等厂商协同业界共同拟定而成的技术规范,以企业与企业之间的运算为导向的JAVA开发环境。J2EE架构定义各类不同组件,如Web Component、EJB Component…等,而各类组件可以再用(reuse),让已开发完成的组件,或者是经由市面采购而得的组件,均能进一步组装成不同的系统。
对于开发人员而言,只需要专注于各种应用系统的商业逻辑与架构设计,至于底层繁琐的程序撰写工作,可搭配不同的开发平台,以让应用系统的开发与部署效率大幅提升。
J2EE的核心规范是 Enterprise Java Beans(EJBs)。EJB依照特性的不同,目前共分为三种,分别是Session Bean、Entity Bean,以及 Message Driven Bean 。其中 Session Bean 与Entity Bean 算是EJB的始祖,这两种EJB规格在EJB 1.x版本推出时就已经存在,而Message Driven Bean则是出现在EJB 2.0的规格之中。
目前业界许多程序设计师,或者是网页设计人员,多利用JSP/Servlet的便利性,进而在J2EE服务器之上开发相关的应用,或是整合公司内部的各种资源。
Java 2平台依照应用领域的不同,共分为三大版本,分别是J2EE、标准版本J2SE(Java 2 Platform, Standard Edition)、微型版本J2ME(Java 2 Platform, Micro Edition),以及Java Card等。 从整体上讲,J2EE是使用Java技术开发企业级应用的一种事实上的工业标准(Sun公司出于其自身利益的考虑,至今没有将Java及其相关技术纳入标准化组织的体系),它是Java技术不断适应和促进企业级应用过程中的产物。Sun推出J2EE的目的是为了克服传统Client/Server模式的弊病,迎合Browser/Server架构的潮流,为应用Java技术开发服务器端应用提供一个平台独立的、可移植的、多用户的、安全的和基于标准的企业级平台,从而简化企业应用的开发、管理和部署。J2EE是一个标准,而不是一个现成的产品。各个平台开发商按照J2EE规范分别开发了不同的J2EE应用服务器,J2EE应用服务器是J2EE企业级应用的部署平台。由于它们都遵循了J2EE规范,因此,使用J2EE技术开发的企业级应用可以部署在各种J2EE应用服务器上。
J2EE组成了一个完整企业级应用的不同部分纳入不同的容器(Container),每个容器中都包含若干组件(这些组件是需要部署在相应容器中的),同时各种组件都能使用各种J2EE Service/API。J2EE容器包括:
◆ Web容器 服务器端容器,包括两种组件JSP和Servlet,JSP和Servlet都是Web服务器的功能扩展,接受Web请求,返回动态的Web页面。Web容器中的组件可使用EJB容器中的组件完成复杂的商务逻辑。
◆ EJB容器 服务器端容器,包含的组件为EJB(Enterprise JavaBeans),它是J2EE的核心之一,主要用于服务器端的商业逻辑的实现。EJB规范定义了一个开发和部署分布式商业逻辑的框架,以简化企业级应用的开发,使其较容易地具备可伸缩性、可移植性、分布式事务处理、多用户和安全性等。
◆ Applet容器 客户端容器,包含的组件为Applet。Applet是嵌在浏览器中的一种轻量级客户端,一般而言,仅当使用Web页面无法充分地表现数据或应用界面的时候,才使用它。Applet是一种替代Web页面的手段,我们仅能够使用J2SE开发Applet,Applet无法使用J2EE的各种Service和API,这是为了安全性的考虑。
◆ Application Client容器 客户端容器,包含的组件为Application Client。Application Client相对Applet而言是一种较重量级的客户端,它能够使用J2EE的大多数Service和API。
通过这四个容器,J2EE能够灵活地实现前面描述的企业级应用的架构。
在View部分,J2EE提供了三种手段:Web容器中的JSP(或Servlet)、Applet和Application Client,分别能够实现面向浏览器的数据表现和面向桌面应用的数据表现。Web容器中的Servlet是实现Controller部分业务流程控制的主要手段;而EJB则主要针对Model部分的业务逻辑实现。至于与各种企业资源和企业级应用相连接,则是依靠J2EE的各种服务和API。
在J2EE的各种服务和API中,JDBC和JCA用于企业资源(各种企业信息系统和数据库等)的连接,JAX-RPC、JAXR和SAAJ则是实现Web Services和Web Services连接的基本支持。
J2EE的各种组件
J2EE 的结构
这种基于组件,具有平台无关性的J2EE 结构使得J2EE 程序的编写十分简单,因为业务逻辑被封装成可复用的组件,并且J2EE 服务器以容器的形式为所有的组件类型提供后台服务. 因为你不用自己开发这种服务, 所以你可以集中精力解决手头的业务问题.
容器和服务
容器设置定制了J2EE服务器所提供得内在支持,包括安全,事务管理,JNDI(Java Naming and Directory Interface)寻址,远程连接等服务,以下列出最重要的几种服务:
? J2EE安全(Security)模型可以让你配置 web 组件或enterprise bean ,这样只有被授权的用户才能访问系统资源. 每一客户属于一个特别的角色,而每个角色只允许激活特定的方法。你应在enterprise bean的布置描述中声明角色和可被激活的方法。由于这种声明性的方法,你不必编写加强安全性的规则。
? J2EE 事务管理(Transaction Management)模型让你指定组成一个事务中所有方法间的关系,这样一个事务中的所有方法被当成一个单一的单元. 当客户端激活一个enterprise bean中的方法,容器介入一管理事务。因有容器管理事务,在enterprise bean中不必对事务的边界进行编码。要求控制分布式事务的代码会非常复杂。你只需在布置描述文件中声明enterprise bean的事务属性,而不用编写并调试复杂的代码。容器将读此文件并为你处理此enterprise bean的事务。
? JNDI 寻址(JNDI Lookup)服务向企业内的多重名字和目录服务提供了一个统一的接口,这样应用程序组件可以访问名字和目录服务.
? J2EE远程连接(Remote Client Connectivity)模型管理客户端和enterprise bean间的低层交互. 当一个enterprise bean创建后, 一个客户端可以调用它的方法就象它和客户端位于同一虚拟机上一样.
? 生存周期管理(Life Cycle Management)模型管理enterprise bean的创建和移除,一个enterprise bean在其生存周期中将会历经几种状态。容器创建enterprise bean,并在可用实例池与活动状态中移动他,而最终将其从容器中移除。即使可以调用enterprise bean的create及remove方法,容器也将会在后台执行这些任务。
? 数据库连接池(Database Connection Pooling)模型是一个有价值的资源。获取数据库连接是一项耗时的工作,而且连接数非常有限。容器通过管理连接池来缓和这些问题。enterprise bean可从池中迅速获取连接。在bean释放连接之可为其他bean使用。
反射
反射机制:所谓的反射机制就是java语言在运行时拥有一项自观的能力。通过这种能力可以彻底的了解自身的情况为下一步的动作做准备。下面具体介绍一下java的反射机制。这里你将颠覆原来对java的理解。
Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method;其中class代表的时类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。通过这四个对象我们可以粗略的看到一个类的各个组 成部分。
Class:程序运行时,java运行时系统会对所有的对象进行运行时类型的处理。这项信息记录了每个对象所属的类,虚拟机通常使用运行时类型信息选择正 确的方法来执行(摘自:白皮书)。但是这些信息我们怎么得到啊,就要借助于class类对象了啊。在Object类中定义了getClass()方法。我 们可以通过这个方法获得指定对象的类对象。然后我们通过分析这个对象就可以得到我们要的信息了。
比如:ArrayList arrayList;
Class clazz = arrayList.getClass();
然后我来处理这个对象clazz。
当然了Class类具有很多的方法,这里重点将和Constructor,Field,Method类有关系的方法。
Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。Java 的这一能力在实际应用中也许用得不是很多,但是个人认为要想对java有个更加深入的了解还是应该掌握的。
1. 检测类:
2. 2、 在类中寻找指定的方法,同时获取该方法的参数列表,例外和返回值
3. 3、 获取类的构造函数信息,基本上与获取方法的方式相同
4. 4、 获取类中的各个数据成员对象,包括名称。类型和访问修饰符号
5. 5、 通过使用方法的名字调用方法
6. 6、 创建新的对象
7. 7、 变更类实例中的数据的值
类加载
要深入了解ClassLoader,首先就要知道ClassLoader是用来干什么的,顾名思义,它就是用来加载Class文件到JVM,以供程序使用的。我们知道,java程序可以动态加载类定义,而这个动态加载的机制就是通过ClassLoader来实现的,所以可想而知ClassLoader的重要性如何。 看到这里,可能有的朋友会想到一个问题,那就是既然ClassLoader是用来加载类到JVM中的,那么ClassLoader又是如何被加载呢?难道它不是java的类? 没有错,在这里确实有一个ClassLoader不是用java语言所编写的,而是JVM实现的一部分,这个ClassLoader就是bootstrap classloader(启动类加载器),这个ClassLoader在JVM运行的时候加载java核心的API以满足java程序最基本的需求,其中就包括用户定义的ClassLoader,这里所谓的用户定义是指通过java程序实现的ClassLoader,一个是ExtClassLoader,这个ClassLoader是用来加载java的扩展API的,也就是/lib/ext中的类,一个是AppClassLoader,这个ClassLoader是用来加载用户机器上CLASSPATH设置目录中的Class的,通常在没有指定ClassLoader的情况下,程序员自定义的类就由该ClassLoader进行加载。
当运行一个程序的时候,JVM启动,运行bootstrap classloader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的加载流程。 上面大概讲解了一下ClassLoader的作用以及一个最基本的加载流程,接下来将讲解一下ClassLoader加载的方式,这里就不得不讲一下ClassLoader在这里使用了双亲委托模式进行类加载。每一个自定义ClassLoader都必须继承ClassLoader这个抽象类,而每个ClassLoader都会有一个parent ClassLoader,我们可以看一下ClassLoader这个抽象类中有一个getParent()方法,这个方法用来返回当前ClassLoader的parent,注意,这个parent不是指的被继承的类,而是在实例化该ClassLoader时指定的一个ClassLoader,如果这个parent为null,那么就默认该ClassLoader的parent是bootstrap classloader,这个parent有什么用呢?我们可以考虑这样一种情况,假设我们自定义了一个ClientDefClassLoader,我们使用这个自定义的ClassLoader加载java.lang.String,那么这里String是否会被这个ClassLoader加载呢?事实上java.lang.String这个类并不是被这个ClientDefClassLoader加载,而是由bootstrap classloader进行加载,为什么会这样?实际上这就是双亲委托模式的原因,因为在任何一个自定义ClassLoader加载一个类之前,它都会先委托它的父亲ClassLoader进行加载,只有当父亲ClassLoader无法加载成功后,才会由自己加载,在上面这个例子里,因为java.lang.String是属于java核心API的一个类,所以当使用ClientDefClassLoader加载它的时候,该ClassLoader会先委托它的父亲ClassLoader进行加载,上面讲过,当ClassLoader的parent为null时,ClassLoader的parent就是bootstrap classloader,所以在ClassLoader的最顶层就是bootstrap classloader,因此最终委托到bootstrap classloader的时候,bootstrap classloader就会返回String的Class。
三大框架
1.读取并解析配置文件
2.读取并解析映射信息,创建SessionFactory
3.打开Sesssion
4.创建事务Transation
5.持久化操作
6.提交事务
7.关闭Session
8.关闭SesstionFactory
为什么要用:
1. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
2. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作
3. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
4. hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。
2. Hibernate是如何延迟加载?
1. Hibernate2延迟加载实现:a)实体对象 b)集合(Collection)
2. Hibernate3 提供了属性的延迟加载功能
当Hibernate在查询数据的时候,数据并没有存在与内存中,当程序真正对数据的操作时,对象才存在与内存中,就实现了延迟加载,他节省了服务器的内存开销,从而提高了服务器的性能。
3.Hibernate中怎样实现类之间的关系?(如:一对多、多对多的关系)
类与类之间的关系主要体现在表与表之间的关系进行操作,它们都市对对象进行操作,我们程序中把所有的表与类都映射在一起,它们通过配置文件中的many-to-one、one-to-many、many-to-many、
4. 说下Hibernate的缓存机制
1. 内部缓存存在Hibernate中又叫一级缓存,属于应用事物级缓存
2. 二级缓存:
a) 应用及缓存
b) 分布式缓存
条件:数据不会被第三方修改、数据大小在可接受范围、数据更新频率低、同一数据被系统频繁使用、非 关键数据
c) 第三方缓存的实现
5. Hibernate的查询方式
Sql、Criteria,object comptosition
Hql:
1、 属性查询
2、 参数查询、命名参数查询
3、 关联查询
4、 分页查询
5、 统计函数
6. 如何优化Hibernate?
1.使用双向一对多关联,不使用单向一对多
2.灵活使用单向一对多关联
3.不用一对一,用多对一取代
4.配置对象缓存,不使用集合缓存
5.一对多集合使用Bag,多对多集合使用Set
6. 继承类使用显式多态
7. 表字段要少,表关联不要怕多,有二级缓存撑腰
7. Struts工作机制?为什么要使用Struts?
工作机制:
Struts的工作流程:
在web应用启动时就会加载初始化ActionServlet,ActionServlet从
struts-config.xml文件中读取配置信息,把它们存放到各种配置对象
当ActionServlet接收到一个客户请求时,将执行如下流程.
-(1)检索和用户请求匹配的ActionMapping实例,如果不存在,就返回请求路径无效信息;
-(2)如果ActionForm实例不存在,就创建一个ActionForm对象,把客户提交的表单数据保存到ActionForm对象中;
-(3)根据配置信息决定是否需要表单验证.如果需要验证,就调用ActionForm的validate()方法;
-(4)如果ActionForm的validate()方法返回null或返回一个不包含ActionMessage的ActuibErrors对象, 就表示表单验证成功;
-(5)ActionServlet根据ActionMapping所包含的映射信息决定将请求转发给哪个Action,如果相应的 Action实例不存在,就先创建这个实例,然后调用Action的execute()方法;
-(6)Action的execute()方法返回一个ActionForward对象,ActionServlet在把客户请求转发给 ActionForward对象指向的JSP组件;
-(7)ActionForward对象指向JSP组件生成动态网页,返回给客户;
为什么要用:
JSP、Servlet、JavaBean技术的出现给我们构建强大的企业应用系统提供了可能。但用这些技术构建的系统非常的繁乱,所以在此之上,我们需要一个规则、一个把这些技术组织起来的规则,这就是框架,Struts便应运而生。
基于Struts开发的应用由3类组件构成:控制器组件、模型组件、视图组件
8. Struts的validate框架是如何验证的?
在struts配置文件中配置具体的错误提示,再在FormBean中的validate()方法具体调用。
9. 说下Struts的设计模式
MVC模式: web应用程序启动时就会加载并初始化ActionServler。用户提交表单时,一个配置好的ActionForm对象被创建,并被填入表单相应的数据,ActionServler根据Struts-config.xml文件配置好的设置决定是否需要表单验证,如果需要就调用ActionForm的 Validate()验证后选择将请求发送到哪个Action,如果Action不存在,ActionServlet会先创建这个对象,然后调用 Action的execute()方法。Execute()从ActionForm对象中获取数据,完成业务逻辑,返回一个ActionForward对象,ActionServlet再把客户请求转发给ActionForward对象指定的jsp组件,ActionForward对象指定的jsp生成动态的网页,返回给客户。
10. spring工作机制及为什么要用?
1.spring mvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作。
2.DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller.
3.DispatcherServlet请请求提交到目标Controller
4.Controller进行业务逻辑处理后,会返回一个ModelAndView
5.Dispathcher查询一个或多个ViewResolver视图解析器,找到ModelAndView对象指定的视图对象
6.视图对象负责渲染返回给客户端。
为什么用:
{AOP 让开发人员可以创建非行为性的关注点,称为横切关注点,并将它们插入到应用程序代码中。使用 AOP 后,公共服务 (比如日志、持久性、事务等)就可以分解成方面并应用到域对象上,同时不会增加域对象的对象模型的复杂性。
IOC 允许创建一个可以构造对象的应用环境,然后向这些对象传递它们的协作对象。正如单词 倒置 所表明的,IOC 就像反 过来的 JNDI。没有使用一堆抽象工厂、服务定位器、单元素(singleton)和直接构造(straight construction),每一个对象都是用其协作对象构造的。因此是由容器管理协作对象(collaborator)。
Spring即使一个AOP框架,也是一IOC容器。 Spring 最好的地方是它有助于您替换对象。有了 Spring,只要用 JavaBean 属性和配置文件加入依赖性(协作对象)。然后可以很容易地在需要时替换具有类似接口的协作对象。
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式,如图 1 所示。
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC)模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
Spring 框架的功能可以用在任何 J2EE 服务器中,大多数功能也适用于不受管理的环境。Spring 的核心要点是:支持不绑定到特定 J2EE 服务的可重用业务和数据访问对象
1.插入排序(直接插入排序、折半插入排序、希尔排序);
* 2.交换排序(冒泡泡排序、快速排序); 3.选择排序(直接选择排序、堆排序);
for (int i = 1; i < data.length; i++) {for (int j = 0; j < data.length - i; j++) {
if (data[j] > data[j + 1]) {
选择排序
int index; for (int i = 1; i < data.length; i++) {index = 0;for (int j = 1; j <= data.length - i; j++) {if (data[j] > data[index]) {index = j;
插入排序for (int i = 1; i < data.length; i++) {//保证前i+1个数排好序for (int j = 0; j < i; j++) {if (data[j] > data[i]) {//交换在位置j和i两个数
反转int length = data.length;int temp = 0;//临时变量
for (int i = 0; i < length / 2; i++) {temp = data[i];data[i] = data[length - 1 - i];data[length - 1 - i] = temp;
二分查找int midIndex = (beginIndex + endIndex) >>> 1; //相当于mid = (low + high) / 2,但是效率会高些if (data < dataset[beginIndex] || data > dataset[endIndex]|| beginIndex > endIndex)return -1;if (data < dataset[midIndex]) {return binarySearch(dataset, data, beginIndex, midIndex - 1);} else if (data > dataset[midIndex]) {return binarySearch(dataset, data, midIndex + 1, endIndex);} else {return midIndex;}
快速int i, j, x;
if (low < high) { //这个条件用来结束递归
i = low;j = high;
x = data[i];while (i < j) {while (i < j && data[j] > x) {j--; //从右向左找第一个小于x的数}if (i < j) {
data[i] = data[j];i++;}while (i < j && data[i] < x) {i++; //从左向右找第一个大于x的数}if (i < j) {data[j] = data[i];j--;}}data[i] = x;qsort_asc(data, low, i - 1);qsort_asc(data, i + 1, high);