文档章节

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

Mr_Qi
 Mr_Qi
发布于 2016/10/08 22:21
字数 432
阅读 89
收藏 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

粉丝 276
博文 356
码字总数 365332
作品 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
Spring Boot 常用注解深入

@RestController和@RequestMapping 被称为一个构造型()注解。它为阅读代码的开发人员提供建议。对于Spring,该类扮演了一个特殊角色。它继承自@Controller注解。4.0之前的版本,spring MV...

小致dad
07/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

kubeadm部署kubernetes集群

一、环境要求 这里使用RHEL7.5 master、etcd:192.168.10.101,主机名:master node1:192.168.10.103,主机名:node1 node2:192.168.10.104,主机名:node2 所有机子能基于主机名通信,编辑...

人在艹木中
今天
2
0
Shell特殊符号总结以及cut,sort,wc,uniq,tee,tr,split命令

特殊符号总结一 * 任意个任意字符 ? 任意一个字符 # 注释字符 \ 脱义字符 | 管道符 # #号后的备注被忽略[root@centos01 ~]# ls a.txt # 备注 a.txt[root@centos01 ~]# a=1[root@centos01...

野雪球
今天
2
0
OSChina 周二乱弹 —— 程序员圣衣

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @达尔文:分享Skeeter Davis的单曲《The End of the World》 《The End of the World》- Skeeter Davis 手机党少年们想听歌,请使劲儿戳(这里...

小小编辑
今天
14
0
[ python import module ] 导入模块

import moudle_name ----> import module_name.py ---> import module_name.py文件路径 -----> sys.path (这里进行查找文件) # from app.web import Personimport app.web.Person as Pe......

_______-
昨天
5
0
Redis性能问题排查解决手册

一、性能相关的数据指标 通过Redis-cli命令行界面访问到Redis服务器,然后使用info命令获取所有与Redis服务相关的信息。通过这些信息来分析文章后面提到的一些性能指标。 nfo命令输出的数据可...

IT--小哥
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部