![](/img/trans.png)
[英]How to use @Autowired MongoTemplate in multiple classes in spring boot
[英]Can I use Spring @Autowired in multiple classes?
我的問題是- 我可以在多個類中自動裝配一個類的實例嗎?
我的應用程序使用Spring MVC在JSP前端頁面和MongoDB后端之間進行通信。 我將MongoDB用於存儲庫。 我創建了一個為MongoDB執行CRUD方法的服務。 可以通過以下一種CRUD方法看到這一點(由於不需要它們,因此未全部顯示)。 它使用Mongo模板。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class SensorReadingService {
@Autowired
private MongoTemplate mongoTemplate;
/**
* Create a unique mongo id and insert the document into
* the collection specified. If collection doesn't exist,
* create it.
* @param sensor
*/
public void addSensorReadingIntoCollection(SensorReading sensor, String collection) {
if (!mongoTemplate.collectionExists(SensorReading.class)) {
mongoTemplate.createCollection(SensorReading.class);
}
String id = UUID.randomUUID().toString();
String[] ids = id.split("-");
String noHyphens = "";
for(int i = 0; i<ids.length; i++) {
noHyphens = noHyphens.concat(ids[i]);
}
sensor.setId(noHyphens);
mongoTemplate.insert(sensor, collection);
}
可以看出,MongoTemplate是自動裝配的。 在我的Dispatcher-Servlet中,我有以下用於MongoDB的代碼:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="usm" />
<!-- Factory bean that creates the Mongo instance -->
<bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
<property name="host" value="localhost" />
</bean>
<!-- MongoTemplate for connecting and querying the documents in the database -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongo" ref="mongo" />
<constructor-arg name="databaseName" value="USMdb" />
</bean>
<!-- Use this post processor to translate any MongoExceptions thrown in @Repository annotated classes -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:annotation-driven />
我現在還有一個控制器,該控制器已經自動連接了服務,以便可以將來自JSP頁面的請求傳遞到控制器,然后控制器通過自動連接的服務將這些請求寫入數據庫。 (下面顯示的一個示例方法是該類的龐大方法)。 這種自動裝配的服務在調度程序servlet中沒有像以前自動裝配的MongoDB一樣。
import gnu.io.SerialPortEventListener;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class SensorReadingController implements SerialPortEventListener {
//mongodb service
@Autowired
private SensorReadingService sensorReadingService;
/**
* When a post method is achieved via save, check if reading already
* exists and update. Else, create new sensor. Redirect back to post race
* page.
* @param sensorReading
* @param model
* @return post race page
*/
@RequestMapping(value = "/postRace-save", method = RequestMethod.POST)
public View createSensorReading(@ModelAttribute SensorReading sensor, ModelMap model,@RequestParam(value="colName", required=true)String name) {
if (StringUtils.hasText(sensor.getId())) {
sensorReadingService.updateSensorReading(sensor, name);
}
else {
sensorReadingService.addSensorReading(sensor);
}
return new RedirectView("/USM-Analysis-Application/postRace");
}
sensorReadingService方法可以完美運行,可以對數據庫執行CRUD方法。 現在我的問題是,如何在另一個類中使用這個sensorReadingService? 當我添加
//mongodb service
@Autowired
private SensorReadingService sensorReadingService;
進入另一個類,該服務將無法正常工作。 沒有拋出錯誤,該服務只是不向數據庫添加任何內容。 是因為@Autowired只允許將一個類自動裝配到一個類中,即不能有多個實例嗎? 還是因為我沒有像MongoDB那樣在調度程序servlet中指定任何內容?
我需要讓它在另一堂課上工作的原因是,在我的課上,我正在偵聽串行事件。 當有可用數據時,我將創建一個新線程來處理此串行事件,以便程序的其余部分仍然可以運行。 在線程中,我解析從Serial接收到的字符串,創建一個新的SensorReading對象,然后將這個SensorReading對象寫入數據庫。 但是,由於無法使sensorReadingService在其他任何類中工作,因此無法執行對數據庫的寫入。
首先,我使用一個實現Runnable的類來執行解析和保存。 在此類中使用@Autowired無效,因此我嘗試將sensorReadingService從控制器傳遞給線程(如下面的代碼所示)。 這也不起作用。 然后,我更改了線程以實現Callable,以便可以返回SensorReading並將其保存到我的具有正常工作的自動接線服務的控制器類中的數據庫中。 但是,這首先破壞了創建線程的目的,因為這是我希望在線程中執行的對數據庫的寫操作,因為這會減慢整個程序的速度。
@Override
public void serialEvent(SerialPortEvent oEvent) {
if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
//use a thread in the thread pool
//tried passing sensorReadingService to thread but did not work
//threadPool.execute(new RealTimeThread(input, sensorReadingService, getRealTimeIdsAndNames()));
//tried return sensor reading. This works but slows down the program.
Callable<List<SensorReading>> callable = new RealTimeThread(input, getRealTimeIdsAndNames(), offset, sensitivity);
Future<List<SensorReading>> future = threadPool.submit(callable);
所以,我只是想知道是否有人知道@Autowired在做什么錯? 我可以有多個@Autowired實例嗎? 我是否需要在調度程序servlet中添加一些內容? 還是應該不使用@Autowired並嘗試以其他方式調用我的服務?
任何建議將不勝感激,如果您需要我發布更多代碼,請告訴我! 提前致謝!
編輯:
對於我的RealTimeThread類,我有以下代碼
import org.springframework.beans.factory.annotation.Autowired;
import usm.service.SensorReadingService;
public class RealTimeThread implements Callable<List<SensorReading>> {
//mongodb service
@Autowired
private SensorReadingService sensorReadingService;
//fed by an InputStreamReader to convert bytes to strings
BufferedReader input;
//variables for getting data from real time
ArrayList<Byte> values = new ArrayList<Byte>();
//mappings for sensors
double[] offset;
double[] sensitivity;
Map<String, String> realTimeIDs;
public RealTimeThread(BufferedReader input, Map<String, String> rt, double[] offset, double[] sens) {
this.input = input;
realTimeIDs = rt;
this.offset = offset;
this.sensitivity = sens;
}
//Split up the line, parse it and add to database
@Override
public List<SensorReading> call() throws Exception {
List<SensorReading> toReturn = new ArrayList<SensorReading>();
String inputLine;
if((inputLine = input.readLine()) != null) {
//pass to the scanner
Scanner scan = new Scanner(inputLine);
//get everything after the starting pattern
Pattern pStart = Pattern.compile("\\x02\\x02\\x02\\x02\\x02(.*)");
Matcher mStart = pStart.matcher(inputLine);
if ( mStart.find() ) {
inputLine = mStart.group(1);
//get everything before ending pattern
Pattern pEnd = Pattern.compile("(.*)\\x04\\x04\\x04\\x04\\x04");
Matcher mEnd = pEnd.matcher(inputLine);
if ( mEnd.find() ) {
inputLine = mEnd.group(1); // " that is awesome"
//split up this string
scan = new Scanner(inputLine);
//set the delimiter to unit separator
Pattern delim = Pattern.compile("\\x1F");
scan.useDelimiter(delim);
while(scan.hasNext()) {
//get the next string
String s = scan.next();
//change it to an integer and make it a byte
int val = Integer.parseInt(s);
byte b = (byte) val;
//add to the arraylist
values.add(b);
}
//parse the values
toReturn = parser(values);
// System.out.println("RETURN 0 " + toReturn.get(1).getRawValue());
//reset the arraylist
values = new ArrayList<Byte>();
}
}
}
return toReturn;
}
//Parser to split up line, create a new sensor reading and add to database
private List<SensorReading> parser(ArrayList<Byte> data) {
//arraylist for data after transformation
ArrayList<Short> convertedData = new ArrayList<Short>();
//get all data in big endian
for (int i = 0; i<46; i=i+2) {
...
...
convertedData.add(dataChunk);
}
//get the time now
double myTime = System.currentTimeMillis();
ArrayList<SensorReading> toReturn = new ArrayList<SensorReading>();
//add to the database
for(int i = 0; i<convertedData.size(); i++) {
//create new sensor reading
SensorReading sr = new SensorReading();
sr.setSensorId(keys[i].toString());
sr.setName(sens.get(keys[i]));
sr.setRawValue(convertedData.get(i));
sr.setTime(myTime);
//add to database - this is not working
sensorReadingService.addSensorReadingIntoCollection(sr, "realTime");
System.out.println("added");
toReturn.add(sr);
}
return toReturn;
}
}
當嘗試使用XML或使用@Component創建bean時,出現BeanCreationException異常,表明沒有默認的空構造函數。 我有一個構造函數,但是有輸入。 如何使Spring使用此構造函數?
我嘗試在具有的構造函數上使用@Autowired,但出現錯誤,提示它無法自動裝配字段BufferedInput。 有什么建議么? 謝謝!
編輯:
我在RealTimeThread類上使用了@Component,在構造函數上使用了@Autowired。 現在我得到的錯誤如下:
[localhost-startStop-1] ERROR org.springframework.web.context.ContextLoader - Context
initialization failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'realTimeThread' defined in file [C:\Users\Lauren\Dropbox\MEng Project\1. Off-board Software\Lauren\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\USM-Analysis-Application\WEB-INF\classes\usm\model\RealTimeThread.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [java.io.BufferedReader]: : No qualifying bean of type [java.io.BufferedReader] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.io.BufferedReader] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
所以我從中收集到的是Spring不處理我的BufferedReader嗎? 我從我的Controller類中傳遞了BufferedReader,如下所示:
@Controller
public class SensorReadingController implements SerialPortEventListener {
//mongodb service
@Autowired
private SensorReadingService sensorReadingService;
private BufferedReader input;
double[] offset;
double[] sensitivity;
...
@Override
public void serialEvent(SerialPortEvent oEvent) {
if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
//use a thread in the thread pool
//threadPool.execute(new RealTimeThread(input, sensorReadingService, getRealTimeIdsAndNames()));
//input.readLine();
Callable<List<SensorReading>> callable = new RealTimeThread(input, getRealTimeIdsAndNames(), offset, sensitivity);
Future<List<SensorReading>> future = threadPool.submit(callable);
我以為,因為我正在從控制器傳遞這些變量,所以Spring已經處理了它們。 但我想不是。 如何使Spring管理這些變量? 我是否像在使用服務一樣在它們上方使用@Autowired?
問題似乎是將SensorReadingService
自動連接到的類不是Spring管理的類。 為了使自動裝配工作,需要接線的類需要由Spring管理其生命周期(這意味着您需要在Spring Java Config的Spring XML中為該類提供一個條目)
您可以這樣重構代碼:
1)向RealTimeThread
添加另一個構造函數參數,該參數SensorReadingService
類型。
2)像這樣創建一個類RealTimeThreadFactory
:
public class RealTimeThreadFactory {
private final SensorReadingService sensorReadingService;
public RealTimeThreadFactory(SensorReadingService sensorReadingService) {
this.sensorReadingService = sensorReadingService;
}
public RealTimeThread getObject(BufferedReader input, Map<String, String> rt, double[] offset, double[] sens) {
return new RealTimeThread(input, rt, offset, sens, sensorReadingService);
}
}
3)在組件掃描中包含的包下的某個位置添加Java Config類
@Configuration
public class RealTimeThreadConfig {
@Autowired
private SensorReadingService sensorReadingService;
@Bean
public RealTimeThreadFactory realTimeThreadFactory() {
RealTimeThreadFactory realTimeThreadFactory = new RealTimeThreadFactory(sensorReadingService);
return realTimeThreadFactory;
}
}
4)現在,使用當前代碼創建RealTimeThread
的類現在必須是Spring bean(使用您喜歡的任何方式)並注入RealTimeThreadFactory
。 為了創建RealTimeThread對象,只需在工廠中使用適當的參數簡單地調用getObject()方法即可。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.