学习EJB3基础知识笔记

最近项目进入系统测试阶段,全赖袁大虾领导有力,保持一周零bug记录,这也让自己腾出不少时间补充知识。花了两天时间把“传智播客EJB3.0”看完了,EJB基本的知识也有些了解,在这记录下EJB的部分知识,以供自己以后复习使用。

 

EJB是sun的服务器端组件模型,最大的用处是部署分布式应用程序。EJB (Enterprise JavaBean)是J2EE的一部分,定义了一个用于开发基于组件的企业多重应用程序的标准。EJB依赖Web服务器,通常入门级推荐使用Jboss服务器,并且Jboss服务器提供了Ejb必备的jar包。

 

EJB中包含三种bean:

①会话bean:负责与客户端交互的bean,主要完成业务逻辑操作,类似于J2EE三层架构(表现层、业务层、持久层)中的业务逻辑层。

②实体bean:java持久化规范(JPA)中的技术,类似于三层架构的持久层,与数据库打交道,Hibernate等经典ORM框架实现了JPA技术。

③消息驱动bean:用户异步处理java消息的组件,具有处理大量并发消息的能力,比如转发短信功能。

 

bean分两种状态:

①有状态bean:一个实例仅供一个用户使用,性能开发较大。

   有状态bean管理对象使用的是激活技术:

            用户初次调用bean时,首先实例化bean

            用户调用结束,垃圾回收器会回收bean,在回收前EJB会将该bean对象通过序列化放入硬盘中(此为钝化)

            当用户再次调用该bean时,EJB又从硬盘反序列对象到内存中形成实例供用户使用(此为激活)

@Stateful   //指定当前Bean为有状态Bean
@Remote(StatefulRemote.class)
@Local(StatefulLocal.class)
public class StatefulImpl implements StatefulLocal,StatefulRemote{

	@Override
	public String say(String s) {
		return "有状态Bean :"+s;
	}
	
}

 

②无状态bean:一个实例可供多个用户使用,性能高,但线程可能不安全。

   无状态bean使用实例池技术管理:类似于数据库连接池,预先创建几个bean实例,用户请求来之后EJB给用户分配空闲的bean实例,如果都不空闲则等待,直到有空闲实例或超时为止。

@Stateless  //指定当前bean为无状态bean
@Remote(StatelessRemote.class)
@Local(StatelessLocal.class)
public class StatelessImpl implements StatelessLocal,StatelessRemote{

	@Override
	public String say(String s) {
		return "无状态Bean :"+s;
	}
	
}

 

 

EJB的分布式技术决定了EJB可以远程调用,所以EJB的bean又分两种类型:远程和本地

①远程接口:客户端与EJB可以不在同一台电脑或者同一个服务器,只要网络畅通,可以通过远程调用即可获得客户需要的信息。客户远程访问EJB是通过Socket通信实现,具体的实现方法已经写好,用户只需要指定该接口为远程即可。

②本地接口:如果客户端与EJB在同一部署服务器下,客户端即可调用本地接口的EJB。此时因为在同一台电脑下,EJB不会通过Socket的方式通信,所以本地接口的运行速度是比远程接口要快的。

用户通过注解可以很方便的定义哪些接口为远程,哪些接口为本地(不是说所有bean都必须要有远程和本地两接口,这是根据项目需要来定,你也可以只做一个本地接口或一个远程接口)。

@Remote(StatelessRemote.class)
@Local(StatelessLocal.class)

 

【部署EJB】

通常用户需要把EJB打成jar包,然后放入Jboss服务器(可以是启动状态)server下的指定目录deploy文件夹下即可,具体的部署方式建议大家看视频或百度谷歌学习。

 

【调用EJB】

如果EJB部署成功,用户可以通过JNDI调用指定bean来测试。前面已经说了,本地接口类型的bean是需要新建一个j2ee项目并且部署到同一jboss下测试;而远程接口的bean则只要客户端不在jboss服务器下均可测试。

 

远程接口测试方法:

public class EjbClient {
	public static void main(String[] args) throws NamingException {
		//获取创建EJB JNDI
		InitialContext ctx = new InitialContext();
		//有状态bean使用激活管理bean
		StatefulRemote stateful = (StatefulRemote) ctx.lookup("StatefulImpl/remote");
		System.out.println(stateful.say("xxoo"));
		System.out.println("---------------------");
		//无状态bean使用 实例池技术管理bean
		StatelessRemote stateless = (StatelessRemote) ctx.lookup("StatelessImpl/remote");
		System.out.println(stateless.say("ooxx"));
	}
}

 

注意InitialContext会默认读取名为“jndi.properties”文件的信息以获得JNDI上下文环境。

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost:1099

 

本地接口的测试方法:

首先新建一个web项目,进入时默认访问一个jsp页面,在jsp页面中写如下代码:

<body>
	<%
	//获取创建EJB JNDI
	InitialContext ctx = new InitialContext();
	//调用本地接口
	StatefulLocal stateful = (StatefulLocal) ctx.lookup("StatefulImpl/local");
	%>
	<%=stateful.say("only") %>
	<br/>------------------------------------<br/>
	<%
	//调用本地接口
	StatelessLocal stateless = (StatelessLocal) ctx.lookup("StatelessImpl/local");
	%>
	<%=stateless.say("nani") %>
	<br/>------------------------------------<br/>
	<%
	//ejb调用ejb
	IocBean ioc = (IocBean)ctx.lookup("IocBeanImpl/local");
	%>
	<%=ioc.say() %>
</body>

最后将web项目部署到同一jboss服务器,再访问web项目即可。

 

 

【EJB注入】

在开发中,我们难免会遇到bean调用bean对象的情况,注意:通过new xxBean的方式是不正确的,那不是一个EJB正确的调用方式。通常通过注解能非常轻松的注入bean:

@Stateless
public class IocBeanImpl implements IocBean{
	//指定输入名为StatelessImpl的会话bean
	@EJB(beanName="StatelessImpl") StatelessLocal stateless;
	@Override
	public String say() {
		return "注入Bean :" + stateless.say("注入者");
	}
	

 

 

【JPA技术实现实体bean】

首先我们必须配置数据源:确定使用什么数据库,帐号密码等。如果文件名以-ds结尾会被认定为数据源:

<datasources>
  <local-tx-datasource>
    <jndi-name>MySqlDS</jndi-name>
    <connection-url>jdbc:mysql://localhost:3306/mtjdbc?characterEncoding=utf-8</connection-url>
    <driver-class>com.mysql.jdbc.Driver</driver-class>
    <user-name>root</user-name>
    <password>sa</password>
    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
    <metadata>
       <type-mapping>mySQL</type-mapping>
    </metadata>
  </local-tx-datasource>
</datasources>

 将数据源xml文件放入deploy目下即可。

 

然后是在EJB项目中定义persistence.xml文件,该文件必须在META-INF目录下,功能等同于平常hibernate的config文件,定义数据源的JNDI、指定映射文件以及数据库框架的额外设置:

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
	version="1.0">

	<!-- 定义持久化单元 -->
	<persistence-unit name="jpademo" transaction-type="JTA">
		<!-- 指定数据源的JNDI名 -->
		<jta-data-source>java:MySqlDS</jta-data-source>
		<properties>
			<property name="hibernate.hbm2ddl.auto" value="update" />
			<!-- 打印sql语句 -->
    		<property name="hibernate.show_sql" value="true" />
    		<!-- 格式化sql语句 -->
    		<property name="hibernate.format_sql" value="true"/>
		</properties>
	</persistence-unit>
</persistence>

 

 了解hibernate的应该知道javabean是orm的关键,用户可以写一个xml+一个javabean实现orm映射,也可以使用单纯的javabean再通过注解定义orm关系:

@Entity
@Table(name = "userinfo")
public class Userinfo implements Serializable {
	private static final long serialVersionUID = -1983888820266030468L;

	@Id
	@Column(name = "id")
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;
	@Column(name = "code")
	private String code;
	@Column(name = "name")
	private String name;
	@Column(name = "sex")
	private Integer sex;
	@Column(name = "phone")
	private String phone;
	@Column(name = "money")
	private double money;

...........

编写增删改查bean,JPA标准定义了增删改查方法接口,hibernate也很好的完成了接口的实现。 

 

@Stateless
@Remote(UserinfoService.class)
public class UserinfoServiceImpl implements UserinfoService{
	//unitName指定persistence.xml持久化单元名
	@PersistenceContext(unitName="jpademo") EntityManager em;
	
	
	@Override
	public void delete(int user) {
		//getReference类似于load
		em.remove(em.getReference(Userinfo.class, user));
	}

	@Override
	public Userinfo get(int user) {
		return em.find(Userinfo.class, user);
	}

	@Override
	public void save(Userinfo user) {
		em.persist(user);
	}

	@Override
	public void update(Userinfo user) {
		em.merge(user);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Userinfo> getAll() {
		return em.createQuery("SELECT user FROM Userinfo user").getResultList();
	}

}

 

 

【JMS消息服务】

java消息服务用于实现两个客户端消息通信,但两客户端不是直接通过Socket或URL通信,而是通过中间服务器控制转发消息:

客户端一----消息---->Jboss服务器-----消息---->客户端二

通过服务器控制转发可以保证消息稳定、安全、效率。

 

消息传递系统的中心就是Message,一条Message由三个部分组成:

头(header)、属性(property)和主体(body)

 

Message接口有多种实现:StreamMessage流消息、MapMessage键值对消息、TextMessage文本字符串消息、ObjectMessage序列化对象消息和ByteMessage字节流消息。

 

JMS支持两种消息传递模型:点对点模型和发布/订阅模型

点对点模型指定了一条消息只能从一个客户端传递到一个接收方(Queue模式)

发布/订阅模型指定一条消息可以被多个订阅的客户接收(Topick模式)

 

 

【EJB的Webservice】

Web Services是由企业发布的完成其特定商务需求的在线应用服务,其他公司或应用软件能够通过Internet来访问并使用这项在线服务。

JavaEE为WebService提供了两种编程模型:EJB容器模型以及Web容器模型。

注意普通的EJB bean并非web service,这些bean只能被java代码调用,而实现web service标准的bean会被java以及其它编程语言调用。

其实EJB实现webservice非常简单,只需要配置一个注解,定义好相应属性即可。

@javax.jws.WebService( //让整个类成为webservice
		targetNamespace="http://com.ejb.webservice",  //指定命名空间名
		name="WebService",  //修改端点接口名
		serviceName="WebServiceImpl"  //服务的名称	
) 
@Stateless
@Remote(WebService.class)
public class WebServiceImpl implements WebService{
	//@WebService 如果只让某个方法成为webservice可以在该方法头设置
	@Override
	public List<User> findUsers() {
		List<User> lst = new ArrayList<User>();
		for(int i=0;i<10;i++){
			lst.add(new User(i, "微博"+i));
		}
		return lst;
	}

	@Override
	public String getName(String name) {
		return "name:"+name;
	}

	@Override
	public User getUser(int id) {
		return new User(id, "微博");
	}
	
}

 

你可能感兴趣的:(bean,Hibernate,webservice,jboss,ejb)