java - 在使用 Camel 的同时如何使用 Spring 加载属性?

标签 java json spring properties apache-camel

我有一个HelloWorld Java项目,它使用Camel获取Map,并以JSON格式打印其内容。 Map 当前具有硬编码值,但我真的想更改我的代码,以便它使用 Spring 将嵌套键、值对的sensor.properties 文件加载到此Map 中。

我编写的另一个 Java 项目仅使用 Spring,并且可以将sensor.properties 文件很好地加载到 Arraylist 对象中。

但是,当我尝试使用该项目中的代码在 HelloWorld 项目中加载sensor.properties 时,我收到以下带有 NPE 的 Camel 错误:

Returning Map
3310 [hello.world.request.timer] ERROR org.apache.camel.processor.DefaultErrorHandler      - Failed delivery for exchangeId: 4e984884-df7f-4b82-a977-f5cf4c311814. Exhausted after     delivery attempt: 1 caught: java.lang.NullPointerException
java.lang.NullPointerException
    at sample.SensorGenerator.getSensors(SensorGenerator.java:17)
    at sample.HelloWorld.returnMap(HelloWorld.java:22)
    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 org.apache.camel.component.bean.MethodInfo.invoke(MethodInfo.java:231)
    at org.apache.camel.component.bean.MethodInfo$1.proceed(MethodInfo.java:146)
    at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:138)
org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:67)
    at org.apache.camel.processor.DelegateProcessor.processNext(DelegateProcessor.java:53)
    at org.apache.camel.processor.DelegateProcessor.proceed(DelegateProcessor.java:82)
    at org.apache.camel.processor.interceptor.TraceInterceptor.process(TraceInterceptor.java:97)
    at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:67)
    at org.apache.camel.processor.RedeliveryErrorHandler.processExchange(RedeliveryErrorHandler.java:185)
 at org.apache.camel.processor.RedeliveryErrorHandler.processErrorHandler(RedeliveryErrorHandler.java:151)
    at     org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:89)
    at     org.apache.camel.processor.DefaultErrorHandler.process(DefaultErrorHandler.java:49)
    at org.apache.camel.processor.DefaultChannel.process(DefaultChannel.java:228)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:75)
    at     org.apache.camel.processor.UnitOfWorkProcessor.processNext(UnitOfWorkProcessor.java:70)
    at org.apache.camel.processor.DelegateProcessor.process(DelegateProcessor.java:48)
    at org.    apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:67)
    at     org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:102)
    at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:49)
    at java.util.TimerThread.mainLoop(Timer.java:555)
    at java.util.TimerThread.run(Timer.java:505)

我需要在 applicationContext.xml 中添加一些内容来告诉 Camel Spring 将加载我的sensor.properties 吗?我需要使用 http://camel.apache.org/springintegration.html 中指定的 Spring 集成组件吗?

这是我当前的 ApplicationContext.xml:

    <?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns:camel="http://camel.apache.org/schema/spring"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/util     http://www.springframework.org/schema/util/spring-util-3.0.xsd
        http://camel.apache.org/schema/spring     http://camel.apache.org/schema/spring/camel-spring.xsd
        http://www.springframework.org/schema/context     http://www.springframework.org/schema/context/spring-context.xsd">

<bean
    class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<context:component-scan base-package="sample" />
<context:annotation-config />

<camel:camelContext id="HelloWorldContext">

    <!-- Add Jackson library to render Java Map into JSON -->
    <camel:dataFormats>
      <camel:json id="jack" library="Jackson"/>
    </camel:dataFormats>

    <camel:route>
        <!-- sends a request to the hello world JMS queue every 10 seconds -->
        <camel:from
            uri="timer://hello.world.request.timer?fixedRate=true&amp;period=10000" />
        <camel:to uri="log:hello.world.request?level=INFO?showAll=true" />
        <camel:bean ref="helloWorld" />

        <!-- now print out the map in JSON format -->
        <camel:marshal ref ="jack"/>
        <camel:convertBodyTo type="java.lang.String" />
        <camel:log message="${body}"/> 

        <!-- now log the message -->
        <camel:to uri="log:hello.world.response?level=INFO?showAll=true" />

    </camel:route>

</camel:camelContext>

<bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent">
    <property name="configuration" ref="jmsConfig" />
</bean>

<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
    <property name="connectionFactory" ref="jmsConnectionFactory" />
    <property name="transacted" value="false" />
    <property name="concurrentConsumers" value="1" />
</bean>

<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
    <property name="brokerURL" value="vm://localhost" />
    <property name="redeliveryPolicy" ref="redeliveryPolicy" />
    <property name="prefetchPolicy" ref="prefetchPolicy" />
</bean>

<bean id="prefetchPolicy" class="org.apache.activemq.ActiveMQPrefetchPolicy">
    <property name="queuePrefetch" value="5" />
</bean>

<bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
    <property name="maximumRedeliveries" value="1" />
    <property name="backOffMultiplier" value="2" />
    <property name="initialRedeliveryDelay" value="2000" />
    <property name="useExponentialBackOff" value="true" />
</bean>

<!-- creates a java.util.Properties instance with values loaded from the supplied location -->
<util:properties id="sensorProperties" location="classpath:/sensor.properties"/>
    <bean class="sample.SensorGenerator">
        <property name="sourceProperties" ref="sensorProperties" />
    </bean>

</beans>

以下是我拥有的四个 Java 类(HelloWorldMain.java、HelloWorld.java、Sensor.java 和 SensorGenerator.Java):

更新:问题是我的 HelloWorld.java 中有一个构造函数调用 SensorGenerator,而不是使用 @Autowired 让 Spring 执行此操作。 Frederic 在底部的答案显示了旧代码构造函数。 @Autowired 注解在 HelloWorld.java 中如下所示:

HelloWorldMain.java:

package sample;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class HelloWorldMain {

    // define context to load properties with Spring

    public static void main(String[] args) throws Exception {

        AbstractApplicationContext context = new ClassPathXmlApplicationContext(
            "applicationContext.xml");
        Thread.currentThread().join();
    }

}      

HelloWorld.java:

package sample;

import java.util.*;

import org.apache.camel.Handler;
import org.springframework.stereotype.Service;


/**
 * POJO that returns Hello World string
 *
 */
@Service
public class HelloWorld {

    @AutoWired
    SensorGenerator sensorGenerator;

    @Handler
    public Map<?, ?> returnMap(){
        System.out.println();
        System.out.println("Returning Map");
        // get the map of Sensors
        Map<String,String> mySensorMap = sensorGenerator.getSensors();
        // print out the Sensors in the map on the console
        Set keys = mySensorMap.keySet();

        for (Iterator i = keys.iterator(); i.hasNext();) {
            String key = (String) i.next();
            String value = (String) mySensorMap.get(key);
            System.out.println("key= " + key + ", value= " + value);
        }
        return mySensorMap;
    }

}

Sensor.java(定义了我从sensor.properties中读取的字段):

package sample;

public class Sensor {

    private String make;
    private String makeDataType;
    private String model;
    private String modelDataType;
    private String serialNumber;
    private String serialNumberDataType;
    private String sensorType;
    private String sensorTypeDataType;

    // getters and setters
    public String getMake() {
        return make;
    }
    public void setMake(String make) {
        this.make = make;
    }
    public String getMakeDataType() {
        return makeDataType;
    }
    public void setMakeDataType(String makeDataType) {
        this.makeDataType = makeDataType;
    }
    public String getModel() {
        return model;
    }
    public void setModel(String model) {
        this.model = model;
    }
    public String getModelDataType() {
        return modelDataType;
    }
    public void setModelDataType(String modelDataType) {
        this.modelDataType = modelDataType;
    }
    public String getSerialNumber() {
        return serialNumber;
    }
    public void setSerialNumber(String serialNumber) {
        this.serialNumber = serialNumber;
    }
    public String getSerialNumberDataType() {
        return serialNumberDataType;
    }
    public void setSerialNumberDataType(String serialNumberDataType) {
        this.serialNumberDataType = serialNumberDataType;
    }
    public String getSensorType() {
        return sensorType;
    }
    public void setSensorType(String sensorType) {
        this.sensorType = sensorType;
    }
    public String getSensorTypeDataType() {
        return sensorTypeDataType;
    }
    public void setSensorTypeDataType(String sensorTypeDataType) {
        this.sensorTypeDataType = sensorTypeDataType;
    }
}

SensorGenerator.java(我当前对属性进行硬编码的类,但希望 Spring 从sensor.properties 加载它们。如果我注释掉 For 循环和引用 sourceProperties 的任何行,我可以使用硬编码返回映射编码值很好。这就是为什么我怀疑它是某种 Spring/Camel 集成问题):

封装样本;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class SensorGenerator {

    private Properties sourceProperties;

    // variable to increment key number for each sensor
    int sensorNumber = 1;

    // method to inject sensor.properties into a Map using Spring
    Map<String, String> getSensors() {
        Map<String, String> sensorMap = new HashMap<String, String>();
        for (Object key : sourceProperties.keySet()) {

            // Separate out each of the key,value pairs as an entry in the
            // values array
            String[] values = sourceProperties.getProperty((String) key).split(
                    ",");
            System.out.println("values array size= " + values.length);

            // define string buffer that appends sensor number for each sensor's
            // keys.  Ex: sensor1 would have s1make, s1makeDataType, etc.
            StringBuffer sensorNumberStringBuffer = new StringBuffer();
            sensorNumberStringBuffer.append("s");
            sensorNumberStringBuffer.append(sensorNumber);

            // make and its data type (with sensor number prefix)
            StringBuffer makeStringBuffer = new StringBuffer();
            makeStringBuffer.append(sensorNumberStringBuffer);
            makeStringBuffer.append("make");
            StringBuffer makeDataTypeStringBuffer = new StringBuffer();
            makeDataTypeStringBuffer.append(sensorNumberStringBuffer);
            makeDataTypeStringBuffer.append("makeDataType");

            // model and its data type (with sensor number prefix)
            StringBuffer modelStringBuffer = new StringBuffer();
            modelStringBuffer.append(sensorNumberStringBuffer);
            modelStringBuffer.append("model");
            StringBuffer modelDataTypeStringBuffer = new StringBuffer();
            modelDataTypeStringBuffer.append(sensorNumberStringBuffer);
            modelDataTypeStringBuffer.append("modelDataType");

            // serialNumber and its data type (with sensor number prefix)
            StringBuffer serialNumberStringBuffer = new StringBuffer();
            serialNumberStringBuffer.append(sensorNumberStringBuffer);
            serialNumberStringBuffer.append("serialNumber");
            StringBuffer serialNumberDataTypeStringBuffer = new StringBuffer();
            serialNumberDataTypeStringBuffer.append(sensorNumberStringBuffer);
            serialNumberDataTypeStringBuffer.append("serialNumberDataType");

            // sensorType and its data type (with sensor number prefix)
            StringBuffer sensorTypeStringBuffer = new StringBuffer();
            sensorTypeStringBuffer.append(sensorNumberStringBuffer);
            sensorTypeStringBuffer.append("sensorType");
            StringBuffer sensorTypeDataTypeStringBuffer = new StringBuffer();
            sensorTypeDataTypeStringBuffer.append(sensorNumberStringBuffer);
            sensorTypeDataTypeStringBuffer.append("sensorTypeDataType");

            /*
              put all the key,value pairs for this sensor in the sensorMap
            */

            //TODO: Change all the hard coded values below to be elements
            // from the values array once Spring can load spring.properties

            // make and and its data type
            sensorMap.put(makeStringBuffer.toString(), "DummyMake");
            sensorMap.put(makeDataTypeStringBuffer.toString(), "String");

            // model and and its data type
            sensorMap.put(modelStringBuffer.toString(), "DummyModel");
            sensorMap.put(modelDataTypeStringBuffer.toString(), "String");

            // serialNumber and and its data type
            sensorMap.put(serialNumberStringBuffer.toString(), "1234567890");
            sensorMap.put(serialNumberDataTypeStringBuffer.toString(), "long");

            // sensorType and its data type
            sensorMap.put(sensorTypeStringBuffer.toString(), "DummyType");
            sensorMap.put(sensorTypeDataTypeStringBuffer.toString(), "String");

            // increment for next sensor
            sensorNumber++;
        }
        return sensorMap;
    }

    public void setSourceProperties(Properties properties) {
        this.sourceProperties = properties;
    }

}

顺便说一句:上面堆栈跟踪中提到的 SensorGenerator.java 第 17 行是:

        for (Object key : sourceProperties.keySet()) {

这是一个示例sensor.properties文件:

sensor1=DummySensor1:String,SensorModel1:String,1234567890:long,SensorType1:String
sensor2=DummySensor2:String,SensorModel2:String,8675309123:long,SensorType2:String

最佳答案

问题是 SensorGenerator 不是由 spring 实例化的,而是由您的代码实例化的,因此永远无法设置属性。

@Service
public class HelloWorld {

    @Handler
    public Map<?, ?> returnMap(){
        SensorGenerator sensorGenerator = new SensorGenerator();

您应该在 HelloWorld 服务中自动连接sensorGenerator。

关于java - 在使用 Camel 的同时如何使用 Spring 加载属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19366350/

相关文章:

java - 简单的纯java CSV读取和解析

java - 为给定的大小为 n 的集合查找大小为 k 的子集

java - 使用 Gson 到 Json 的单个键值

json - 将多态案例类转换为 json 并返回

java - Spring 任务:scheduler XML configuration problem

Web 应用程序中的 Java Spring 错误处理性能

java - Netbeans build-impl.xml 错误

java - Java 有引用所有权或不可复制类的概念吗?

javascript - DataTable.js - 对于通过 Ajax 调用传入的某些数据集,<tbody></tbody> 内不会显示任何数据

java - 如何向 Spring Boot 添加更多指标?