文档章节

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

Mr_Qi
 Mr_Qi
发布于 2016/10/08 22:21
字数 432
阅读 88
收藏 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
粉丝 267
博文 331
码字总数 346601
作品 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

没有更多内容

加载失败,请刷新页面

加载更多

下一页

python标准输入输出

input() 读取键盘输入 input() 函数从标准输入读入一行文本,默认的标准输入是键盘。 input 可以接收一个Python表达式作为输入,并将运算结果返回。 print()和format()输出 format()输出...

colinux
20分钟前
0
0
Python 核心编程 (全)

浅拷贝和深拷贝 1.浅拷贝:是对于一个对象的顶层拷贝,通俗的理解是:拷贝了引用,并没有拷贝内容。相当于把变量里面指向的一个地址给了另一个变量就是浅拷贝,而没有创建一个新的对象,如a...

代码打碟手
33分钟前
0
0
PHP 对象比数组省内存?错!数组比对象省内存?错!

刚刚一个群里有人引出了 PHP 数组和对象占用内存谁多谁少的问题。我想起之前我好像也测试过这个问题,和群里人说的对象比数组节省内存的结论相反,我得出的是数组比对象节省内存。 但今天,我...

宇润
49分钟前
1
0
memcached命令行及其用法

21.5 memcached命令行 创建数据 yum install -y telnet 利用telnet命令连接memcached数据库 telnet 127.0.0.1 11211 #写入数据 set key2 0 30 212STORED 这个是错误的示范,因为0 30 已经...

lyy549745
49分钟前
0
0
Maven私服

Maven私服 一、简介 当多人项目开发的时候,尤其聚合项目开发,项目和项目之间需要有依赖关系,通过maven私服,可以保存互相依赖的jar包,这样的话就可把多个项目整合到一起。 如下图: Inst...

星汉
52分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部