编程语言
首页 > 编程语言> > spring – Camel的BridgePropertyPlaceholderConfigurer在使用Java配置时不起作用

spring – Camel的BridgePropertyPlaceholderConfigurer在使用Java配置时不起作用

作者:互联网

我正在使用Spring Java配置并使用一些Camel路由编写控制台应用程序.我的应用程序中有几个属性源,因此我使用了两个PropertyPlaceholderConfigurers:

@Configuration
@Import(CamelConfig.class)
@ComponentScan(basePackageClasses = {App.class})
public class Config
{
  final static String ENV = System.getProperty( "ENV" );

  @Bean
  public static BridgePropertyPlaceholderConfigurer properties()
  {
    final BridgePropertyPlaceholderConfigurer result = new BridgePropertyPlaceholderConfigurer();

    result.setOrder( 0 );
    result.setIgnoreUnresolvablePlaceholders( true );
    result.setLocations( new ClassPathResource( "a/b/c/environments/base.properties" ),
      new ClassPathResource( "a/b/c/environments/" + ENV + "/env.properties" ) );

    return result;
  }

  @Bean
  public static BridgePropertyPlaceholderConfigurer dlqAppProperties()
  {
    final YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
    final BridgePropertyPlaceholderConfigurer result = new BridgePropertyPlaceholderConfigurer();

    yaml.setResources( new ClassPathResource( "app.yaml" ) );
    result.setOrder( 1 );
    result.setIgnoreUnresolvablePlaceholders( true );
    result.setProperties( yaml.getObject() );

    return result;
  }
}

根据this doc,我使用BridgePropertyPlaceholderConfigurer类在Camel中使Spring属性可用.它的配置也很简单:

@Configuration
public class CamelConfig extends SingleRouteCamelConfiguration
{
  @Override
  protected CamelContext createCamelContext() throws Exception
  {
    final SpringCamelContext result = new SpringCamelContext( getApplicationContext() );

    return result;
  }

  @Override
  protected void setupCamelContext( CamelContext camelContext ) throws Exception
  {
  }

  @Bean
  @Override
  public RouteBuilder route()
  {
    return (new Routes()).builder();
  }
}

测试路线(Scala DSL)也很简单:

class Routes extends RouteBuilder {
  "timer://{{foo}}?period=2s" ==> {
    process((exchange) => {
      exchange.getIn.setBody("test")
    })
    to("log:test")
  }
}

但是上下文不是从以下异常开始的:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'camelContext' defined in class path resource [a/b/c/config/CamelConfig.class]: Invocation of init method failed; nested exception is org.apache.camel.FailedToCreateRouteException: Failed to create route route1: Route(route1)[[From[timer://{{foo}}?period=2s]] -> [process[... because of Failed to resolve endpoint: timer://{{foo}}?period=2s due to: PropertiesComponent with name properties must be defined in CamelContext to support property placeholders.
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1566)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
  at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
  at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
  at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
  at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
  at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
  at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84)
  at a.b.c.App.main(App.java:13)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:606)
  at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: org.apache.camel.FailedToCreateRouteException: Failed to create route route1: Route(route1)[[From[timer://{{foo}}?period=2s]] -> [process[... because of Failed to resolve endpoint: timer://{{foo}}?period=2s due to: PropertiesComponent with name properties must be defined in CamelContext to support property placeholders.
  at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:182)
  at org.apache.camel.impl.DefaultCamelContext.startRoute(DefaultCamelContext.java:770)
  at org.apache.camel.impl.DefaultCamelContext.startRouteDefinitions(DefaultCamelContext.java:1914)
  at org.apache.camel.impl.DefaultCamelContext.doStartCamel(DefaultCamelContext.java:1670)
  at org.apache.camel.impl.DefaultCamelContext.doStart(DefaultCamelContext.java:1544)
  at org.apache.camel.spring.SpringCamelContext.doStart(SpringCamelContext.java:179)
  at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
  at org.apache.camel.impl.DefaultCamelContext.start(DefaultCamelContext.java:1512)
  at org.apache.camel.spring.SpringCamelContext.maybeStart(SpringCamelContext.java:228)
  at org.apache.camel.spring.SpringCamelContext.afterPropertiesSet(SpringCamelContext.java:104)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1625)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1562)
  ... 16 more
Caused by: org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: timer://{{foo}}?period=2s due to: PropertiesComponent with name properties must be defined in CamelContext to support property placeholders.
  at org.apache.camel.impl.DefaultCamelContext.getEndpoint(DefaultCamelContext.java:477)
  at org.apache.camel.util.CamelContextHelper.getMandatoryEndpoint(CamelContextHelper.java:63)
  at org.apache.camel.model.RouteDefinition.resolveEndpoint(RouteDefinition.java:192)
  at org.apache.camel.impl.DefaultRouteContext.resolveEndpoint(DefaultRouteContext.java:106)
  at org.apache.camel.impl.DefaultRouteContext.resolveEndpoint(DefaultRouteContext.java:112)
  at org.apache.camel.model.FromDefinition.resolveEndpoint(FromDefinition.java:72)
  at org.apache.camel.impl.DefaultRouteContext.getEndpoint(DefaultRouteContext.java:88)
  at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:890)
  at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:177)
  ... 27 more
Caused by: java.lang.IllegalArgumentException: PropertiesComponent with name properties must be defined in CamelContext to support property placeholders.
  at org.apache.camel.impl.DefaultCamelContext.resolvePropertyPlaceholders(DefaultCamelContext.java:1121)
  at org.apache.camel.impl.DefaultCamelContext.getEndpoint(DefaultCamelContext.java:475)
  ... 35 more

看起来这个桥不起作用(但我绝对可以在Spring中使用占位符).可能是什么问题?

解决方法:

看起来如果要使用BridgePropertyPlaceholderConfigurer,则需要使用CamelContextFactoryBean实例化Camel上下文.它有initPropertyPlaceholder方法:

@Override
protected void initPropertyPlaceholder() throws Exception {
    super.initPropertyPlaceholder();

    Map<String, BridgePropertyPlaceholderConfigurer> beans = applicationContext.getBeansOfType(BridgePropertyPlaceholderConfigurer.class);
    if (beans.size() == 1) {
        // setup properties component that uses this beans
        BridgePropertyPlaceholderConfigurer configurer = beans.values().iterator().next();
        String id = beans.keySet().iterator().next();
        LOG.info("Bridging Camel and Spring property placeholder configurer with id: " + id);

        // get properties component
        PropertiesComponent pc = getContext().getComponent("properties", PropertiesComponent.class);
        // replace existing resolver with us
        configurer.setResolver(pc.getPropertiesResolver());
        configurer.setParser(pc.getPropertiesParser());
        String ref = "ref:" + id;
        // use the bridge to handle the resolve and parsing
        pc.setPropertiesResolver(configurer);
        pc.setPropertiesParser(configurer);
        // and update locations to have our as ref first
        String[] locations = pc.getLocations();
        String[] updatedLocations;
        if (locations != null && locations.length > 0) {
            updatedLocations = new String[locations.length + 1];
            updatedLocations[0] = ref;
            System.arraycopy(locations, 0, updatedLocations, 1, locations.length);
        } else {
            updatedLocations = new String[]{ref};
        }
        pc.setLocations(updatedLocations);
    } else if (beans.size() > 1) {
        LOG.warn("Cannot bridge Camel and Spring property placeholders, as exact only 1 bean of type BridgePropertyPlaceholderConfigurer"
                + " must be defined, was {} beans defined.", beans.size());
    }
}

嗯,现在的问题是有两座桥梁,但这是另一个故事……

标签:spring-java-config,spring,apache-camel
来源: https://codeday.me/bug/20190824/1711461.html