Camel查找组件方式

在前面的Camel示例中,路由的构建中调用了RouteBuilder的from,to方法,该方法的参数为一个uri字符串。Camel运行是由组件(component)进行组织的,而我们传递的参数为一字符串,所以Camel要根据这个uri字符串来查找到对应的组件,即要维护uri到组件之间的映射关系。

查找组件的过程是调用DefaultCamelContext中的getComponent(String name)方法来完成的,至于该方法什么时候被调用,调用该方法真正目的是什么在后面讲解Camel运行原理时说明,为什么要先要讲清楚组件的查找过程,也是为讲解Camel运行原理做准备的。下面是getComponent(String name)方法源码:

public Component getComponent(String name) {
	//调用重载方法
    return getComponent(name, autoCreateComponents);
}
public Component getComponent(String name, boolean autoCreateComponents) {
    synchronized (components) {
    	//先根据名称在components这个Map中查找
        Component component = components.get(name);
        //如果没有找到并且要自动创建组件
        if (component == null && autoCreateComponents) {
            try {
                if (log.isDebugEnabled()) {
                    log.debug("Using ComponentResolver: {} to resolve component with name: {}", getComponentResolver(), name);
                }
                //获取组件解析器根据组件名称进行解析,返回组件
                component = getComponentResolver().resolveComponent(name, this);
                if (component != null) {
                    addComponent(name, component);
                    if (isStarted() || isStarting()) {
                        // 组件返回后,如果是实现了Service接口,则调用startService方法
                        if (component instanceof Service) {
                            startService((Service)component);
                        }
                    }
                }
            } catch (Exception e) {
                throw new RuntimeCamelException("Cannot auto create component: " + name, e);
            }
        }
        log.trace("getComponent({}) -> {}", name, component);
        return component;
    }
}

在上面的方法中使用了synchronized关键字,当然这是在进行线程同步,因为CamelContext中可以运行多个路由,而CamelContext的是单例的所以,components这个成员变量就存在多个线程并发访问的问题,加上synchronized关键字就是为了避免重复创建组件。

现在就看resolveComponent方法了,下面是DefaultComponentResolver的resolveComponent方法源码:

public Component resolveComponent(String name, CamelContext context) {
    Object bean = null;
    try {
    	//先在注册表中进行查找
        bean = context.getRegistry().lookupByName(name);
        getLog().debug("Found component: {} in registry: {}", name, bean);
    } catch (Exception e) {
        getLog().debug("Ignored error looking up bean: " + name, e);
    }
    if (bean != null) {
        if (bean instanceof Component) {//如果在注册表中找到了组件则直接返回
            return (Component) bean;
        } else {
            //如果不是Component类型则尝试进行转化
            Component component = CamelContextHelper.convertTo(context, Component.class, bean);
            if (component != null) {
                return component;
            }
        }
        // we do not throw the exception here and try to auto create a component
    }

    // not in registry then use component factory
    Class<?> type;
    try {//注册表中没有找到则调用findComponent方法
        type = findComponent(name, context);
        if (type == null) {
            // not found
            return null;
        }
    } catch (NoFactoryAvailableException e) {
        return null;
    } catch (Exception e) {
        throw new IllegalArgumentException("Invalid URI, no Component registered for scheme: " + name, e);
    }

    if (getLog().isDebugEnabled()) {
        getLog().debug("Found component: {} via type: {} via: {}{}", new Object[]{name, type.getName(), factoryFinder.getResourcePath(), name});
    }

    //根据获取的组件Class类型,利用反射创建出其实例
    if (Component.class.isAssignableFrom(type)) {
        return (Component) context.getInjector().newInstance(type);
    } else {
        throw new IllegalArgumentException("Type is not a Component implementation. Found: " + type.getName());
    }
}

在上面的方法中,查找组件的方法就有了两种,一是在注册表中进行查找,找到了并且是Component类型实例则直接返回,如果不是则尝试进行转化;二是调用findComponent方法继续查找。下面是findComponent方法源码:

private Class<?> findComponent(String name, CamelContext context) throws ClassNotFoundException, IOException {
    if (factoryFinder == null) {
        factoryFinder = context.getFactoryFinder(RESOURCE_PATH);
    }
    return factoryFinder.findClass(name);
}

首先根据资源路径获取出一个FactoryFinder实例,再调用其findClass方法,其中RESOURCE_PATH为一常量,值为META-INF/services/org/apache/camel/component/

一看,就知道这是要根据在类路径的某一特定路径下的资源进行查找。获取FactoryFinder实例过程很简单就不讲了,FactoryFinder是一接口,返回的真实类型为DefaultFactoryFinder,下面是DefaultFactoryFinder的findClass方法源码:

public Class<?> findClass(String key) throws ClassNotFoundException, IOException {
    return findClass(key, null);
}
public Class<?> findClass(String key, String propertyPrefix) throws ClassNotFoundException, IOException {
	//参数key就是组件名称,propertyPrefix为null,所以最后prefix就为一空字符串
    String prefix = propertyPrefix != null ? propertyPrefix : "";
    //重classMap中进行查找
    Class<?> clazz = classMap.get(prefix + key);
    if (clazz == null) {//没有找到则调用newInstance方法
        clazz = newInstance(doFindFactoryProperties(key), prefix);
        if (clazz != null) {//放入calssMap中缓存起来
            classMap.put(prefix + key, clazz);
        }
    }
    return clazz;
}

newInstance方法需要一个Properties对象,该对象中就旋转了组件名称与组件类型(Calss)的映射关系,下面是doFindFactoryProperties方法源码:

private Properties doFindFactoryProperties(String key) throws IOException {
	//path就是获取FactoryFinder时传入的资源路径,即META-INF/services/org/apache/camel/component/
	//key就是组件名称
    String uri = path + key;
    //根据uri把资源流返回,所以就是在类路径META-INF/services/org/apache/camel/component/下的一个名为key的文件(其实就是一properits文件)读取出来
    InputStream in = classResolver.loadResourceAsStream(uri);
    if (in == null) {
        throw new NoFactoryAvailableException(uri);
    }

    // lets load the file
    BufferedInputStream reader = null;
    try {
        reader = IOHelper.buffered(in);
        Properties properties = new Properties();
        //文件内容读取properties文件中,包含了组件名称与组件类型映射关系
        properties.load(reader);
        return properties;
    } finally {
        IOHelper.close(reader, key, null);
        IOHelper.close(in, key, null);
    }
}

下面是newInstance方法源码:

private Class<?> newInstance(Properties properties, String propertyPrefix) throws ClassNotFoundException, IOException {
    String className = properties.getProperty(propertyPrefix + "class");
    if (className == null) {
        throw new IOException("Expected property is missing: " + propertyPrefix + "class");
    }

    Class<?> clazz = classResolver.resolveClass(className);
    if (clazz == null) {
        throw new ClassNotFoundException(className);
    }
    return clazz;
}

该方法很简单就是获取key为class的值出来,该值就为组件类型。

根据上述,获取组件实例的途径有两种:

a.在注册表中进行查找

b.从在类路径META-INF/services/org/apache/camel/component/下与组件名称同名的一个properties文件中获取

这两种途径在查找到组件后都会进行缓存,以免重复查找。

至此,根据uri解析出组件名称,再由组件名称获取到组件实例的过程应该就很清楚了,至于查找组件到底有什么作用,在什么时候被调用,下次再讲解。

时间: 2024-10-20 11:08:25

Camel查找组件方式的相关文章

ExtJs window(三)添加子组件,查找组件

一.通过items添加子组件 1.new Ext.button.Button创建组件:2.也可以通过通过别名xtype创建组件 二.查找组件 1.组件都有up,down方法,表示向上.向下查找,需要参数为组件xtype或者选择器  alert(btn.up('window').title); 2.最常用的查找方式 alert(Ext.getCmp('mywin').title); Ext.onReady(function(){ //在组件上,添加子组件:并进行针对组件的查找等操作 //通过ite

通过SSIS的“查找”组件进行不同数据源之间数据的合并操作

原文:通过SSIS的"查找"组件进行不同数据源之间数据的合并操作 为了协助开发还原生产环境中的某些bug,需要将将生产环境的某些特定表数据导入到测试环境做测试,之前一直都是暴力地truncate测试环境的表,然后用SSIS将生产环境对应的整张表数据导入测试环境,简便快捷后来开发提出来,保留测试环境已有的数据,只同步差异的数据(根据主键),于是就尝试使用SSIS中的“查找”组件进行不同服务器之间的“存在则更新,不存在则插入”数据合并操作,实际操作的时候只执行插入操作,达到同步数据的目的.

SSIS 查找 组件

通过SSIS的“查找”组件进行不同数据源之间数据的合并操作 为了协助开发还原生产环境中的某些bug,需要将将生产环境的某些特定表数据导入到测试环境做测试,之前一直都是暴力地truncate测试环境的表,然后用SSIS将生产环境对应的整张表数据导入测试环境,简便快捷后来开发提出来,保留测试环境已有的数据,只同步差异的数据(根据主键),于是就尝试使用SSIS中的“查找”组件进行不同服务器之间的“存在则更新,不存在则插入”数据合并操作,实际操作的时候只执行插入操作,达到同步数据的目的. 尝试之后觉得还

慕课网实战—《用组件方式开发 Web App全站 》笔记五-折线图组件开发

运用HTML5.CSS3.JS流行技术,采用组件式开发模式,开发Web App全站!技术大牛带你统统拿下不同类型的HTML5动态数据报告! <用组件方式开发 Web App全站 > 折现图绘制大致步骤 折线图画布 JavaScript CSS 折线图绘制网格线 // 水平网格线 100份 -> 10份 var step = 10; ctx.beginPath(); ctx.lineWidth = 1; ctx.strokeStyle = '#AAAAAA'; window.ctx = c

慕课网实战—《用组件方式开发 Web App全站 》笔记七-饼图和环图组件开发

运用HTML5.CSS3.JS流行技术,采用组件式开发模式,开发Web App全站!技术大牛带你统统拿下不同类型的HTML5动态数据报告! <用组件方式开发 Web App全站 > 饼图开发(绘制饼图准备) 饼图实现原理 饼图开发(绘制饼图) 代码 /* 饼图组件对象 */ var H5ComponentPie =function ( name, cfg ) { var component = new H5ComponentBase( name ,cfg ); // 绘制网格线 - 背景层 v

慕课网实战—《用组件方式开发 Web App全站 》笔记四-柱状图组件开发

运用HTML5.CSS3.JS流行技术,采用组件式开发模式,开发Web App全站!技术大牛带你统统拿下不同类型的HTML5动态数据报告! <用组件方式开发 Web App全站 > 柱图开发思路 水平柱图开发(HTML的DOM搭建) ???? ???? 水平柱图开发(CSS样式编写) /* 柱状组件样式 */ .h5_component_bar{ } .h5_component_bar .line{ height: 15px; font-size: 12px; line-height: 15p

《开源框架那点事儿23》:采用TinyDB组件方式开发

采用TinyDB组件方式开发 步骤 Icon 前文介绍四则运算的流程编程开发时,说过流程编排在开发重复功能时,可以利用已有的组件库快速开发.对于开发人员而言只需要简单配置流程就可以完成工作了. 开发增删改查的组件接口.本来这部分很花费时间,如果采用组件复用的话,就可以实现一次开发,终生受益. 配置curd.beans.xml和tinydb.xml. 使用流程编辑器定制组件流程curd.pageflow. 修改页面文件:list.page和operate.page,使之符合流程方式调用. 修改布局

《开源框架那点事儿23》:採用TinyDB组件方式开发

採用TinyDB组件方式开发 步骤 Icon 前文介绍四则运算的流程编程开发时,说过流程编排在开发反复功能时.能够利用已有的组件库高速开发.对于开发者而言仅仅须要简单配置流程就能够完毕工作了.开发增删改查的组件接口.本来这部分非常花费时间,假设採用组件复用的话,就能够实现一次开发,终生受益. 配置curd.beans.xml和tinydb.xml. 使用流程编辑器定制组件流程curd.pageflow. 改动页面文件:list.page和operate.page.使之符合流程方式调用. 改动布局

慕课网实战—《用组件方式开发 Web App全站 》笔记二

运用HTML5.CSS3.JS流行技术,采用组件式开发模式,开发Web App全站!技术大牛带你统统拿下不同类型的HTML5动态数据报告! <用组件方式开发 Web App全站 > 项目JS类开发 静态页思路验证 jQuery全屏滚动插件fullPage.js ??使用参考:Fullpage入门指南 组件切换,入场,出场动画 ???? DOM事件循环传播-无限循环 ??使用return false;或者triggerHander()方法阻止事件向上传播. 相关代码 HTML <body&