6.RPC框架的简单实现(服务发布-rmi协议)
2017-09-12 16:22
549 查看
通过rmi协议发布一个Java服务,使用java.rim包下的Naming.bind()方法即可,但是jdk默认rmi协议的实现需要接口类继承java.rmi.Remote,接口方法抛出RemoteException,实现类需要继承UnicastRemoteObject类比较繁琐。spring框架也提供了一套rmi协议的实现,参考spring帮助文档中Exposing services using RMI部分,spring对rmi协议的支持,不需要我们的业务接口去继承任何父类,业务代码更加简洁,RmiProtocol类的实现使用spring框架的相关工具类。
在第一篇中我们在maven配置文件中只添加了netty,jboss-marshalling,javassist三个依赖,现在需要增加上spring的依赖:
在第五篇中有Protocol接口的子类关系图,抽象类AbstractProxyProtocol实现了Protocol接口,RmiProtocol类和LdubboProtocol类又分别继承了该抽象类,这个结构也是跟dubbo源码中的Protocol接口类似的。好的,先看一下抽象类AbstractProxyProtocol的实现,代码如下:
在ServiceConfig类的export()方法中,调用
接下来看RmiProtocol类的实现代码:
doExport方法通过spring的RmiServiceExporter类实现服务的发布,首先创建一个RmiServiceExporter对象,设置端口、服务名称、服务接口、实现类,然后通过afterPropertiesSet()方法暴露服务,这个方法是不是有点熟悉?spring的RmiServiceExporter对象也是实现了InitializingBean接口的,当bean初始化后,执行该方法。doExport方法我们是用编码的方式自己调用的,spring帮助文档上面的例子是xml配置文件的方式,写在配置文件中时afterPropertiesSet()方法会自动调用的。
所以spring框架的rmi和dubbo框架发布rpc服务方式的入口是一样的,如果大家看一下dubbo框架的RmiProtocol类的源码,和上面我们自己写的代码是一样的。(doRefer引用服务的方法暂时先不实现)
到目前为止,我们先实现了一个rmi协议的服务发布,那么先来测试一下这个rpc框架的server端能否正常运行起来
把ldubbo项目运行maven的install命令打好jar包,看一下ldubbo项目的结构:(common和remote包先忽略)
新建一个接口ldubbo-api项目,创建一个测试用的接口类UserService:
定义一个User对象:
接口项目定义完了,然后创建一个新的的provider项目,在pom中把ldubbo和ldubbo-api两个项目引用进来,再增加下面两个slf4j的日志工具包
provider项目需要写一个UserService接口的实现,代码如下:
实现类有了,定义spring的配置文件applicationContext.xml:
applicationContext-ldubbo.xml文件:
实现类,spring配置文件都定义完了,最后需要一个启动类,创建一个Provider类:
在provider项目下还需定义一个log4j.xml的配置文件,如下:
运行Provider类,输出:
ldubbo框架可以发布rmi协议的服务了!
下一篇先不写LdubboProtocol如何使用netty做服务发布,先写rmi的服务引用
在第一篇中我们在maven配置文件中只添加了netty,jboss-marshalling,javassist三个依赖,现在需要增加上spring的依赖:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.6.RELEASE</version> </dependency>
在第五篇中有Protocol接口的子类关系图,抽象类AbstractProxyProtocol实现了Protocol接口,RmiProtocol类和LdubboProtocol类又分别继承了该抽象类,这个结构也是跟dubbo源码中的Protocol接口类似的。好的,先看一下抽象类AbstractProxyProtocol的实现,代码如下:
package com.lipenglong.ldubbo.rpc; import com.lipenglong.ldubbo.config.RegistryConfig; /** * AbstractProxyProtocol * <p/> * Created by lipenglong on 2017/7/27. */ public abstract class AbstractProxyProtocol implements Protocol { @Override public void export(Class interfaceClass, Object ref) { doExport(interfaceClass, ref); } @Override public <T> T refer(Class<?> interfaceClass, RegistryConfig registryConfig) { return doRefer(interfaceClass, registryConfig); } protected abstract void doExport(Class interfaceClass, Object ref); protected abstract <T> T doRefer(Class interfaceClass, RegistryConfig registryConfig); }
在ServiceConfig类的export()方法中,调用
protocol.export(interfaceClass, ref);方法,这里调用的就是AbstractProxyProtocol抽象类的export()方法,看上面的类代码,它又调用了抽象方法
doExport(interfaceClass, ref);这个抽象方法就是具体的协议类需要实现的方法。
接下来看RmiProtocol类的实现代码:
package com.lipenglong.ldubbo.rpc.protocol; import com.lipenglong.ldubbo.config.RegistryConfig; import com.lipenglong.ldubbo.rpc.AbstractProxyProtocol; import org.springframework.remoting.rmi.RmiProxyFactoryBean; import org.springframework.remoting.rmi.RmiServiceExporter; import java.rmi.RemoteException; /** * rmi协议通信类 * <p/> * Created by lipenglong on 2017/7/25. */ public class RmiProtocol extends AbstractProxyProtocol { private static final Integer DEFAULT_PORT = 1099; @Override protected void doExport(Class interfaceClass, Object ref) { RmiServiceExporter rmiServiceExporter = new RmiServiceExporter(); rmiServiceExporter.setRegistryPort(DEFAULT_PORT); rmiServiceExporter.setServiceName(interfaceClass.getName()); rmiServiceExporter.setServiceInterface(interfaceClass); rmiServiceExporter.setService(ref); try { rmiServiceExporter.afterPropertiesSet(); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected <T> T doRefer(Class interfaceClass, RegistryConfig registryConfig) { return null; } }
doExport方法通过spring的RmiServiceExporter类实现服务的发布,首先创建一个RmiServiceExporter对象,设置端口、服务名称、服务接口、实现类,然后通过afterPropertiesSet()方法暴露服务,这个方法是不是有点熟悉?spring的RmiServiceExporter对象也是实现了InitializingBean接口的,当bean初始化后,执行该方法。doExport方法我们是用编码的方式自己调用的,spring帮助文档上面的例子是xml配置文件的方式,写在配置文件中时afterPropertiesSet()方法会自动调用的。
所以spring框架的rmi和dubbo框架发布rpc服务方式的入口是一样的,如果大家看一下dubbo框架的RmiProtocol类的源码,和上面我们自己写的代码是一样的。(doRefer引用服务的方法暂时先不实现)
到目前为止,我们先实现了一个rmi协议的服务发布,那么先来测试一下这个rpc框架的server端能否正常运行起来
把ldubbo项目运行maven的install命令打好jar包,看一下ldubbo项目的结构:(common和remote包先忽略)
新建一个接口ldubbo-api项目,创建一个测试用的接口类UserService:
package com.lipenglong.ldubbo.api.service; import com.lipenglong.ldubbo.api.domain.User; import java.util.List; /** * 用户service接口类 * <p/> * Created by lipenglong on 2017/7/24. */ public interface UserService { List<User> queryUserList(); User getUserById(Long id); }
定义一个User对象:
package com.lipenglong.ldubbo.api.domain; import java.io.Serializable; /** * User * <p/> * Created by lipenglong on 2017/7/24. */ public class User implements Serializable { private static final long serialVersionUID = 2775326738215482673L; private Long id; private String name; private String password; private Integer role; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getRole() { return role; } public void setRole(Integer role) { this.role = role; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", password='" + password + '\'' + ", role=" + role + '}'; } }
接口项目定义完了,然后创建一个新的的provider项目,在pom中把ldubbo和ldubbo-api两个项目引用进来,再增加下面两个slf4j的日志工具包
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.9</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.9</version> </dependency>
provider项目需要写一个UserService接口的实现,代码如下:
package com.lipenglong.ldubbo.provider.service; import com.lipenglong.ldubbo.api.domain.User; import com.lipenglong.ldubbo.api.service.UserService; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; /** * UserServiceImpl * <p/> * Created by lipenglong on 2017/7/24. */ @Service(value = "userService") public class UserServiceImpl implements UserService { @Override public List<User> queryUserList() { List<User> result = new ArrayList<User>(); User user = new User(); user.setId(1L); user.setName("user1"); user.setPassword("****"); user.setRole(1); result.add(user); return result; } public User getUserById(Long id) { User user = new User(); user.setId(id); user.setName("user" + id); user.setPassword("****"); user.setRole(1); return user; } }
实现类有了,定义spring的配置文件applicationContext.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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--自动扫描注解--> <context:annotation-config/> <context:component-scan base-package="com.lipenglong.ldubbo.provider.service"/> <import resource="applicationContext-ldubbo.xml"/> </beans>
applicationContext-ldubbo.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:ldubbo="http://www.lipenglong.com/schema/ldubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.lipenglong.com/schema/ldubbo http://www.lipenglong.com/schema/ldubbo/ldubbo.xsd" default-lazy-init="true"> <ldubbo:protocol name="rmi"/> <ldubbo:service interface="com.lipenglong.ldubbo.api.service.UserService" ref="userService"/> </beans>
实现类,spring配置文件都定义完了,最后需要一个启动类,创建一个Provider类:
package com.lipenglong.ldubbo.provider; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.text.SimpleDateFormat; import java.util.Date; /** * ldubbo服务提供者启动类 * <p/> * Created by lipenglong on 2017/7/25. */ public class Provider { private static Log logger = LogFactory.getLog(Provider.class); public static void main(String[] args) throws Exception { new ClassPathXmlApplicationContext("applicationContext.xml"); logger.info(new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]").format(new Date()) + " ldubbo service server started!"); } }
在provider项目下还需定义一个log4j.xml的配置文件,如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d [%p] %c.%M(%L) | %m%n"/> </layout> </appender> <root> <level value="INFO"/> <appender-ref ref="CONSOLE"/> </root> </log4j:configuration>
运行Provider类,输出:
ldubbo框架可以发布rmi协议的服务了!
下一篇先不写LdubboProtocol如何使用netty做服务发布,先写rmi的服务引用
相关文章推荐
- 8.RPC框架的简单实现(服务发布-Ldubbo协议)
- 7.RPC框架的简单实现(服务引用-ReferenceBean实现与RMI协议)
- 9.RPC框架的简单实现(服务引用-Ldubbo协议)
- 4.RPC框架的简单实现(服务发布-ServiceBean实现)
- 利用Thrift和zk简单实现服务治理框架中的订阅发布机制
- 消息服务框架(MSF)应用实例之分布式事务三阶段提交协议的实现
- 构建插件式的应用程序框架(八)----视图服务的简单实现
- Java远程调用(二)实现一个简单的服务框架
- 简单的服务调用框架实现
- Java远程调用(二)实现一个简单的服务框架
- 分布式服务框架远程服务通讯简单实现
- 构建插件式的应用程序框架(八)----视图服务的简单实现
- 构建插件式的应用程序框架(八)-视图服务的简单实现
- Java实现的简单的WebService服务发布和Client调用例子
- Java实现一个简单的RPC框架(二) 协议
- 【远程调用框架】如何实现一个简单的RPC框架(三)优化一:利用动态代理改变用户服务调用方式
- 构建插件式的应用程序框架(八)----视图服务的简单实现
- 构建插件式的应用程序框架(八)----视图服务的简单实现
- [转]构建插件式的应用程序框架(八)----视图服务的简单实现
- 简单的RMI远程调用框架架实现