EJB开发第二期---开发具有本地接口的无状态Bean

一、EJB中的bean

1.1 EJB中bean分类

会话bean(session bean)

负责与客户端交互,是编写业务逻辑的地方,在会话bean中可以通过jdbc直接操作数据库,但大多数情况下都是通过实体bean来完成对数据库的操作。

实体bean(entity bean)

它实际上属于java持久化规范(简称JPA)里的技术,JPA的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate、TopLink等ORM框架各自为营的局面。

消息驱动bean(message-driven bean)

它是专门用于异步处理java消息的组件,具有处理大量并发消息的能力。

1.2会话bean

无状态会话bean

平常,我们使用最多的是无状态bean,因为它的bean实例可供多个用户使用,所以它的性能比有状态bean高。正因为一个bean实例被多个用户使用,那么,前一个用户设置的值有可能被后一个用户所修改,所以它无法正确保存某个用户设置的值,因此是无状态的。

有状态会话bean

有状态bean平常使用的并不多,因为它的一个bean实例只供一个用户使用,所以性能开销比较大,正因为它的实例只被一个用户使用,用户为它设置的值是不会被其他用户修改,所以可以正确保存用户设置的值,因此是有状态的。

二、开发无状态会话bean

2.1 开发工具

IDE工具:Eclipse Java EE IDE for Web Developers Version: Indigo Service Release 2

JBoss服务器:jboss-4.2.3.GA

JDK:JDK-1.6

打包工具:Ant

EJB依赖jar包:jboss安装路径的client目录下所有Jar文件以及javaee.jar

2.2 开发无状态会话bean

在开发前,先熟悉一下无状态会话bean的调用流程图,如下图所示。

01. 浏览器请求Test.jsp文件。

02. 应用服务器的JSP引掣编译Test.jsp。

03. Tast.jsp通过JNDI查找获得HelIoWorld EJB的存根对象,然后调用SayHello{)方法,EJB容器截获到方法调用。

04. EJB容器调用HeIIoWorld实例的SayHello()方法 。

05. 返回客户端浏览器。

2.3 开发步骤

无状态会话bean的开发步骤如下:

(1) 定义一个包含业务方法的接口

这个接口不需要包含任何注释,它是一个普通的Java接口。调用EJB的客户端,使用这个接口引用从EJB容器返回的存根( stub)。代码如下:

package ejb3Hello;

public interface HelloWorld {

public String SayHello(String name);

}

(2) 编写Bean class

HeIIoWorldBean.java。Bean类推荐的命名方式是"接口+Bean",如HeIIoWorldBean。代码如下:

package ejb3Hello.impl;

import ejb3Hello.HelloWorld;

import javax.ejb.Remote;

import javax.ejb.Stateless;

@Stateless

@Remote({HelloWorld.class})

public class HelloWorldBean implements HelloWorld{

@Override

public String SayHello(String name) {

return name+"say:hello,this is my first EJB3.0.";

}

}

在Bean类上面有两个注释@Stateless和@Remote,@Stateless注释指明这是一个无状态会话Bean。@Stateless注释的定义如下:

Package javax.ejb;

@Target(TYPE) @Retention(RUNTIME)

public @interface Stateless {

String name() default "";

String mappedName() default "";

}

name()属性用于指定Session Bean的EJB名称。该名称在EJB Jar包中必须是全局唯一的,而在EAR中却可以重复,因为EAR可以包含多个EJB JAR,而每个JAR可以存在一个同名的EJB。在EAR中要定位某个EJB,可以这样使用:xxx.jar#HeIloWorldBean。如果不指定该属性,默认就是Bean class的非限定名称。对本例而言,EJB名称默认为HeIIoWorldBean。

mappedName()属性指定Bean的全局JNDI名称,这个属性在WebLogic、Sun应用服务器和glassfish起作用。

@Remote注释指定这个无状态Bean的remote接口。Bean类可以具有多个remote接口,每个接口之间用逗号分隔,如:@Remote({HeIIoWorld.class,Hello.class,World.class})。

如果只有一个接口,则可以省略大括号,对于本例而言,可以写成这样:@Remote(HeIloWorld.class)。

经过上面两步,一个HeIloWorld EJB就开发完了。现在将它发布到JBoss中。在发布前需要把它打成JAR色。打包JAR的方法有很多,如使用jar命令、集成开发工具或者Ant。下面介绍两种常用的打包方式:Eclipse打包向导和Ant打包。

三、EJB任务打包

3.1 Jar命令打包

jar命令打包比较简单,进入要被打包的文件根目录中,比如被打包程序的目录结构如下:

|---D:\webapp

|---Test.jsp

|--- WEB-INF

|---web.xml

可以进入到D:\webapp目录下,执行如下命令:

jar cvf EJBTest.jar war *

此命令将把Web应用的根目录下的所有文件打包成EJBTest.war文件,参数一:表示打包方式,参数二:表示打包后的文件名,参数三:表示文件类型。打包后的文件内容如下:

3.2 Eclipse打包

步骤一:选择打包程序右键或单击Flile菜单,如下图所示。

步骤二:选择Export选项,如下图所示,同时选择打包的类型:jar文件,填写文件路径及文件名。

步骤三:选择next选项,如下图所示,选择默认设置就行。

步骤四:选择next选项,如下图所示,如果程序中有main函数,选择Main类,最后选择finish。

3.3 Ant打包方式

步骤一:选择项目右键,新建Ant的build.xml文件。

步骤二:在 build.xml文件,可以编写所要做的工作,包括如下:

01. 对应用进行编译

02. 对应用进行打包

03. 对应用进行发布

04. 对应用进行解发

build.xml文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<project name="HelloWorld",basedir=".">

<property name="src.dir" value="${basedir}\src"/>

<property environment="env"/>

<property name="jboss.home" value="${env.JBOSS_HOME}"/>

<property name="jboss.server.config" value="default"/>

<property name="build.dir" value="${basedir}\build"/>

<path id="build.classpath">

<fileset dir="${jboss.home}\client">

<include name="*.jar"/>

</fileset>

<pathelement location="${build.dir}"/>

</path>

<target name="prepare">

<delete dir="${build.dir}"/>

<mkdir dir="${build.dir}" />

</target>

<target name="compile" depends="prepare" description="编译">

<javac srcdir="${src.dir}" destdir="{build.dir}">

<classpath refid="build.classpath"/>

</javac>

</target>

<target name="ejbjar" depends="compile" description="创建EJB发布包">

<jar jarfile="${basedir}\${ant.project.name}.jar">

<fileset dir="${build.dir}">

<include name="**/*.class"

</fileset>

</jar>

</target>

</project>

这个打包任务建立了一个名为HelloWorld的Ant项目,项目的源目录由basedir属性来表示。该项目定义的四个属性如下:

"src.dir":源文件路径

"env":环境变量

"jboss.home":Jboss安装目录

"jboss.server.config":指定目前Jboss使用的配置项

"build.dir":编译源文件的class类的目录

接下来是一个类路径配置如下,它指定了应用程序依赖的jar文件,并且可以从配置项可以看出将编译存放的类路径也添加进来,如:pathelement。

<path id="build.classpath">

<fileset dir="${jboss.home}\client">

<include name="*.jar"/>

</fileset>

<pathelement location="${build.dir}"/>

</path>

接下来又定义了一些具体任务,如下:

<target name="prepare">

<delete dir="${build.dir}"/>

<mkdir dir="${build.dir}" />

</target>

该任务定义了,创建的build文件夹目录,用于存放编译后的jar文件,并定义了清空路径。

<target name="compile" depends="prepare" description="编译">

<javac srcdir="${src.dir}" destdir="{build.dir}">

<classpath refid="build.classpath"/>

</javac>

</target>

不难看出,该任务就是编译任务。通过javac命令对源文件进行编译。编译的源文件目录为:src.dir,编译后的源文件存放目录为:build.dir,编译过程中用的jar包通过refid来引用。并且该任务依赖于prepare任务,只有prepare任务先执行,该任务才可执行。

<target name="ejbjar" depends="compile" description="创建EJB发布包">

<jar jarfile="${basedir}\${ant.project.name}.jar">

<fileset dir="${build.dir}">

<include name="**/*.class"

</fileset>

</jar>

</target>

该任务为打包任务,用到了jar命令对类文件进行打包。打包出来的路径:

步骤三:在 build.xml文件,在Eclispe的Outline栏,执行build中的任务,首先执行编译。

编译结果,Eclispe中console输出如下图所示:

编译后的,项目结构如下:

步骤四:在 build.xml文件,在Eclispe的Outline栏,执行打包,console端输出如下。

打包后的项目结构如下:

步骤五:在 build.xml文件,在Eclispe的Outline栏,执行发布,执行结果如下表示发布成功。

19:16:45,605 INFO [AjpProtocol] Starting Coyote AJP/1.3 on ajp-127.0.0.1-8009

19:16:45,611 INFO [Server] JBoss (MX MicroKernel) [4.2.3.GA (build: SVNTag=JBoss_4_2_3_GA date=200807181439)] Started in 9s:386ms

19:17:45,945 INFO [JmxKernelAbstraction] creating wrapper delegate for: org.jboss.ejb3.stateless.StatelessContainer

19:17:45,949 INFO [JmxKernelAbstraction] installing MBean: jboss.j2ee:jar=EJBTest.jar,name=HelloWorldBean,service=EJB3 with dependencies:

19:17:45,975 INFO [EJBContainer] STARTED EJB: ejb3Hello.impl.HelloWorldBean ejbName: HelloWorldBean

19:17:46,008 INFO [EJB3Deployer] Deployed: file:/F:/Tools/DevelopTool/javaserver/jboss-4.2.3.GA/server/default/deploy/EJBTest.jar

网页查看方式如下:

Global JNDI Namespace:

如上图所示表示,EJB发布成功。 在上图所示页面中可以看到JBoss的JNDI树。其命名约定如下:

(1) java:comp (Java:comp namespace)

这个上下文环境和其子上下文环境仅能被应用组件内部访问和使用。

(2) java: (Java: Namespace)

子上下文环境和绑定的对象只能被处在同一个JVM内的客户访问。

(3) Global JNDI Namespace

上下文环境能被所有客户访问,不管它们是否处在同一个JVM内。

当EJB发布到JBoss时,如果没有为它指定全局JNDI名称。JBoss就会按照默认的命名规则,为EJB生成全局JNDI名称。默认的命名规则如下:

■ 如果把EJB作为模块打包进后缀为*.ear的Java EE企业应用文件,默认的全局JNDI名称如下:

■ 本地接口:EAR-FILE-BASE-NAME/EJB-CLASS-NAME/local

■ 远程接口:EAR-FILE-BASE-NAME/EJB-CLASS -NAME/remote

EAR-FILE-BASE-NAME为ear文件的名称,EJB-CLASS-NAME为EJB的非限定类名。

:把HelloWorld应用作为EJB模块打包进名为HeIIoWorld.ear的企业应用文件,它的远程接口的JNDI名称是HeIloWorld/HeIloWorldBean/remote。

■ 如果把EJB应用打包成后缀为*.j ar的模块文件,默认的全局JNDI名称如下。

■ 本地接口:EJB-CLASS-NAME/local

■ 远程接口:EJB-CLASS-NAME/remote

:把HelIoWorld应用打包成HelIoWorld.jar文件,它的远程接口的JNDI名称是HelIoWorldBean/remote。

注意:EJB-CLASS-NAME是不带包名的,如ejb3Hello.impl.HeIIoWorldBean只需取HeIIoWorldBean。在Glabal JNDI Namespace栏可以看到HeIIoWorldBean的远程接口的JNDI名称为,HeIIoWorldBean/remote,意味者EJB已经发布成功,接下来看看客户端如何访问它。

四、开发EJB客户端

4.1 EJB客户端代码

public class EJBClient {

public static void main(String[] args) {

Properties props = new Properties();

props.setProperty("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");

props.setProperty("java.naming.provider.url", "localhost:1099");

try {

InitialContext ctx = new InitialContext(props);

HelloWorld helloworld = (HelloWorld) ctx.lookup("HelloWorldBean/remote");

System.out.println(helloworld.sayHello("Sunddenly"));

} catch (NamingException e) {

System.out.println(e.getMessage());

}

}

}

4.1 EJB客户端运行结果

运行结果如下:

Sunddenly say:hello,this is my first EJB3.0.

五、开发具有Local接口的Session bean

5.1 概述

之前,我们介绍过远程接口。在这里,我们需要了解一下通过远程接口调用ejb的过程。首先客户端需要与ejb建立起socket通信,在通信管道上他们之间需要来回发送IIOP协议消息,因为数据要在网络进行传输,存放数据的java对象必须要进行序列化。

在这个过程中我们看到,有网络通信的开销、协议解析的开销、对象序列化的开销。因为ejb是分布式技术,它允许客户端与ejb应用在不同一机器上面,所以这些性能开销也是必然的。但是在实际生产中,不可避免存在这种情况:客户端与EJB应用运行在同一个jboss中。这时候客户端访问ejb是否有必要走上面的网络通信呢?据我们所知,这时候客户端与ejb是在同一个jvm内,他们之间完全可以通过内存进行交互,这样就可以避免网络通信的性能开销。既然我们都想到了这一点,EJB专家组也想到了这一点,所以引入了本地接口。通过本地接口调用ejb,直接在内存中交互,这样就能避免因网络通信所造成的各种性能开销。但是有一点,大家必须注意,只有客户端与EJB应用在同一个JVM内运行的时候,我们才能调用本地接口,否则只能调用远程接口。谈到这里,有同学会问什么情况下客户端与EJB应用是在同一个JVM?简单地说只要客户端与ejb发布在同一个jboss内,我们就认为他们是在同一个JVM。

5.2 程序实现

开发只有Local接口的无状态Session Bean的步骤和开发只有Remote接口的无状态会话Bean的步骤相同,两者唯一不同之处是,前者使用@Remote注释声明接口是远程接口,后者使用@Local注释声明接口是本地接口。当@Local和@Remote注释都不存在时,容器会将Bean class实现的接口默认为Local接口。如果EJB与客户端部署在同一个应用服务器。采用Local接口访问EJB优于Remote接口。因为通过Remote接口访问EJB需要在TCP/IP协议基础上转换和解释Corba IIOP协议消息,在调用EJB的这一过程中存在对象序列化,协议解释、TCP/IP通信等开销。而通过Local接口访问EJB是在内存中与Bean彼此交互的,没有了分布式对象协议的开销,大大改善了性能。下面是只有Loctd接口的无状态会话Bean。

业务接口:LocaIHeIloWorld.java

package ejb3Hello;

public interface LocalHelloWorld {

public String sayHello(String name);

}

Bean类:LocaIHeIloWorldBean.java

package ejb3Hello.impl;

import javax.ejb.Local;

import javax.ejb.Remote;

import javax.ejb.Stateless;

import ejb3Hello.LocalHelloWorld;

@Stateless

@Local({LocalHelloWorld.class})

public class LocalHelloWorldBean implements LocalHelloWorld{

@Override

public String sayHello(String name) {

return name+"say:hello,this is my first EJB3.0.";

}

}

@Local和@Remote注释一样,@Local注释也可以定义多个本地接口。如:@Local({ LocaIHelloWorld.class,Hello.class,World.class})。如果只有一个本地接口,可以省略大括号,对于本例而言,可以写成:@Remote(LocalHelIoWorld.class)。把上面的EJB打包成jar文件后,发布到"jboss安装目录/server/default/deploy目录中。接下来编写客户端调用代码。

客户端类:

将上面的代码打包成jar文件,发布到JBoss后会生成一个JNDI名称:beanname/lcoal。即,LocalHelloworldBean/local。下面按照Remote客户端方式编写的客户端代码如下:

public class EJBClient {

public static void main(String[] args) {

try {

InitialContext ctx = new InitialContext();

LocalHelloWorld helloworld = (LocalHelloWorld) ctx.lookup("HelloWorldBean/local");

System.out.println(helloworld.sayHello("Sunddenly "));

} catch (NamingException e) {

System.out.println(e.getMessage());

}

}

}

运行结果如下:

Exception in thread "main" javax.ejb.EJBException: Invalid (i.e. remote) invocation of local interface (null container)

at org.jboss.ejb3.stateless.StatelessLocalProxy.invoke(StatelessLocalProxy.java:80)

at $Proxy0.sayHello(Unknown Source)

at ejb3Hello.impl.test.EJBClient.main(EJBClient.java:15)

运行过程中抛出了异常,大概意思为:无效的本地接口调用。这是因为目前,客户端和EJB应用在不同的JVM内,如果客户端和EJB应用在不同的JVM内中,我们只能通过远程接口调用EJB而不能通过本地接口调用EJB。那么,如果我们要通过本地接口调用EJB应用,就必须确保客户端和EJB在同一个JVM内,也就是说部署在同一个JBss中。

5.2 创建Web客户端应用

考虑到大部分客户端应用都是Web应用,在这里我也建立一个Web应用作为EJB客户端,并把它部署到Jboos中。WEB应用创建过程如下:

步骤一:创建Web工程,选择动态Web项目,如下:

点击next,填写项目名称,和服务器类型

next

next,之后finish

步骤二:在Web应用中创建Jsp文件,如下:

next,之后finish

步骤三:修改Web应用中创建的Jsp文件,格式改为"UTF-8",并把文件存放格式改为"UTF-8",如下:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"

pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

<title>Insert title here</title>

</head>

<body>

</body>

</html>

步骤四:编辑Test.jsp客户端,如下:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"

pageEncoding="UTF-8"%>

<%@ page import="javax.naming.*,ejb3Hello.*" %>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

<title>Insert title here</title>

</head>

<body>

<%

try {

InitialContext ctx = new InitialContext();

HelloWorld helloworld = (HelloWorld) ctx.lookup("HelloWorldBean/local");

out.println(helloworld.sayHello("Local Person "));

} catch (NamingException e) {

out.println(e.getMessage());

}

%>

</body>

</html>

步骤五:将程序Ant打包并发布,Ant 的build.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>

<project name="LocalHelloWorld" basedir=".">

<property name="src.dir" value="${basedir}\src"/>

<property environment="env"/>

<property name="jboss.home" value="${env.JBOSS_HOME}"/>

<property name="jboss.server.config" value="default"/>

<property name="build.dir" value="${basedir}\build"/>

<path id="build.classpath">

<fileset dir="${jboss.home}\client">

<include name="*.jar"/>

</fileset>

<pathelement location="${build.dir}"/>

</path>

<target name="prepare">

<delete dir="${build.dir}"/>

<mkdir dir="${build.dir}" />

</target>

<target name="compile" depends="prepare" description="编译">

<javac srcdir="${src.dir}" destdir="${build.dir}">

<classpath refid="build.classpath"/>

</javac>

</target>

<target name="ejbjar" depends="compile" description="创建EJB发布包">

<jar jarfile="${basedir}\${ant.project.name}.jar">

<fileset dir="${build.dir}">

<include name="**/*.class"/>

</fileset>

</jar>

</target>

<target    name="deploy" depends="ejbjar" description="发布ejb">

<copy file="${basedir}\${ant.project.name}.jar" todir="${jboss.home}\server\${jboss.server.config}\deploy"/>

</target>

<target    name="undeploy" description="卸载ejb">

<delete file="${jboss.home}\server\${jboss.server.config}\deploy\${ant.project.name}.jar"/>

</target>

</project>

5.3 创建Web客户端运行结果

如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【Sunddenly】。

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

时间: 2024-10-19 08:34:29

EJB开发第二期---开发具有本地接口的无状态Bean的相关文章

EJB通过ANT提高EJB应用的开发效率、开发具有本地接口的无状态bean、开发有状态bean

把jboss集成进eclipse 关闭Jboss控制台按Ctrl+c,在MyEclipse→Servers→Jboss里面可以配置JBoss. 通过ANT提高EJB应用的开发效率 在HelloWorld 加入ANT,右击项目新建xml:build.xml,右击打开方式选择Ant .. 对应用进行编译.打包.发布.解发布 <?xml version="1.0" encoding="UTF-8"?> <!--basedirz项目所在路径,.代表在bui

微信开发第二讲 开发与微信交互的servlet

?? 在上一节中我们学习了如何在微信服务号中配置URL和token,现在介绍一下如何开发与微信交互的Servlet. package com.demo.weixin.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.htt

EJB通过ANT提高EJB应用程序的开发效率、无状态发展本地接口bean、开发状态bean

该jboss集成到eclipse 关掉Jboss控制台新闻Ctrl+c,在MyEclipse→Servers→Jboss可配置JBoss. 通过ANT提高EJB应用的开发效率 在HelloWorld 增加ANT,右击项目新建xml:build.xml,右击打开方式选择Ant .. 相应用进行编译.打包.公布.解公布 <? xml version="1.0" encoding="UTF-8"? > <!--basedirz项目所在路径,.代表在bui

EJB开发第一个无状态会话bean、开发EJB客户端

开发第一个无状态会话bean EJB中的三中bean: 会话Bean(Session Bean) 负责与客户端交互,是编写业务逻辑的地方,在会话bean中可以通过JDBC直接操作数据库,但大多数情况下都是通过实体bean来完成对数据库的操作. 实体Bean(Entity Bean) 它实际上属于java持久化规范(JPA)里的技术,JPA的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate.TopLink等ORM框架各自为营的局面. 消息驱动Bean(Messag

Java深度历险(二) EJB Session Bean有状态和无状态的区别与联系

刚开始对两种sessionbean存在误解,认为有状态是实例一直存在,保存每次调用后的状态,并对下一次调用起作用,而认为无状态是每次调用实例化一次,不保留用户信息.仔细分析并用实践检验后,会发现,事实恰好相反:有状态和无状态会话bean的本质区别是它们的生命期. 首先解释一个下面要用到的概念--用户:sessionbean 的用户实际上就是直接调用ejb的类的实例,甚至是这个实例的某个方法.同一个类的不同实例对于session bean来说是不同的用户. 实例解析 有状态的StatefulEjb

EJB 有状态的对象和无状态的对象

有状态Bean: @Stateful @Remote public class StatefulEjbBean implements StatefulEjb{ private int state; @Override public void compute(int i) { state=state+i; } @Override public int getResult() { return state; } } 无状态Bean: @Stateless @Remote public class S

有状态的EJB对象和无状态的EJB对象

一,定义有状态Bean和无状态Bean 有状态Bean: @Stateful @Remote public class StatefulEjbBean implements StatefulEjb{ private int state; @Override public void compute(int i) { state=state+i; } @Override public int getResult() { return state; } } 无状态Bean: @Stateless @R

JBoss+Ant实现EJB无状态会话bean实例

EJB分为session bean.entity bean.message-driven bean,session bean又分为无状态会话bean和有状态会话bean. session bean负责与客户端交互,是编写业务逻辑的地方,在session bean中可以通过jdbc直接操作数据库,但大多数情况下都是通过entity bean来完成对数据库的操作的. 平常,我们使用最多的是无状态bean,因为它的bean实例可供多个用户使用,所以它的性能比有状态bean高.正因为一个bean实例被多

组队开发第二周第五次会议

会议时间:组队开发第二周  星期日   开始时间晚上3:30-10:20 会议地点:学一食堂 二楼 到会人员:李志岩  王亚蕊 安帅 薛禄坤 张新宇 孙存良 会议概要:   1.总结开发的成果: 2.讨论开发中遇到的问题: 3. 更新任务板: 内容一  总结开发的成果 李志岩 实现添加通知栏 部分代码 效果图 张新宇   对spinner的学习 薛禄坤  Edit  Text控件 EditText有一些属性可以设置EditText的特性,比如最大长度,空白提示文字等. 1. 有时候我们有一些特属