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


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

  • Spring
  • rmi categories: spring date: 2016-09-25 18:18:54

对于需要暴露大量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>
复制代码
 
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值