自动装配 TimerTask 不工作

Autowired with TimerTask not working

我在 Java Sprint 中有一个 API,它需要每天执行一项任务,以从在 FTP 服务器中生成 txt 的外部系统导入一些数据。 我遇到的问题是自动装配字段没有被自动装配....我的意思是,它们是空的。

每次应用程序启动时,我都使用@PostConstruct 来执行任务,因此我可以使用计时器安排操作。

尝试 1

这是代码(首先是 PostContruct 方法)

@Override
    @PostConstruct
    @Transactional
    public Response importdata(){
        Response response = new Response();
        try {
            System.out.println("*** Setting Import ****");
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, 21);
            calendar.set(Calendar.MINUTE, 5);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);

            Timer time = new Timer(); // Instantiate Timer Object
            time.schedule(new ImportServiceImpl(), calendar.getTime(), TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS));
        } catch (Exception e) {
            e.printStackTrace();
            response.setCode(CodeList.EXCEPTION);
            response.setSuccess(false);
        }
        return response;
    }

所以在这里,我安排在每天 21 点 05 点举行活动。

这里有 ImportServiceImpl

@Component
public class ImportServiceImpl extends TimerTask  implements ImportService{

    @Autowired
    InvoiceDao invoiceDao;

    @Autowired
    ClientDao clientDao;

    @Override
    @Transactional
    public void run() {
        System.out.println("*** Running **** " + new Date());
        startImport();
    }

    @Override
    @Transactional
    public void startImport() {
        Path dir = Paths.get(ResourcesLocation.IMPORT_ROUTE);
        Boolean success = true;
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
            for (Path entry : stream) {
                if (!Files.isDirectory(entry)) {
                    BufferedReader br = new BufferedReader(
                            new InputStreamReader(new FileInputStream(ResourcesLocation.IMPORT_ROUTE + entry.getFileName().toString())));
                    System.out.println("*** Importing file **** " + ResourcesLocation.IMPORT_ROUTE + entry.getFileName().toString());
                    try {
                        String line;
                        int i = 0;
                        while ((line = br.readLine()) != null) {

                            final String[] parts = line.split("\|");
                            System.out.println("Line: " + i++ + " Text: " + line);
                            System.out.println("Factura: " + parts[1]);
                            Client client = (Client) this.clientDao.get(parts[0]);
                            String invoiceNumber = this.generateInvoiceNumber(parts[1].substring(1).replace("-", ""));
                            Invoice inv = (Invoice) this.invoiceDao.getByNumber(invoiceNumber);
                            if(inv == null){
                                inv = new Invoice();
                                inv.setClient(client);
                                inv.setNumber(invoiceNumber);
                                inv.setDate(this.convertDate(parts[2]));
                                inv.setTotal(this.convertFloat(parts[3]));
                                inv = (Invoice) this.invoiceDao.addOrUpdate(inv);
                            }
                        }
                    }
                    catch (Exception e) {
                        e.printStackTrace();
                        success = false;
                    }
                    finally {
                        try {
                            br.close();
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        if(success){
                            try {
                                Files.delete(entry);
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    }

这里的问题是 this.clientDao 应该自动装配,但它是空的.... 所以我试着做

if(this.clientDao == null)
    this.clientDao = new ClientDaoImpl();

但是,在 ClientDaoImpl 的 get 方法中我有

@SuppressWarnings("unchecked")
    public Object get(String name) throws Exception
    {
        Query q = sessionFactory.getCurrentSession()
                .createQuery("from " + this.entity + " WHERE name = '" + name + "'");
        return q.uniqueResult();
    }

并且 sessionFactory 为空,因为它不是自动装配的。我不认为解决方案是继续手动初始化每个 class...

尝试 2

然后我尝试自动连接 class ImportServiceImpl 而不是手动初始化,并更改了我的代码:

@Autowired
    ImportService importService;

time.schedule(this.importService, calendar.getTime(), TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS));

但是我得到一个错误,因为 this.importService 不是 ImportServiceImpl,它是接口 ImportService,接口不能扩展 TimerTask。

3 次尝试

更改自动装配 class 以自动装配实现而不是接口。 像这样:

@Autowired
    ImportServiceImpl importService;

所以我得到以下错误:

java.lang.IllegalArgumentException: Can not set com.app.services.ImportServiceImpl field com.app.services.InvoiceServiceImpl.importService to com.sun.proxy.$Proxy184

我检查了 Why is my Spring @Autowired field null?

中的答案

但是手动解决方案不起作用,因为从未设置上下文。我也尝试使用 @Configure 注释,这也是这里建议的,或者我不知道如何使用它或者它不起作用。

为了简化示例: 我有一个 class InvoiceServiceImpl,它有一个带有注释 @PostConstruct 的方法 importdata,所以它在应用程序启动后调用(那部分没问题) importdata 方法,为 class ImportServiceImpl 安排一个定时器任务(所以到目前为止还不错)。但是当合适的时候,该方法被执行,但是 timertask class 中方法内的 @Autowired 属性为空。

已更新

我必须建议对代码的组织方式进行小幅修改。

首先定义ImportService

public interface ImportService {
    public void startImport();
}

以及相关的实现。

@Service
public class ImportServiceImpl implements ImportService {

    @Autowired
    private InvoiceDao invoiceDao;

    @Autowired
    private ClientDao clientDao;

    @Override
    @Transactional
    public void startImport() {
        // Process...
    }

然后,您就有了 TimerTask 实施。

@Component
public class ImportTimerTask extends TimerTask {

    @Autowired
    private ImportService importService;

    @Override
    public void run() {
        importService.startImport();
    }
}

最后,您在任何 Class.

中都有 @PostConstruct 方法
@Autowired
private ImportTimerTask importTimerTask;

@PostConstruct
@Transactional
public void importData() {
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY, 9);
    calendar.set(Calendar.MINUTE, 2);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    Timer time = new Timer();
    time.schedule(importTimerTask, calendar.getTime(),
            TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS));
}

通过这样的实现,我的简单测试没问题,invoiceDaocliendDao 已成功自动装配。


您可以尝试在 @Configuration class 中添加 @EnableAspectJAutoProxy(proxyTargetClass=true) 以实施尝试 3。

您可以找到更多参考 here