简化spring rmi服务端配置

我们在使用spring rmi实现服务间远程调用时,每一个普通的service要想导出成远程服务供其他服务调用,都需要在spring的配置文件中配置一个org.springframework.remoting.rmi.RmiServiceExporter类的bean。一般都采用下面这种配置方法:

     <bean name="serviceARmiExporter" class="org.springframework.remoting.rmi.RmiServiceExporter">
        <property name="service" ref="serviceA" />
        <property name="serviceName" value="serviceA" />
        <property name="serviceInterface" value="com.springrmi.service.IServiceA" />
        <property name="registryPort" value="${rmi.port}" />
    </bean>

    <bean name="serviceBRmiExporter" class="org.springframework.remoting.rmi.RmiServiceExporter">
        <property name="service" ref="serviceB" />
        <property name="serviceName" value="serviceB" />
        <property name="serviceInterface" value="com.springrmi.service.IServiceB" />
        <property name="registryPort" value="${rmi.port}" />
    </bean>

    。。。。。。。其他的远程服务配置

可以看到上面这样的配置太过臃肿,对于看过spring源码的人来说,一般都了解spring是先针对某个类来注册一个BeanDefinition,然后通过BeanDefinition来创建Bean实例,所以我们可以通过程序来批量创建这些RmiServiceExporter类的BeanDefinition,然后将这些BeanDefinition注册到spring容器中,最后由spring容器创建RmiServiceExporter实例供其他服务调用。

接下来我们来看看spring容器主要初始化方法,AbstractApplicationContext的refresh()方法。

// Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();

            }

从这个方法中可以看到,我们可以从三个地方可以介入到spring BeanDefinition的注册过程中,

1、继承某一个AbstractApplicationContext的子类,覆盖postProcessBeanFactory方法,在这个方法中批量注册RmiServiceExporter的BeanDefinition到容器中。

2、实现一个BeanFactoryPostProcessor接口,在该接口的postProcessBeanFactory方法中批量注册RmiServiceExporter BeanDefinition。

3、finishRefresh方法中,会触发ContextRefreshedEvent事件,我们可以针对该事件写一个ApplicationListener,也可以批量注册RmiServiceExporter BeanDefinition。

下面通过第一种方式实现下批量注册RmiServiceExporter BeanDefinition,其他两种方法大同小异。

(1)首先定义一个接口用于标识业务类需要导出成远程服务。

public interface RmiServiceExporterAutoRegistrar {

    // String getServiceInterface();

}

(2)编写两个普通的业务接口和实现类

public interface IUserService {
    User getOneUser();

    String addUser();

    String updateUser();
}

public interface IGroupService {

    String addGroup();

    String updateGroup();

    String deleteGroup();
}

@Service(value = "userService")
public class UserService implements IUserService,
        RmiServiceExporterAutoRegistrar
{

    private static final Log LOG = LogFactory.getLog(UserService.class);

    @Override
    public User getOneUser() {
        User user = new User();
        user.setAge(Integer.valueOf(1000));
        user.setEmail("sunwukong@qq.com");
        user.setNickname("孙悟空");
        user.setPassword("123456");
        user.setUsername("sunwukong");
        return user;
    }

    @Override
    public String addUser() {
        LOG.info("新增用户");
        return "已成功新增用户!";
    }

    @Override
    public String updateUser() {
        LOG.info("修改用户");
        return "已成功修改用户!";
    }
}

 

@Service(value = "groupService")
public class GroupService implements IGroupService,
        RmiServiceExporterAutoRegistrar
{

    private static final Log LOG = LogFactory.getLog(GroupService.class);

    @Override
    public String addGroup() {
        LOG.info("新增用户组!");
        return "已成功新增用户组!";
    }

    @Override
    public String updateGroup() {
        LOG.info("修改用户组!");
        return "已成功修改用户组!";
    }

    @Override
    public String deleteGroup() {
        LOG.info("删除用户组!");
        return "已成功删除用户组!";
    }

}

业务实现类一定要实现RmiServiceExporterAutoRegistrar,并且放在implements关键字后面的第二个接口。

(3)覆盖AbstractApplicationContext的postProcessBeanFactory方法。

public class MyAnnotationConfigApplicationContext extends
        AnnotationConfigApplicationContext {

    public MyAnnotationConfigApplicationContext() {
        super();
    }

    public MyAnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        super(annotatedClasses);
    }

    public MyAnnotationConfigApplicationContext(
            DefaultListableBeanFactory beanFactory) {
        super(beanFactory);
    }

    public MyAnnotationConfigApplicationContext(String... basePackages) {
        super(basePackages);
    }

    @Override
    protected void postProcessBeanFactory(
            ConfigurableListableBeanFactory beanFactory) {
        DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory) beanFactory;
        String[] autoRegisterBeanNameArr = listableBeanFactory
                .getBeanNamesForType(RmiServiceExporterAutoRegistrar.class);
        BeanDefinitionBuilder beanDefinitionBuilder = null;
        Class<?> tempBeanClass = null;
        for (String tempBeanName : autoRegisterBeanNameArr) {
            logger.info("auto registrar bean name>>>>>>>>>>>>>"
                    + tempBeanName);
            AbstractBeanDefinition tempBeanDefinition = (AbstractBeanDefinition) listableBeanFactory
                    .getBeanDefinition(tempBeanName);
            try {
                tempBeanClass = ClassUtils.forName(
                        tempBeanDefinition.getBeanClassName(),
                        ClassUtils.getDefaultClassLoader());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (LinkageError e) {
                e.printStackTrace();
            }

            beanDefinitionBuilder = BeanDefinitionBuilder
                    .rootBeanDefinition(RmiServiceExporter.class);
            beanDefinitionBuilder.addPropertyReference("service", tempBeanName);
            beanDefinitionBuilder.addPropertyValue("serviceName", tempBeanName);
            Class<?>[] interfaces = tempBeanClass.getInterfaces();
            String interfaceName = interfaces[0].getName();
            beanDefinitionBuilder.addPropertyValue("serviceInterface",
                    interfaceName);
            beanDefinitionBuilder.addPropertyValue("registryPort",
                    System.getProperty("RMI_PORT", "1099"));

            listableBeanFactory.registerBeanDefinition(tempBeanName
                    + "Exporter", beanDefinitionBuilder.getBeanDefinition());
        }
    }
}

(4)启动rmi服务端和客户端

//spring rmi服务端启动程序

public class RmiServiceStarter {

    public static void main(String[] args) {
                MyAnnotationConfigApplicationContext applicationContext = new MyAnnotationConfigApplicationContext(
                "org.yanfeilin.helloworld.spring.annotations.service");
    }
}

//spring rmi客户端调用程序

@Configuration
public class SpringRmiClient {

    private static final Log LOG = LogFactory.getLog(SpringRmiClient.class);

    @Bean(name = "userService")
    public RmiProxyFactoryBean userService() {
        RmiProxyFactoryBean userServiceProxy = new RmiProxyFactoryBean();
        userServiceProxy.setServiceUrl("rmi://localhost:1099/userService");
        userServiceProxy.setServiceInterface(IUserService.class);
        userServiceProxy.setRefreshStubOnConnectFailure(true);
        userServiceProxy.setLookupStubOnStartup(true);
        return userServiceProxy;
    }

    @Bean(name = "groupService")
    public RmiProxyFactoryBean groupService() {
        RmiProxyFactoryBean groupServiceProxy = new RmiProxyFactoryBean();
        groupServiceProxy.setServiceUrl("rmi://localhost:1099/groupService");
        groupServiceProxy.setServiceInterface(IGroupService.class);
        groupServiceProxy.setRefreshStubOnConnectFailure(true);
        groupServiceProxy.setLookupStubOnStartup(true);
        return groupServiceProxy;
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext clientApplicationContext = new AnnotationConfigApplicationContext(
                SpringRmiClient.class);

        IUserService userService = (IUserService) clientApplicationContext
                .getBean("userService");
        LOG.info(userService.addUser());
        LOG.info(userService.updateUser());

        IGroupService groupService = (IGroupService) clientApplicationContext
                .getBean("groupService");
        LOG.info(groupService.addGroup());
        LOG.info(groupService.updateGroup());
        LOG.info(groupService.deleteGroup());
    }
}

以上就是实现简化spring rmi服务端配置的方法,我们在使用spring其他组件(比如jms服务提供者配置)的时候,同样可以用这样的思路简化某些臃肿的配置。

Spring为各种远程访问技术提供集成工具类。Spring远程访问通过使用普通POJOs,能更容易的开发远程访问服务。目前,Spring远程访问的主要技术如下: 1. 远程调用RMI(Remote Method Invocation): 通过使用 RmiProxyFactoryBean 和 RmiServiceExporter,并且,Spring支持两个传统的RMI(使用 java.rmi.Remote接口和java.rmi.RemoteException)和通过RMI调用器实现的暴露远程调用(支持任何Java接口)。 2. Spring的HTTP调用器(Spring’s Http Invoker): Spring提供了一种特殊的允许通过HTTP进行Java串行化的远程调用策略,支持任意Java接口(就像RMI调用器)。相对应的支持类是 HttpInvokerProxyFactoryBean和 HttpInvokerServiceExporter。 3. Hessian: 通过 HessianProxyFactoryBean 和 HessianServiceExporter,可以使用Caucho提供的基于HTTP的轻量级二进制协议来透明地暴露服务。 4. Burlap: Burlap是Caucho的另外一个子项目,可以作为Hessian基于XML的替代方案。Spring提供了诸如 BurlapProxyFactoryBean 和 BurlapServiceExporter 的支持类。 5. JAX RPC: Spring通过JAX-RPC为远程Web服务提供支持(J2EE 1.4's web service API)。 6. JAX-WS:Spring通过JAX-WS为远程Web服务提供支持(the successor of JAX-RPC, as introduced in Java EE 5 and Java 6)。 7. JMS:远程访问通过类JmsInvokerServiceExporter和JmsInvokerProxyFactoryBean使用JMS的底层协议实现。 二. 远程访问------RMI 1. RMI远程访问基本流程 1). 服务端定义远程访问接口; 2). 服务端通过RmiServiceExporter暴露服务接口 3). 客户端定义与服务端已暴露的相同接口 4). 客户端通过RmiProxyFactoryBean调用服务接口
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值