我有一个 HelloWorld Java 项目,它使用 Camel 获取地图,并以 JSON 格式打印出其内容。Map 当前具有硬编码值,但我真的想更改我的代码,以便它使用 Spring 将嵌套键值对的 sensor.properties 文件加载到此 Map 中。
我编写了另一个仅使用 Spring 的 Java 项目,并且可以将 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&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