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.
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
Réponse mise à jour avec une suggestion de modification de code. J'espère que cela pourra aider. – lzagkaretos
Oh mec! tu sauves ma vie! Cela fonctionne comme un champion! – Faabass