EJB
EJB是sun的JavaEE服务器端组件模型,设计目标与核心应用是部署分布式应用程序。简单来说就是把已经编写好的程序(即:类)打包放在服务器上执行。凭借java跨平台的优势,用EJB技术部署的分布式系统可以不限于特定的平台。EJB (Enterprise JavaBean)是J2EE(javaEE)的一部分,定义了一个用于开发基于组件的企业多重应用程序的标准。其特点包括网络服务支持和核心开发工具(SDK)。 在J2EE里,Enterprise Java Beans(EJB)称为Java 企业Bean,是Java的核心代码,分别是会话Bean(Session Bean),实体Bean(Entity Bean)和消息驱动Bean(MessageDriven Bean)。在EJB3.0推出以后,实体Bean被单独分了出来,形成了新的规范JPA。
简单来说:就是目前spring IOC做的东西,上面也说了在EJB3.0推出以后,实体Bean被单独分了出来,形成了新的规范JPA。
可以认为这部分就是现在ssh框架的hibernate
认知以及概念
EJB 是为了”服务集群”和”企业级开发”而生,那么它设计架构呢?看下图
看上图我们,从左->右可以看到有俩客户端?这是什么鬼?这里解释一下:第一个客户端就是我们的客户,比如qq浏览器,客户端软件就是个启动好的tomcat,而A,B,C功能块就是EJB集群,看似这样的架构挺好的,能分解客户端的压力,实则不然,因为A,B,C功能块,他们都依赖同一个数据库,这样的分布式部署,数据库就是最大的瓶颈,看下图.
看到这里,你可能想到数据库可以部署多个,但是多个数据库实例之前如何数据共享?可能你还想到mysql的master/slave机制,但是master/slave,读写分离,还是一个master,那么如何多个master,数据又能共享,这是个不容易解决的问题,就是问题解决了,这个架构仅仅适合大型网站,中小型网站做这样的部署,成本太高.逐渐EJB也就淡出了视野,迎来的是Spring的春天!
EJB的原理
实则利用的Java的序列化技术以及RMI通信技术
什么是序列化
对象的序列化过程就是将对象状态转换成字节流和从字节流恢复对象。将对象状态转换成字节流之后,可以用java.io
包中的各种字节流类将其保存到文件中,或者通过网络连接将对象数据发送到另一个主机。上面的说法有点”八股”,我们不妨再用白话解释一下:对象的序列化就是将你程序中实例化的某个类的对象,比如,你自定一个类MyClass,或者任何一个类的对象,将它转换成字节数组,也就是说可以放到一个byte
数组中,这时候,你既然已经把一个对象放到了byte数组中,那么你当然就可以随便处置了它了,用得最多的就是把他发送到网络上远程的计算机上了,如下图.
简单来说:就是把JavaBean以字节流的形式存储下来,反序列就是从字节流转换为JavaBean的过程
RMI
谈到RMI必先说RPC
RPC 并不是一个纯粹的Java 概念,因为在Java 诞生之前就已经有了RPC 的这个概念,RPC是”Remote Procedure
Call”的缩写,也就是”远程过程调用”。在Java 之前的大多数编程语言,如,Fortran、C、COBOL
等等,都是过程性的语言,而不是面向对象的。所以,这些编程语言很自然地用过程表示工作,如,函数或子程序,让其在网络上另一台机器上执行。说白了,就是本地计算机调用远程计算机上的一个函数。
简单来说:就是本地调用远程服务器的一个函数(方法)的过程,称之为RPC(远程过程调用)
序列化+RPC=RMI
RMI 英文全称是”Remote Method Invocation”,它的中文名称是”远程方法调用”,它就是利用Java
对象序列化的机制实现分布式计算,实现远程类对象的实例化以及调用的方法。说的更清楚些,就是利用对象序列化来实现远程调用,也就是上面两个概念的结合体,利用这个方法来调用远程的类的时候,就不需要编写Socket
程序了,也不需要把对象进行序列化操作,直接调用就行了非常方便。远程方法调用是一种计算机之间对象互相调用对方函数,启动对方进程的一种机制,使用这种机制,某一台计算机上的对象在调用另外一台计算机上的方法时,使用的程序语法规则和在本地机上对象间的方法调用的语法规则一样。过程如下图
过程:本地序列化,把字节流通过RPC传输,到B服务器,B服务器反序列化数据,拿到请求参数,进行处理,返回结果
一个RMI的测试实例
Account.class
import java.io.Serializable;
public class Account implements Serializable, Cloneable {
private static final long serialVersionUID = -1858518369668584532L;
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
UserManagerInterface.class
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface UserManagerInterface extends Remote {
public String getUserName() throws RemoteException;
public Account getAdminAccount() throws RemoteException;
}
UserManagerImpl.class
import java.rmi.RemoteException;
public class UserManagerImpl implements UserManagerInterface {
public UserManagerImpl() throws RemoteException {
//super();
// TODO Auto-generated constructor stub
//UnicastRemoteObject.exportObject(this);
}
@Override
public String getUserName() throws RemoteException {
// TODO Auto-generated method stub
return "Tommy Lee";
}
@Override
public Account getAdminAccount() throws RemoteException {
// TODO Auto-generated method stub
Account account=new Account();
account.setUsername("admin");
account.setPassword("admin");
return account;
}
}
Server.class
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class Server {
public static void main(String[] args) throws AlreadyBoundException, RemoteException, MalformedURLException {
UserManagerImpl userManager = new UserManagerImpl();
UserManagerInterface userManagerI = (UserManagerInterface) UnicastRemoteObject.exportObject(userManager, 0);
// Bind the remote object's stub in the registry
Registry registry = LocateRegistry.createRegistry(2003);
registry.rebind("userManager", userManagerI);
System.out.println("server is ready");
}
}
Client.class
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
public static void main(String[] args) {
try {
Registry registry = LocateRegistry.getRegistry("localhost", 2003);
UserManagerInterface userManager = (UserManagerInterface) registry.lookup("userManager");
System.out.println(
"" + userManager.getAdminAccount().getUsername() + userManager.getAdminAccount().getPassword());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NotBoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
先启动server,再启动client即可,看下图也可以
一个RMI基本spring测试实例
服务端
public static void main(String[] args) throws RemoteException {
ApplicationContext ctx = new ClassPathXmlApplicationContext("rmi_client_context.xml");
IHello hs = (IHello) ctx.getBean("hello");
System.out.println(hs.hellWorld());
System.out.println(hs.sayHelloToSomeBody("美女"));
}
服务端xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="hello" class="com.zzy.test.test_spring_rmi.HelloImpl" />
<bean id="serviceExporter" class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="service" ref="hello" />
<!-- 定义服务名 -->
<property name="serviceName" value="hello" />
<property name="serviceInterface" value="com.zzy.test.test_spring_rmi.IHello" />
<property name="registryPort" value="8088" />
</bean>
</beans>
客户端spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="hello" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://localhost:8088/hello" />
<property name="serviceInterface" value="com.zzy.test.test_spring_rmi.IHello" />
</bean>
</beans>
POM配置文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zzy.test</groupId>
<artifactId>test-spring-rmi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>test-spring-rmi</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<springframework.version>4.2.1.RELEASE</springframework.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${springframework.version}</version>
</dependency>
</dependencies>
</project>
JSF
JavaServer Faces (JSF) 是一种用于构建Java Web 应用程序的标准框架(是Java Community Process 规定的JSR-127标准)。它提供了一种以组件为中心的用户界面(UI)构建方法,从而简化了Java服务器端应用程序的开发。由于由Java Community Process (JCP) 推动,属于Java EE 5中的技术规范,而受到了厂商的广泛支持。
体系结构
JSF 的主要优势之一就是它既是 Java Web 应用程序的用户界面标准又是严格遵循模型-视图-控制器 (MVC)
设计模式的框架。用户界面代码(视图)与应用程序数据和逻辑(模型)的清晰分离使 JSF
应用程序更易于管理。为了准备提供页面对应用程序数据访问的 JSF
上下文和防止对页面未授权或不正确的访问,所有与应用程序的用户交互均由一个前端FacesServlet(控制器)来处理。如下图
生命周期
FacesServlet 充当用户和 JSF 应用程序之间的纽带。它在明确限定的 JSF
生命周期(规定了用户请求之间的整个事件流)的范围内工作。 1.
当JSF页面上的一个事件发生时(比如:用户单击了一个按钮),事件通知通过HTTP发往服务器。服务器端使用FacesServet这个特殊的Servlet处理该通知。
2.
FacesServlet一接收到用户的请求就创建一个FacesContext对象(JSF上下文,它存放了应用程序的所有数据)。在处理过程中,主要修改的就是这个FaceContext对象。
3.
接着就是处理过程,处理器是一个叫作Lifecycle的对象。FacesServet把控制权转交给Lifecycle对象。该对象分6个阶段来处理FacesContext对象以生成响应,最后将响应发回客户端。
如何使用
简单的实例需要:faces-config.xml,login.jsp,LoginBean
faces-config.xml:描述了直接jsf客户传的参数,以及LoginBean的位置,web.xml启动要配置jsf启动
login.jsp:入口页面,填写参数
LoginBean:对参数处理返回
总结
a.EJB实现原理: 就是把原来放到客户端实现的代码放到服务器端,并依靠RMI进行通信。
b.RMI实现原理 :就是通过Java对象可序列化机制实现分布计算。
c.服务器集群: 就是通过RMI的通信,连接不同功能模块的服务器,以实现一个完整的功能。
d.JSF就是现在的spirng mvc,基本已经弃用,EJB就是现在的spring ioc 基本已经弃用
e.RMI一直在用,因为目前的比较流行微服务的技术,例如dubbo,Hessian,web service,还有搜索引擎elasticsearch都是用Java RMI进行通信的.