前言
目前笔者所在的公司生产系统的后台就是采用的EJB,但是我一直理解ejb是一种类似tomcat的前台服务器,就这样认为了好几年,直到最近准备给新员工培训,在准备培训材料的时候,我才认识到自己的理解是不对的。那么ejb到底是什么?
什么是EJB?
官方的解释可以参考百度百科:baike.baidu.com/item/EJB/14…
下面是我自己对ejb的理解:
ejb可以认为是一个自带通信功能的框架,既然是框架,那就和Spring、mybatis这类东西是一个意思,只是使用框架的场景侧重点不同。ejb天然支持分布式,可以支持跨JVM通信。但是和一般框架不同的是,ejb需要依赖容器,这个有点不太好理解。比如普通的使用spring实现的WEB应用程序,部署的时候需要部署到tomcat或者jetty等WEB容器。那么EJB也需要部署到相应的例如JBoss、Weblogic等容器上,因为EJB底层的对象管理不是靠自身维护的,而是依赖容器去管理的。还有EJB的通信功能,底层也是依赖于容器实现的的RMI协议来实现的。因此EJB必须依赖于容器。
既然说到EJB的通信能力,那么可以理解为EJB容器已经实现了一个类似RPC协议的通信功能,并且该功能支持自动序列化和反序列化,这样使用者在使用时,就可以利用EJB容器来通过对象直接进行通信了。这也是EJB可以支持远程方法调用的原理。
EJB的使用
由于公司使用的是自研的开发框架,很多底层功能都进行了封装,业务开发者在框架进行开发时很少去关注底层的实现原理,比如开发一个界面,前端采用的是拖拽式的代码生成,而后端也是类似的操作就可以生成绝大部分和业务无关的配置或代码,而开发者只需关注业务逻辑的实现即可。 那么ejb到底是如何运作的? 通过百度百科的解释,大概可以理解为EJB其实就是对RMI的一个封装。
下面是一个RMI的demo
服务端:
package com.cz.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* @program: Reids
* @description: 定义一个接口实现RMI的提供的接口
* @author: Cheng Zhi
* @create: 2023-06-09 09:47
**/
public interface UserService extends Remote {
public String sayHello(String username) throws RemoteException;
}
package com.cz.rmi;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* @program: Reids
* @description: 服务端实现自己的业务逻辑
* @author: Cheng Zhi
* @create: 2023-06-09 09:50
**/
public class UserServiceImpl extends UnicastRemoteObject implements UserService {
protected UserServiceImpl() throws RemoteException {
}
@Override
public String sayHello(String username) throws RemoteException {
return "TEST JAVA RMI " + username;
}
}
package com.cz.rmi;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
/**
* @program: Reids
* @description: 绑定url和端口发布接口服务
* @author: Cheng Zhi
* @create: 2023-06-09 09:51
**/
public class JdkMainServer {
public static void main(String[] args) {
try {
UserService userServer = new UserServiceImpl();
LocateRegistry.createRegistry(8080);
Naming.bind("rmi://localhost:8080/UserService", userServer);
System.out.println("server running......");
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户端:
package com.cz.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* @program: Reids
* @description: 客户端要实现和服务端一样的接口,注意包名也要一致。否则会提示no security manager: RMI class loader disabled异常
* @author: Cheng Zhi
* @create: 2023-06-09 09:47
**/
public interface UserService extends Remote {
public String sayHello(String username) throws RemoteException;
}
package com.cz.rmi;
import java.rmi.Naming;
/**
* @program: Reids
* @description: 客户端远程调用服务端方法
* @author: Cheng Zhi
* @create: 2023-06-09 09:52
**/
public class JdkMainClient {
public static void main(String[] args) {
try {
UserService userService = (UserService) Naming.lookup("rmi://localhost:8080/UserService");
System.out.println(userService.sayHello("test"));
}catch (Exception e) {
e.printStackTrace();
}
}
}
结果: 远程调用成功
通过上面的案例可以看出使用RMI通信的客户端和服务端必须要拥有同名的接口(UserService)。查看了一下公司的代码其核心原理也是类似的,只不过它自动生成了Remote接口。