文档章节

把大象放进冰箱--spring自动扫描并发布rmi

Mr_Qi
 Mr_Qi
发布于 2016/10/08 22:21
字数 432
阅读 90
收藏 3

对于需要暴露大量rmi的应用来说,每次新增加一个service都需要手写一段xml也是蛮累的……

偷懒的程序员想到了如下的办法

利用component-scan发布service同时发布rmi呢?

说做就做

把大象放进冰箱三步骤

  1. 打开冰箱门
    首先需要把所有的@service注解扫描,设置BeanDefinition的相关属性包括service,serviceName等
  2. 把大象塞进冰箱
    将BeanDefinition注册到spring容器中
  3. 关上冰箱门
    初始化对应的BeanDefinition


    具体代码如下

    /**
     * Created by qixiaobo on 2016/10/8.
     */
    public class PublishRmiBean implements ApplicationContextAware {
        private Logger logger = Logger.getLogger(PublishRmiBean.class);
        private String basePkg;
        private ApplicationContext context;
        private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        @Value("${erp.rmi.base.port}")
        private int port;
     
        private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
     
        private static final List<TypeFilter> includeFilters = new LinkedList<>();
        private static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
     
     
        public String getBasePkg() {
            return basePkg;
        }
     
        public void setBasePkg(String basePkg) {
            this.basePkg = basePkg;
        }
     
        static {
            includeFilters.add(new AnnotationTypeFilter(Service.class));
        }
     
        @PostConstruct
        public void init() throws IOException {
            assert (basePkg != null);
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    resolveBasePackage(basePkg) + "/" + DEFAULT_RESOURCE_PATTERN;
            Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
            for (Resource resource : resources) {
                {
                    try {
                        MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
                        if (isCandidateComponent(metadataReader)) {
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            sbd.setResource(resource);
                            sbd.setSource(resource);
                            if (isCandidateComponent(sbd)) {
                                String clazzName = sbd.getBeanClassName();
                                Class clazz = null;
                                if (sbd.hasBeanClass()) {
                                    clazz = sbd.getBeanClass();
                                } else {
                                    clazz = Class.forName(clazzName);
                                }
                                String beanName = RmiNameGenerator.getBeanName(clazzName.substring(clazzName.lastIndexOf(".") + 1));
                                registerRmi(clazz, beanName);
                            }
                        }
                    } catch (Throwable e) {
                        logger.error(e);
                    }
                }
            }
            try {
                context.getBeansOfType(RmiServiceExporter.class);
            } catch (Exception ex) {
                logger.error(ex);
            }
     
        }
     
        private void registerRmi(Class clazz, String beanName) {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(RmiServiceExporter.class);
            if (clazz.getInterfaces().length == 0) {
                logger.warn("skip publish rmi:" + beanName + " because no interface found!");
                return;
            }
            builder.addPropertyValue("serviceInterface", clazz.getInterfaces()[0]);
            builder.addPropertyValue("serviceName", beanName);
            builder.addPropertyValue("registryPort", port);
            builder.addPropertyReference("remoteInvocationExecutor", "clientInfoRemoteInvocationExecutor");
            builder.addPropertyValue("service", context.getBean(clazz));
            builder.setLazyInit(false);
            getBeanDefinitionRegistry().registerBeanDefinition(beanName + "Exporter", builder.getRawBeanDefinition());
            logger.info("publish rmi:" + beanName);
        }
     
     
        private BeanDefinitionRegistry getBeanDefinitionRegistry() {
            return (BeanDefinitionRegistry) ((XmlWebApplicationContext) context).getBeanFactory();
        }
     
        private boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
            for (TypeFilter tf : includeFilters) {
                if (tf.match(metadataReader, this.metadataReaderFactory)) {
                    return true;
                }
            }
            return false;
        }
     
        private boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
            return (beanDefinition.getMetadata().isConcrete() && beanDefinition.getMetadata().isIndependent());
        }
     
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.context = applicationContext;
        }
     
        private String resolveBasePackage(String basePackage) {
            return ClassUtils.convertClassNameToResourcePath(basePackage);
        }
     
    }

    在spring的xml中注册如下

    <bean class="com.xxx.PublishRmiBean" >
        <property name="basePkg" value="com.xxx.service.*.impl"/>
    </bean>

     

© 著作权归作者所有

共有 人打赏支持
Mr_Qi

Mr_Qi

粉丝 280
博文 359
码字总数 369228
作品 0
南京
程序员
私信 提问
大象放进冰箱 - 建造者模式

设计模式 - 建造者模式 [toc] 简介 Builder:又名生产器模式 将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 精髓:顺序 组成角色 builder:给出一个抽象接口...

草帽行者
2016/05/10
41
0
PHP 面向对象实例:获取数据库用户数据

我们使用面向过程的方式和面向对象的方式分别写几个程序,理解面向对象编程带来的优势。 数据库使用mysql 数据库, 数据库结构和数据如下图所示。 先写一个数据库配置文件如下: db_config....

BENNEE
2011/03/22
0
0
[转]Spring MVC 3.0.5+Spring 3.0.5+MyBatis3.0.4全注...

第一章 Spring更新到3.0之后,其MVC框架加入了一个非常不错的东西——那就是REST。它的开放式特性,与Spring的无缝集成,以及Spring框架的优秀表现,使得现在很多公司将其作为新的系统开发框...

robinjiang
2012/10/18
0
1
springmvc 项目完整示例05 日志 --log4j整合 配置 log4j属性设置 log4j 配置文件 log4j应用

log4j 就是log for java嘛,老外都喜欢这样子,比如那个I18n ---internationalization 不就是i和n之间有18个字母... http://logging.apache.org/log4j/2.x/ 直接入正题 他是一个强大的日止功能...

noteless
2016/02/24
0
0
通过HTML5的getUserMedia实现拍照功能

参考HTML5Rocks的这篇文章实现的一个简单的例子。 思路如下: 1. 把冰箱门打开 2. 把大象放进冰箱里 3. 把冰箱门关上 好了不开玩笑了,其实思路是: 1. 通过getUserMedia调用设备的摄像头(电...

PortWatcher
2013/12/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Ubuntu16.04下安装docker

[TOC] 本文开发环境为Ubuntu 16.04 LTS 64位系统,通过apt的docker官方源安装最新的Docker CE(Community Edition),即Docker社区版,是开发人员和小型团队的理想选择。 1. 开始安装 1.1 由于...

豫华商
7分钟前
0
0
使用XShell工具密钥认证登录Linux系统

如果你是一名Linux运维,那么Linux服务器的系统安全问题,可能是你要考虑的,而系统登录方式有两种,密码和密钥。哪一种更加安全呢? 无疑是后者! 这里我为大家分享用Xshell利器使用密钥的方...

dragon_tech
19分钟前
0
0
day178-2018-12-15-英语流利阅读-待学习

“真蛛奶茶”了解一下?蜘蛛也会产奶了 Lala 2018-12-15 1.今日导读 “蛋白质含量是牛奶的 4 倍,并有着更低的脂肪和含糖量”,听起来诱人又美味的并不是羊奶或豆奶,而是你可能打死都想不到...

飞鱼说编程
24分钟前
6
0
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents

场景重现 npm install --verbose 安装依赖的时,出现如下警告 强迫症患者表示不能接受 npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\fsevents):npm WARN......

taadis
29分钟前
1
0
OSChina 周六乱弹 —— 你一口我一口多咬一口是小狗

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @达尔文 :分享Roy Orbison的单曲《She's a Mystery to Me》 《She's a Mystery to Me》- Roy Orbison 手机党少年们想听歌,请使劲儿戳(这里...

小小编辑
今天
306
6

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部