我可以在多个类中使用Spring @Autowired吗? [英] Can I use Spring @Autowired in multiple classes?

查看:146
本文介绍了我可以在多个类中使用Spring @Autowired吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题是-我可以自动装配多个类中的一个类的实例吗?

我的应用程序使用Spring MVC在JSP前端页面和我的MongoDB后端之间进行通信.我正在将MongoDB用于我的存储库.我创建了一个为MongoDB执行CRUD方法的服务.可以通过以下一种CRUD方法看到这一点(未显示全部,因为它们不是必需的).它使用Mongo模板.

My application uses Spring MVC to communicate between the JSP front end pages and my MongoDB back end. I am using MongoDB for my repository. I have created a service which performs the CRUD methods for MongoDB. This can be seen below with one of the CRUD methods (not all are shown as they are not needed). It uses the Mongo template.

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的代码:

As can be seen, the MongoTemplate is autowired. In my Dispatcher-Servlet I have the following code for 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一样.

I now also have a controller which has autowired the service so that requests from the JSP page can be passed to the controller, and the controller then writes these requests to the database via the autowired service. (One example method shown below as the class is massive). This autowired service doesn't have anything in the dispatcher servlet like the MongoDB autowired previously.

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?添加时

The sensorReadingService method runs perfectly, performing CRUD methods on the database. Now my question is, how do I use this sensorReadingService in another class? When I add

//mongodb service
@Autowired
private SensorReadingService sensorReadingService;

进入另一个类,该服务将无法正常工作.没有抛出错误,该服务只是不向数据库添加任何内容.是因为@Autowired只允许将一个类自动装配到一个类中,即不能有多个实例?还是因为我没有像在MongoDB中那样在调度程序servlet中指定任何内容?

into another class, the service doesn't work. No errors are flung, the service just does not add anything to the database. Is it because @Autowired only allows the class to be autowired in one class i.e. there can't be multiple instances? Or is it because I haven't specified anything in my dispatcher-servlet like with the MongoDB?

我需要让它在另一堂课上工作的原因是,在我的课上,我正在侦听Serial事件.当有可用数据时,我将创建一个新线程来处理此串行事件,以便程序的其余部分仍然可以运行.在线程中,我解析从Serial接收到的字符串,创建一个新的SensorReading对象,然后将这个SensorReading对象写入数据库.但是,由于无法使sensorReadingService在其他任何类中工作,因此无法执行对数据库的写操作.

The reason I need to have it work in another class is that in my class, I am listening for Serial events. When there is data available, I create a new thread to deal with this serial event so that the rest of my program can still function. In the thread, I parse the string I received from Serial, create a new SensorReading object, and then I want to write this SensorReading object to the database. However, as I cannot get sensorReadingService to work in any other classes, I can't perform this write to database.

首先,我使用了一个实现Runnable的类来执行解析和保存.在此类中使用@Autowired无效,因此我尝试将sensorReadingService从控制器传递到线程(如下面的代码所示).这也不起作用.然后,我将线程更改为实现Callable,以便可以返回SensorReading并将其保存到我的具有正常工作的自动接线服务的控制器类中的数据库中.但是,这首先破坏了创建线程的目的,因为这是我希望在线程中执行的对数据库的写操作,因为这会使整个程序变慢.

First I used a class that implements Runnable to perform the parsing and saving. Having @Autowired in this class did not work, so I tried passing the sensorReadingService to the thread from the controller (shown in code below). This did not work either. I then changed my thread to implement Callable so I could return the SensorReading and save it to the database in my original controller class that has the working autowired service. However, this defeats the purpose of creating the thread in the first place as it is the writing to the database I wish to perform in the thread, as it slows down the whole program if not.

 @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并尝试以其他方式调用我的服务?

So, I was just wondering if anyone knew what I was doing wrong with @Autowired? Can I have multiple instances of @Autowired? Do I need to add something in my dispatcher servlet? Or should I just not use @Autowired and try to call my service another way?

任何建议将不胜感激,如果您需要我发布更多代码,请告诉我!提前致谢!

Any suggestions would be much appreciated and if you need me to post anymore code let me know! Thanks in advance!

对于我的RealTimeThread类,我具有以下代码

For my RealTimeThread class I have the following code

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使用此构造函数?

When trying to create a bean either in my XML or using @Component I get a BeanCreationException saying that there is no default empty constructor. I have a constructor but it has inputs into it. How do I make Spring use this constructor?

我尝试在拥有的构造函数上使用@Autowired,但出现错误,提示它无法自动装配BufferedInput字段.有什么建议?谢谢!

I tried using @Autowired on the constructor I have but I got an error saying that it could not autowire field BufferedInput. Any suggestions? Thanks!

我在RealTimeThread类上使用了@Component,在构造函数上使用了@Autowired.现在我得到的错误如下:

I have used @Component on my RealTimeThread class and @Autowired on my constructor. Now the errors I am getting are as follows:

[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,如下所示:

So what I gather from this is that my BufferedReader is not handled by Spring? I am passing my BufferedReader in from my Controller class as follows:

@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?

I thought that because I was passing these variables from the controller, Spring already dealt with them. But I guess not. How do I make Spring manage these variables? Do I just use @Autowired above them like I have done with my service?

推荐答案

问题似乎是SensorReadingService被自动连接到的类不是Spring管理的类.为了使自动装配工作,需要接线的类需要由Spring管理其生命周期(这意味着您需要在Spring Java Config的Spring XML中为该类提供一个条目)

The problem seems to be that the class in which SensorReadingService is being autowired into, is not a class managed by Spring. For autowiring to work, the class that requires the wiring needs to have it's lifecycle managed by Spring (meaning that you need to have an entry for that class in your Spring XML of Spring Java Config)

您可以像这样重构代码:

You could refactor your code like this:

1)向RealTimeThread添加另一个构造函数参数,该参数的类型将为SensorReadingService.

1) Add another constructor argument to RealTimeThread which is going to be of type SensorReadingService.

2)像这样创建一个类RealTimeThreadFactory:

2) Create a class RealTimeThreadFactory like so:

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类

3) Add a Java Config class somewhere under the package that is being included in the component scan

@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()方法

4) The class that with your current code creating RealTimeThread needs to now be a Spring bean (using any way you prefer) and be injected with RealTimeThreadFactory. In order to create the RealTimeThread objects , simple call the getObject() method on the factory with the appropriate arguments

这篇关于我可以在多个类中使用Spring @Autowired吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆