美文网首页
J2EE入门指南(转)

J2EE入门指南(转)

作者: 古剑诛仙 | 来源:发表于2019-07-05 16:03 被阅读0次

    (一)前言

    这是写给零基础小白的一系列文章。
    为啥叫生存指南呢, 因为Java发展了20年, 现在已经不仅仅是一个单纯的语言了, 而是一套完整的生态系统, 其中的术语像 HTML, XML, CSS, Javascript , AJAX, JQuery,Prototype, HTTP, Tomcat, JBoss, Nginx , Memecached , Redis, MVC ,Servlet, JSP, Struts, Hibernate, myBatis , Spring, JFinal, MySql, JDBC, EJB, JMS, Swing , AWT, Reflection, OSGi... 铺面而来, 搞的你头晕脑胀, 无所适从,很容易就Lost了。
    所以写这个文章的目的就是帮助小白能在Java 的汪洋大海里生存, 时不时的能冒出水面喘口气, 看看空中的生存指南, 把握自己的方向继续向前。


    先回答一个问题? 为什么要学习Java ?
    我想原因无非有这么几点

    1. 我周围的人都在学, 所以我也学
    2. Java 好找工作啊, 确实是,在中国,软件行业还处于模仿、学习美国鬼子的阶段, 做系统级编程的不是没有, 像BAT就会用到。 不过绝大部分公司还都是搞应用级程序的开发, 所以Java, 尤其是Java EE 工作机会是非常多的。
    3. Java 看起来挺简单的。

    Java 语言本身看起来确实挺简单的, 不像C语言, 一个指针就把你搞迷糊了;
    也不像C++, 语法复杂而诡异, new 了一个对象以后还得记住 释放内存,确实是挺悲催的;
    Java 即使加上了面向对象(封装,继承,多态), 也是简单的令人发指, 不用上大学,高中生,甚至初中生都能看明白。
    可是你会发现学了基本的Java 以后, 除了能写个水仙花数, 九九乘法表,还是啥也干不了,更别说月薪过万了。
    人家公司至少要求精通SSH,AJAX,JQuery ,CSS,mysql , 这条路走起来就不那么容易了。

    再看第二个问题: Java 到底能干什么?
    一句话, Java 最擅长的就是Web 应用开发(通俗的讲就是网站开发),不善长桌面应用开发。
    你想想你开发一个Java 桌面应用, 还得让用户下载一个Java 虚拟机, 甚至要设置环境变量, 一般人是搞不定的。 此外Java 内置的Swing ,AWT确实不怎么样, 开发出来的界面距离操作系统原生界面差了很远, 所以除了特殊情况, 奉劝那些还在孜孜不倦的研究Java 界面编程(Swing, AWT)的同学还是不要浪费精力了, 不要硬逼着Java干他不擅长也不不愿意做的事情。

    所以咱们就聊聊Java Web 开发中用到的那些技术和术语。
    先来说说HTML, 咱们想象一个场景, 互联网还没有出现, 你是个球迷+程序员, 电脑里有很多的记录足球的文件例如 足球.txt, 巴塞罗那.txt , 曼联.txt .....
    其中足球.txt 中有一个词"巴萨罗那" , 为了方便, 你想点这4个字就打开另外一个文件“巴赛罗那.txt” 立刻就能看看球队的介绍 ,这该怎么办?
    你冥思苦想,终于顿悟了, 可以这么干: 定义一个协议 <a href ="巴塞罗那.txt">巴塞罗那 </a>  , 然后开发一个软件, 把所有的文本都管理起来, 遇到像<a href ...>这样的东西, 软件就认为这是一个链接, 点击后就打开另外一个文件 !
    这的确是个好主意,其实在1989年, 万维网的发明人蒂姆·伯纳斯·李也是这么干的, 你看你要是早出生20年,估计也是WWW的发明人了。
    加了链接以后, 文本就不是不同的文本了, 而升级为超文本 (Hypertext)了 !

    但是如果你的“足球.txt”还有“广州恒大”几个字, 但是广州恒大的介绍是在你哥们的电脑上, 而他也想把他的文本能链接到你的电脑文件上,这怎么办?
    一个单机运行的软件就不行的, 必须得有网络 , 有网络还不够,你得解决通信的问题。
    你就想:既然上面的文本是超文本,并且需要把你好哥们的文本传输到你的电脑上才能看, 那通信方法就叫做超文本传输协议吧 HyperText Transfer Protocol , 简称Http。

    于是你又扩展上一个程序, 不但把你的文本文件都管理起来,还允许通过网络访问, 别人要想通过网络看你的文件, 得发个这样的命令给你的软件:
    http://192.168.0.10/football/巴萨罗那.txt 。 你的程序就会找到football 目录下的 巴萨罗那.txt , 读出内容, 发给对方, 并且给他说: 200 成功
    如果找不到, 软件就告诉他: 404 对不起,找不到 。
    如果你的软件在处理过程中出了错 , 软件就说: 500  唉, 服务器出错了。
    这个软件功能强大,专门在网络上别人服务,就叫网络服务器吧,可以起个名字叫Apache 。

    可是只看文字太不爽了, 你还想看表格,列表,图片,甚至视频。 干脆自己定义一个描述界面的语言吧, 像这样:
    <table> ---表示表格
    <li> --- 表示列表
    <image> -- 表示图片。
    这些都称为标记(markup) , 所以现在你的超文本就更加丰富了, 这个语言就叫做 Hyper Text Markup Language , 简称为 HTML。

    原来的软件只能显示文本和处理链接, 现在还需要能处理这些标签, 遇到不同的标签, 就显示相应的内容 。
    现在你把你的文本全部用html改写了一遍, 放到了Apache 服务器中, 你的哥们也把他的html放到了他的Apache服务器上, 当然你们的html之间还保持着链接 。 然后你们就可以用新的软件对这些html进行浏览了, 对了,可以把这个软件称为浏览器。

    由于方便,快捷,能发布图文并茂的信息, 更关键的是可以把散布在全世界各个角落中的计算机连接在一起, HTML , HTTP, 网络服务器,浏览器 迅速普及, 人们上网在也不用使用那些难用的telnet , ftp 了。 网络就变成了这样:


    image.png

    下面的文字来源于百度百科:
    因为在互联网技术上的杰出贡献,伯纳斯·李被业界公认为“互联网之父”。他的发明改变了全球信息化的传统模式,带来了一个信息交流的全新时代。然而比他的发明更伟大的是,伯纳斯·李并没有像其他人那样为“WWW”申请专利或限制它的使用,而是无偿的向全世界开放。伯纳斯·李本来可以在金钱上与盖茨一比高低,但他的这一举措却为互联网的全球化普及翻开了里程碑式的篇章,让所有人都有机会接触到互联网,也圆了那些。com公司创建者们的富翁梦。即便如此,伯纳斯·李仍然十分谦虚,总是以一种平静的口气回应:“我想,我没有发明互联网,我只是找到了一种更好的方法。”

    (二)web技术

    上次说到你发明了html , http, 浏览器, web服务器, 这下子把整个世界的信息都链接成了一个了一个大网: world wide web
    可是你注意到一个问题没有, 这些html都是静态的 , 也就是说你除了浏览你的网站和别人的网站之外,什么都做不成。 用你发明的HTTP术语来讲, 就是现在的互联网, 只支持 “GET”
    比如说, 你看了哥们的网站,知道广州恒大夺得了2015亚冠冠军, 想给他留个言表示一下兴奋之情,这就做不到了。
    这是不能令你满意的, 对互联网做扩展吧
    先扩展HTML ,加上一堆新标签 像<form>了, <input>了 什么type=text, radio, textarea,checkbox 。。。 这样你就可以在html中支持输入各式各样的信息了。
    你还得扩展HTTP协议, 引入一个“POST”这样可以把数据发到Web服务器。
    Web 服务器当然也得扩展, 接收到POST过来的留言数据以后, 肯定得想办法处理啊 ,怎么处理? 
    无非就是新生成一个html , 除了把原有的数据保留以外,还要把新的留言相关的数据“动态”的加上去, 这就是所谓的动态页面。
    必须得有程序来办这件事情, 你马上就面临两个问题:
    (1) 用什么语言来写, 毕竟有那么多语言像C, Perl , Python, 甚至Java 都在虎视眈眈呢
    (2) 这个程序怎么和 Web 服务器交互

    解决方法也很简单, 你弄了了一个叫做 Common Gateway Interface (简称CGI) 的东西, 定义了标准的输入(STDIN)和输出(STDOUT), 所有的程序都可以从STDIN 读入数据,处理后形成html, 然后向STDOUT 输出 。
    这下子任何语言都可以写cgi程序了, 网页也变成了“可交互式”的, 整个互联网又向前推进了一大步, 各种各样的商业网站如雨后春笋一般发展起来。

    ( ps : 现在CGI 技术已经过时了, ASP, JSP, PHP等技术是主流。
    在Java的世界里, 把Apache ,Ngnix 这样的服务器称为静态内容服务器, 主要处理像图片/文件件这样不变的,只读的静态资源,性能非常好; 把Tomcat, JBoss ,Websphere, Weblogic等称为动态内容服务器, 主要产生动态内容。
    一般的设计会把Apache/Ngnix 放的前边,接收所有的Http 请求,如果是静态资源,就直接处理掉, 如果是动态资源,就转发到Tomcat/Jboss 去处理。 )

    等等,还有个小问题, 我的留言我能看到, 别人的留言我也想看到改怎么办? 很明显, 每个人通过浏览器提交的留言都需要保存起来, 在生成页面的时候动态的读取他们,形成html 。

    可以把所有的用户留言都存放到一个文件当中,读取文件形成html没有任何压力, 但是你要非常小心处理同步的问题:你提交留言的时候,别人也在提交, 可不能相互覆盖啊 !
    这也是为什么Web程序都有一个数据库的原因, 数据库帮我们解决了这些乱七八糟的同步问题, 我们只需要向数据库发出 Select, Insert, Upate ,Delete 就好了。数据库的历史要比WWW久远的多, 早在大机时代就出现了, 现在已经发展的非常成熟 , 直接拿过来用就可以了。

    解决了用户留言的问题, 你接下来要写一个网上售票的应用, 让大家在网上买球票, 买票的时候需要一个购物车, 大家可以把票暂时放到购物车里。
    开发购物车的时候发现了你设计的HTTP一个非常严重的缺陷 : 没有状态 , 因为用户往购物车里加了一个球票, 一刷新页面购物车就空了,里边的所有东西都丢失了。
    假设用户A在操作, 用户B也在操作, 你的Apache服务器实际上根本区分不出来谁是用户A, 谁是用户B, 只是看到了一个个毫无关联的GET和POST 。 根本记录不下来同一个用户在过去一段时间内做了什么事情。
    你想改一下HTTP协议, 可是悲催的是数以亿计的网站已经在用了, 你想改都改不了了。
    于是你想了个办法, HTTP 协议不是有个header吗, 在里边做做手脚 :
    浏览器A第一次给服务器发送请求时, 服务器通过header告诉它一个编号number_a,浏览器A需要记住这个编号, 然后下次请求的时候(以及后续所有请求的时候)也通过header 把number_a 发给服务器。 这样服务器一看, 奥,原来你是浏览器A 啊, 就可以把浏览器A相关的购物车数据从内存中取出来, 形成html 发回浏览器A了。
    浏览器A和服务器的这个通过这个编号来交互, 这个过程就称为 : session
    用了这一个小伎俩, 这样服务器就把各个浏览器(各个用户)给区分开了。

    到目前为止,构建一个Web系统最基础的工作可以说已经完成了, 我想起来高中时物理老师说的一句话: 牛顿三定律出来以后 ,经典物理学的大厦已经建立起来了, 后人的工作无非是刷刷墙, 装饰装饰而已。
    对于互联网也是: HTTP + HTML + Web服务器 + 数据库 就是WWW的基石, 后续的工作都是为了提高生产率做的包装和装饰。

    最后简单做一个总结: 其实发明创造并没有那么难, 马云说过, 哪里有抱怨,哪里就有机会, 所以找一找现在你感觉最不爽的地方, 也许能发明下一代互联网呢。

    (三)XML

    前两篇文章 基本上把Web编程所依赖的基础技术(HTTP,HTML, WEB服务器,浏览器)的来龙去脉介绍完了, 从这篇开始 ,正式开始进入应用程序的开发领域。

    其实Web应用程序开发也有个极为常见的技术: XML . 很多小白在问,为什么有XML, 要XML干嘛?不是有HTML了吗 ? 晕倒
    对一项技术我的风格是喜欢刨根问底, 不但要知道how, 还要知道why , 了解了一个技术的成因, 才能真正掌握。

    假设你用Java 写了一个很棒的Web应用, 这个程序可以在线购书, 在互联网刚起步的时代这个应用火的一塌糊涂 , 后来有个出版社看到了机遇, 就想和你搞合作: 我这儿也有个Web应用,可以给你提供很多书籍的资源, 你能不能开发个程序把这些书的信息读出来,放到你的网站上?

    这没啥难的, 首先得定义一下你的应用和出版社的应用中间怎么进行数据交换, 你要定义一个格式,像这样:
    [isbn|书名|作者|简介|价格]
    例如: [978-7-229-03093-3|三体|刘慈欣|中国最牛的科幻书|38.00]

    数据虽然紧凑, 但是每个字段是什么含义,不好理解, 你想起了HTML的标签好像不错,不如学习HTML改进一下:
    <book>
    <isbn>978-7-229-03093-3</isbn>
    <name>三体</name>
    <author>作者</author>
    <introduction>中国最牛的科幻书</introduction>
    <price>38.00</price>
    </book>
    由于HTML的标签<head>,<title>,<tr><td>...... 是有限的,而你的标签确实可以随意扩展的,想写什么写什么 所以你就把它称为 Extensible Markup Language, 简称XML
    现在每个字段的含义很明确, 人读起来也很爽了, 但是毕竟是程序在处理出版社发过来的数据, 万一他们的数据里少了一些重要字段该怎么办, 能不能自动的检测出来?

    所以你需要设计一套校验规则, 能让程序自动校验一段xml 文本是不是你期望的, 这个规则可以像这样:
    <!ELEMENT book (isbn, name, author, introduction, price)>
    <!ELEMENT price (#PCDATA)>
    <!ELEMENT name (#PCDATA)>
    <!ELEMENT isbn (#PCDATA)>
    <!ELEMENT introduction (#PCDATA)>
    <!ELEMENT author (#PCDATA)>

    其中第一行的意思是 xml 需要有个 book 标签(元素), 它包含了几个子标签 , 并且这几个标签必须都得有,并且按次序出现。
    其他行表示每个标签都是文本就可以了。
    你把这个东西起名为文档类型定义 Document Type Definition, 简称DTD 。
    这样就不怕出版社使坏了, 对他们发过来的数据, 在真正的处理之前, 你写了个程序, 调用用DTD一验证就知道是不是合法的, 少了个字段什么的一下子就能查出来,巨爽。
    后来又有人发明了DTD的改进版XML Schema ,那就是后话了。

    慢慢的你就发现,XML极为灵活,描述一个东西非常方便, 除了应用之间交互数据之外,用来描述你的系统的配置信息也大有用武之地。
    原来你为了让代码有可移植性(说白了就是在别人的机器上安装时不用费那么大劲),把数据库的ip , 用户名, 密码 都写在了一个文本文件中, 这样就可以只改配置而不用改动代码了
    ip=192.168.0.1
    name=test
    user=liuxin
    password=liuxin

    但是碰到复杂的,尤其是层次化的配置用文本文件就捉襟见肘了,例如:
    form1.name=login
    form1.class=com.test.login
    form1.property1.name=ok
    form1.property1.type=java.lang.String
    form1.property2.name=failure
    form1.property2.type=java.lang.String

    form2.name=logout
    form2.class=com.test.logout
    form2.property1.name=ok
    form2.property1.type=java.lang.String
    form2.property2.name=failure
    form2.property2.type=java.lang.String
    是不是看的头大?
    改成xml 描述看看, 是不是就容易理解多了:
    <form name="login" class="com.test.login">
    <property name="ok" type="java.lang.String" />
    <property name="failure" type="java.lang.String" />
    </form>
    <form name="logout" class="com.test.logout">
    <property name="ok" type="java.lang.String" />
    <property name="failure" type="java.lang.String" />
    </form>

    其实不光是你, 现在绝大多数Java 应用程序的配置文件都是xml , 已经成为事实的标准了。
    总结:XML主要用于程序之间的数据交换, 以及描述程序的配置信息。

    历史知识:
    早在1969年,IBM公司就开发了一种文档描述语言GML用来解决不同系统中文档格式不同的问题,这个语言在1986年演变成一个国际标准(ISO8879),并被称为SGML,SGML是很多大型组织,比如飞机、汽车公司和军队的文档标准,它是语言无关的、结构化的、可扩展的语言,这些特点使它在很多公司受到欢迎,被用来创建、处理和发布大量的文本信息。
    在1989年,在CERN欧洲粒子物理研究中心的研究人员开发了基于SGML的超文本版本,被称为HTML。HTML继承了SGML的许多重要的特点,比如结构化、实现独立和可描述性,但是同时它也存在很多缺陷:比如它只能使用固定的有限的标记,而且它只侧重于对内容的显示。
    同时随着Web上数据的增多,这些HTML存在的缺点就变的不可被忽略。W3C提供了HTML的几个扩展用来解决这些问题,最后,它决定开发一个新的SGML的子集,称为XML。

    (四)Tomcat

    下面讲一下几乎100%Java 开发人员都要用的 Tomcat。
    为什么有Tomcat ? 其实需要从Servlet 说起。
    记得(2)提到的动态网页吗? 常见的实现动态网页的技术就是CGI。
    但是作为Java 的发明人, Sun肯定要搞一个超越CGI的技术出来, 之前Sun 通过Applet出了一个超级大风头, 让整个世界一下子认识了Java , 不过很快发现悲催的Applet其实用途不大, 眼看着互联网开始起势, 一定要搭上千载难逢的快车啊。

    于是Servlet 就应运而生了, Servlet 其实就是Sun为了让Java 能实现动态的可交互的网页, 从而进入Web编程的领域而定义的一套标准。

    这套标准说了:
    你想用Java 开发动态网页,可以定义一个自己的"Servlet"(名字很怪,不知道怎么翻译) , 但一定要是实现我的HttpServlet接口, 然后重载doGet(), doPost()等方法。
    用户从浏览器GET的时候, 调用doGet()方法, 从浏览器向服务器发送表单数据的时候, 调用doPost()方法。

    如果你想访问用户从浏览器传递过来的参数, 没问题, 用HttpServletRequest 对象就好了, 里边有getParameter() ,getQueryString()方法。
    如果你处理完了, 想向浏览器返回数据, 用HttpServletResponse 调用getPrintWriter() 就可以输出数据了。
    如果你想实现一个购物车, 需要session, 很简单, 从HttpServletRequest 调用getSession() 就好了。

    你写了一个"Servlet",接下来要运行, 你就发现没法通过java 直接运行了, 你需要一个能够运行Servlet的容器 , 这个容器Sun 最早实现了一个,叫Java Web Server, 1999年捐给了Apache Software foundation , 就改名叫Tomcat 。

    所以Tomcat 就是一个Servlet容器, 能接收用户从浏览器发来的请求, 然后转发给Servlet处理, 把处理完的响应数据发回浏览器。
    但是Servlet 输出html ,还是采用了老的CGI 方式,是一句一句输出,所以,编写和修改 HTML 非常不方便。
    于是 Java Server Pages(JSP) 就来救急了,JSP 并没有增加任何本质上不能用 Servlet 实现的功能。
    实际上JSP在运行之前,需要先编译成servlet , 然后才执行的。
    但是,在 JSP 中编写静态HTML 更加方便,不必再用 println语 句来输出每一行 HTML 代码。更重要的是,借助内容和外观的分离,页面制作中不同性质的任务可以方便地分开:比如,由页面设计者进行 HTML设计,同时留出供 Java 程序员插入动态内容的空间。
    Tomcat 能运行Servlet, 当然运行JSP肯定也是易如反掌。

    既然是Web 服务器, Tomcat除了能运行Servlet和JSP之外, 也能像Apache/nginx 那样,支持静态html, 图片,文档的访问, 只是性能要差一些, 在实际的应用中, 一般是这么使用他们的:


    image.png

    Nginx 作为负载均衡服务器 和静态资源服务器放在最前端, 后面是tomcat组成的集群。
    如果用户请求的是静态资源, Nginx直接搞定, 不用麻烦后面的tomcat了。
    如果是动态资源(如xxx.jsp) , Nginix 就会按照一定的算法转发到某个Tomcat上, 达到负载均衡的目的。

    (五) AJAX

    回到2001年, 当时的老刘还是小刘, 在计算所跟着老板和四川的一个公司合作,做一个类似于OA(办公自动化)的项目。
    当时小刘刚毕业,写过一些asp的程序,在小刘的意识当中, 还是觉得只要你通过浏览器向服务器发出请求, 服务器处理以后, 需要刷新整个网页才能看到服务器处理的结果。
    但是有一天我突然看到项目中大牛写的一个页面,这个页面上面是菜单,中间是一个树形结构,代表了一个公司的各个部门。
    点击了菜单以后, 整个页面没有刷新, 神奇的是那个部门的树形机构竟然发生了变化! 也就是说整个页面没有刷新, 只是页面的局部发生了刷新。
    太不可思议了 ! 我赶紧打开那个普通的asp程序, 看看到底是什么情况。
    原来点了菜单以后, 执行了一段javascript, 其中创建了一个叫XMLHttpRequest的东西;
    var xhr;
    if (window.XMLHttpRequest){
    xhr=new XMLHttpRequest(); //非IE浏览器
    }else{
    xhr=new ActiveXObject("Microsoft.XMLHTTP"); //IE 浏览器
    }

    //放置一个回调函数: state_change, 当http的状态发生变化时会调用
    xhr.onreadystatechange=state_change

    xhr.open("GET","http://xxxxxx.xxx/xxx.asp",true); // true 表示异步调用
    xhr.send(); //这是一个耗时的操作
    //具体的回调函数定义
    function state_change()
    {
    if (xmlhttp.readyState==4 && xmlhttp.status==200){
    //获取到服务器返回的xml
    xmlRes = xhr.responseXML;
    //对xml进行处理,更新部门的树形结构, 代码略
    document.getElementById('deptTree').innerHTML = xxxxxxx
    }

    }

    //其他代码, 略

    你可以想象我第一次看到这样的处理时那种震惊的表情。 原来页面可以这么写, javascript 可以这么用!
    其实这里体现的思想有两点:

    1. 异步调用
      异步的意思是说, 调用一个耗时的函数(上例中的xhr.send()) 以后, 不等到它返回,就直接执行后续的代码了。
      当然在调用它之前会放置一个回调的函数callback(上例中的state_change),等到这个耗时的函数完成以后,再来调用callback 。
      为什么要这么做呢? 主要是网络操作太耗时了, 你在浏览器中的一个点击可能访问是地球那一边的服务器, 如果是同步操作, 即等待网络操作完成以后再进行下一步, 就可能阻塞当前线程, 甚至会导致浏览器卡死的情况。

    异步调用在编程中是个非常常用的手段, 后来服务器端的javascript Node.js 几乎全是基于事件的异步调用。

    1. 用XML做浏览器端和服务器端的数据交换
      这点毋庸解释, 参见(3) ,看看xml 的作用。

    2. 局部刷新
      Javascript 取到从服务器端返回的XML以后, 解析该XML, 然后通过DOM对象只更新整个页面html的一部分,例如更新一个table, 一个div ....
      document.getElementById('deptTree').innerHTML = xxxxxxx

    异步的JavaScript和XML(Asynchronous Javascript And XML) 就简称AJAX, 你看这些缩写其实没什么神秘的。

    AJAX这个词2005才出现,之前已经出现了大量的“AJAX”Web应用, 我认为其中最著名的就是Google Maps 它使用XMLHttpRequest异步调用服务器端来获取数据,并将数据应用在客户端,实现了无刷新的效果,极好的用户体验让Google Maps获取了巨大的成功。

    【XML VS JSON】
    但是在javascript中使用XML有两个问题:

    1. XML 要求有开始标签和结束标签, 如<name>liuxin</name> ,name出现了两次, 这在网络传输中其实是一种冗余浪费。
    2. javascript 需要解析xml , 然后展示到浏览器中。
      第二点尤其不爽, 所以就有人发展了一个叫JSON(JavaScript Object Notation) 的一个轻量级的数据格式。 JSON其实就是javascript 语法的子集, 就是javascript中的对象和数组。
      对象在js中表示为“{}”括起来的内容,数据结构为 {key:value,key:value,...}的键值对的结构。
      数组在js中是中括号“[]”括起来的内容,数据结构为 ["java","javascript","vb",...]。
      这两种结构虽然很简单, 但是递归组合起来能表达任意的数据结构, 这就是简单的力量, 下面就是一个例子:
      {
      "programmers":
      [{
      "firstName": "Brett",
      "lastName": "McLaughlin",
      "email": "aaaa"
      }, {
      "firstName": "Jason",
      "lastName": "Hunter",
      "email": "bbbb"
      }],
      "authors":
      [{
      "firstName": "Isaac",
      "lastName": "Asimov",
      "genre": "sciencefiction"
      }, {
      "firstName": "Tad",
      "lastName": "Williams",
      "genre": "fantasy"
      }],
      "musicians":
      [{
      "firstName": "Eric",
      "lastName": "Clapton",
      "instrument": "guitar"
      }, {
      "firstName": "Sergei",
      "lastName": "Rachmaninoff",
      "instrument": "piano"
      }]
      }

    由于JSON本身就是Javascript 语法的一部分, javascipt代码可以直接把他们当成对象来处理, 根本不用解析XML了。
    再加上JSON结构很紧凑, 很快就流行开来了, 现在AJAX 基本上都是在用JSON来传递数据了。

    (六) Java 反射

    讲点稍微有深度的:反射。
    这里不定义什么叫反射,先来看个例子,假设我给你一个Java 类:
    package com.example;
    public class HelloWorld {
    public HelloWorld(){
    }
    public void sayHello(){
    System.out.println("hello world!");
    }
    }
    现在要求:
    (1) 你不能使用 HelloWorld hw = new HelloWorld() , 但是要构建一个HelloWorld的实例来.
    (2) 调用sayHello() 方法, 但是不能直接用 HelloWorld实例的 hw.sayHello()方法 , 说起来怪拗口的 :-)

    用Java的反射功能, 可以很轻松的完成上面的要求:
    //第一步, 先把HelloWorld的类装载进来
    Class cls = Class.forName("com.example.HelloWorld");
    //第二步, 创建一个HelloWorld的实例, 注意, 这里并没有用强制转型把obj转成HelloWorld
    Object obj = cls.newInstance();
    //第三步, 得到这个类的方法, 注意, 一个类的方法也是对象啊
    Method m = cls.getDeclaredMethod("sayHello");
    //第四部, 方法调用, 输出"hello world"
    m.invoke(obj);
    可能有人要问了, 为什么不直接new 出来呢? 通过反射来创建对象,调用方法多费劲啊 ?
    这是个好问题,关键点就是: 很多时候我们并不能事先知道要new 什么对象, 相反,我们可能只知道一个类的名称和方法名, 很多时候这些名称都是写在XML配置当中的。

    为了更好的说明问题, 来看看几个SSH的例子:
    【Struts的例子】

    1. 在XML配置文件中定义Action
      <action name="HelloWorld" class="example.HelloWorld">
      <result>/hello.jsp</result>
      </action>
    2. 定义Java 类
      public class HelloWorld extends ExampleSupport {
      public String execute() throws Exception {
      ......
      return SUCCESS;
      }
      .......
      }
      Struts 框架的作者事先肯定不知道你会配置一个HelloWorld的Action 。
      不过他可以这么做, Struts 在启动以后,解析你配置XML配置文件, 发现名称为HelloWorld的Action, 找到相对于的类名example.HelloWorld, 然后就可以通过反射去实例化这个类。 等到有人调用这个action 的时候, 可以通过反射来调用HelloWorld的execute() 方法。
      【Hibernate的例子】
    3. 定义Java类和表之间映射, 类名叫Event, 对应的表名是EVENTS 。
      <hibernate-mapping package="org.hibernate.tutorial.hbm">
      <class name="Event" table="EVENTS">
      <id name="id" column="EVENT_ID">
      <generator class="increment"/>
      </id>
      <property name="date" type="timestamp" column="EVENT_DATE"/>
      <property name="title"/>
      </class>
      </hibernate-mapping>
    4. 定义Event 类,如下所示:
      public class Event {
      private Long id;
      private String title;
      private Date date;
      ...... 为了节省篇幅, 每个属性的getter /setter 方法略...
      }
    5. 查询, 你可以用Hibernate 这么查询表中的数据了:
      List result = session.createQuery( "from Event" ).list();
      for ( Event event : (List<Event>) result ) {
      System.out.println( "Event (" + event.getDate() + ") : " + event.getTitle() );
      }
      Struts 的作者事先也不知道你会配置一个叫Event的类。
      不过他会这么处理: 类名(Event)-> 数据库表名(EVENTS) -> 发出SELECT查询表数据 -> 通过反射创建Event的实例 -> 通过反射调用实例的setter方法把数据库的值设置进去

    【Spring的例子】

    1. 配置一个Bean
      <beanid="helloWorld"class="example.HelloWorld">
      <propertyname="message"value="Hello World!"/>
      </bean>

    2. 写一个Java 文件
      public class HelloWorld
      {
      private String message;
      public void setMessage(String message){
      this.message = message;
      }
      public void getMessage(){
      System.out.println("My Message : "+ message);
      }
      }

    3. 调用

    ApplicationContext context =newClassPathXmlApplicationContext("Beans.xml");
    HelloWorld hw=(HelloWorld) context.getBean("helloWorld");
    hw.getMessage();
    我都懒得解释了, 无非是根据类的名称通过反射创建一个类HelloWorld的实例, 然后再通过反射调用setMessage方法, 这样当你getMessage就有值了。
    所以反射是很重要的, 在Java EE世界里, 反射最大的用途就是支持以声明式的方法(在XML中)来描述应用的行为, 是Struts, Hibernate , Spring 的最核心的技术之一。
    简单的来讲, 反射能让你在运行时而不是编程时做下面的事情:
    (1) 获取一个类的内部结构信息(或者成为元数据), 包括包名,类名, 类所有的方法,
    (2) 运行时对一个Java对象进行操作, 包括创建这个类的实例, 设置一个属性的值, 调用这个类的方法等等。
    这篇文章只是介绍了反射的一点皮毛和用途, 具体的细节还是等待你自己去发掘吧。
    【元编程】
    等等,还有一个小问题:为什么叫反射呢?
    我想可能是Java程序在运行时能够看到自己的结构和行为吧, 就像看到镜子当中的自己一样, 反射了出来 。
    如果扩展一点, 这种用代码来生成代码的方式, 其实叫做“元编程”。
    C语言就不具备这样的能力, 经过编译以后, C语言中的struct 名称 , 数组名等信息都已经消失了, 基本上就是指针了。 你可以这么试一试:写个程序,在运行时打印一下一个struct的名称, 看看能不能实现。
    但是像其他一些语言, 例如Ruby , 程序在运行时不但能检视自己, 还能动态的修改自己, 比如:给自己加上一个方法, 这种开放的能力给Ruby 编程来了巨大的飞跃, LISP的元编程能力更加强悍, 仅仅使用LISP自己就能定义一个新语言出来。
    利用这种能力, 人们可以针对某个领域编写领域特定语言(Domain specific Language, 简称DSL), 然后使用DSL这个语言来进行应用编程, 那效率可不是一般的高, 像Ruby on Rail 不就号称开发速度是Java的10倍嘛!

    相关文章

      网友评论

          本文标题:J2EE入门指南(转)

          本文链接:https://www.haomeiwen.com/subject/pinshctx.html