2017-09-21 5 views
0

J'ai une API dans Java Sprint qui doit exécuter une tâche quotidienne pour importer des données d'un système externe qui génère un txt dans un serveur FTP. Le problème que j'ai est que les champs Autowired ne sont pas autowired .... Je veux dire, ils sont null. J'utilise @PostConstruct pour exécuter une tâche à chaque démarrage de l'application, donc je peux planifier l'action avec un minuteur.Autowired avec TimerTask ne fonctionne pas

Tentative 1

Voici le code (d'abord la méthode 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; 
    } 

Donc ici, je suis la planification de la fonction quotidienne à 21h05.

Ici vous avez 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(); 
     } 
    } 

La question est ici que this.clientDao devrait être autowired, mais il est nul .... donc j'ai essayé de le faire

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

Mais, dans la méthode get dans ClientDaoImpl j'ai

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

Et il sessionFac tory était nulle car il n'a pas été autowired .. Et je ne pense pas que la solution est de garder toutes les classes d'initialisation manuellement ...

attemp 2

Puis j'ai essayé de Autowired la classe ImportServiceImpl au lieu d'initialisation manuellement et changé mon code avec:

@Autowired 
    ImportService importService; 

et

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

Mais je reçois une erreur parce que le this.importService n'est pas ImportServ iceImpl, c'est ImportService qui est l'interface et l'interface ne peut pas étendre TimerTask.

3 Tentative

Modifier la classe Autowired à autowired la mise en œuvre et non l'interface. Comme ceci:

@Autowired 
    ImportServiceImpl importService; 

J'obtiens l'erreur suivante:

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

J'ai vérifié les réponses dans Why is my Spring @Autowired field null?

Mais la solution manuelle ne fonctionne pas comme le contexte est jamais setted. J'ai aussi essayé avec l'annotation @Configure, qui a été suggérée ici aussi ou je ne sais pas comment l'utiliser ou ça ne marche pas.

Pour simplifier l'exemple: J'ai un InvoiceServiceImpl de classe qui a une importdata méthode avec le @PostConstruct d'annotation, il est donc appelé après le début de l'application (cette partie est ok) la méthode importdata, planifier un TimerTask pour la ImportServiceImpl de classe (jusqu'ici tout va bien).Mais alors, quand c'est le bon moment, la méthode est exécutée mais les propriétés @Autowired à l'intérieur de la méthode dans la classe timertask sont nulles.

Répondre

1

Mise à jour

Je dois proposer une petite modification de la façon dont est organisé le code.

Tout d'abord ImportService est défini.

public interface ImportService { 
    public void startImport(); 
} 

Et l'implémentation associée. Puis, vous avez votre implémentation TimerTask.

@Component 
public class ImportTimerTask extends TimerTask { 

    @Autowired 
    private ImportService importService; 

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

Et enfin, vous avez la méthode @PostConstruct dans une classe.

@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)); 
} 

Avec une telle mise en œuvre, mes tests simples étaient bien, et invoiceDaocliendDao ont été autowired avec succès.


Vous pouvez essayer d'ajouter @EnableAspectJAutoProxy(proxyTargetClass=true) dans une classe @Configuration afin de mettre en œuvre 3. Tentative

Plus référence, vous pouvez trouver here.

+0

J'ai ajouté que à mon WebConfig mais il ne fonctionne pas: @ Configuration @ EnableWebMvc @ EnableAspectJAutoProxy (proxyTargetClass = true) WebConfig public class étend WebMvcConfigurerAdapter {.. Maintenant, je me fais erreur Proxy174 $ (Je ne sais pas si le nombre compte) – Faabass

+0

Réponse mise à jour avec une suggestion de modification de code. J'espère que cela pourra aider. – lzagkaretos

+1

Oh mec! tu sauves ma vie! Cela fonctionne comme un champion! – Faabass