Comment puis-je @autowire
bean class TransactionManagerImpl
qui a 1 constructeur d'argument (String) sans utiliser new
dans l'application spring-boot?
Même après avoir parcouru de nombreux articles, je n'ai pas pu obtenir d'indice sur autowire
sans utiliser new
Je dois autowire
TransactionManager
dans trois classes différentes et les paramètres sont différents dans les trois classes.
Cela ressemble à un scénario très basique.
@Service public class TransactionManagerImpl implements TransactionManager { private final Logger logger = LoggerFactory.getLogger(this.getClass()); String txnLogFile; @ConstructorProperties({"txnLogFile"}) public TransactionManagerImpl(String txnLogFile) { this.txnLogFile= txnLogFile; } }
3 Réponses :
Y a-t-il une exigence spécifique pour laquelle vous souhaitez utiliser l'annotation @Service? sinon, vous pouvez utiliser @Bean pour créer un bean pour TransactionManagerImpl comme ci-dessous.
@Configuration public class Config { @Value("${txnLogFile}") private String txnLogFile; @Bean public TransactionManager transactionManager() { return new TransactionManagerImpl(txnLogFile); } }
et supprimer l'annotation @Service de TransactionManagerImpl.
En mettant de côté les autres complications, cela peut être fait comme ceci
public TransactionManagerImpl(@Value("${txnLogFile}") String txnLogFile) { this.txnLogFile= txnLogFile; }
Enfin, je l'ai fait comme ci-dessous, maintenant sûr que c'est la meilleure façon de faire. Je ne voulais pas avoir trois implémentations uniquement à cause d'une variable.
application.yaml
public class TransactionManagerImpl implements TransactionManager { @Autowired private ApplicationContext applicationContext; private String txnLogFile; public TransactionManagerImpl(String txnLogFile) { this.txnLogFile = txnLogFile; } private CsvService csvService; @PostConstruct public void init() { csvService = applicationContext.getBean(CsvService.class, txnLogFile); } public ZonedDateTime create() throws IOException, ParseException { try { csvService.createTxnInfoFile(); return csvService.getLastSuccessfulTxnTimestamp(); } catch (IOException e) { throw new IOException("Exception occured in getTxnStartDate()", e); } } }
MainApplication.java
@Service @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public interface TransactionManager { public ZonedDateTime create() throws IOException, ParseException; }
TypeOneRoute.java
@Configuration public class TypeTwoRoute extends RouteBuilder { @Value("${app.type-b.txn-log-file}") private String txnLogFile; @Autowired private ApplicationContext applicationContext; private TransactionManager transactionManager; @Override public void configure() throws Exception { transactionManager = applicationContext.getBean(TransactionManager.class, txnLogFile); transactionManager.create(); } }
TypeTwoRoute.java
@Configuration public class TypeOneRoute extends RouteBuilder { @Value("${app.type-a.txn-log-file}") private String txnLogFile; @Autowired private ApplicationContext applicationContext; private TransactionManager transactionManager; @Override public void configure() throws Exception { transactionManager = applicationContext.getBean(TransactionManager.class, txnLogFile); transactionManager.someOperation(); } }
TransactionManager.java
@SpringBootApplication public class MainApplication { public static void main(String[] args) { new SpringApplicationBuilder(MainApplication.class).web(WebApplicationType.NONE).run(args); } @Bean public TransactionManager transactionManager(@Value("${app.default.txn-log-file}") String txnLogFile) { return new TransactionManagerImpl(txnLogFile); } @Bean public CsvService csvService(String txnLogFile) { return new CsvServiceImpl(txnLogFile); } }
TransactionManagerImpl.java
app: type-a: txn-log-file: data/type-a-txn-info.csv type-b: txn-log-file: data/type-b-txn-info.csv default: txn-log-file: data/default/txn-info.csv
Initialement, TransactionManager Bean sera enregistré avec app.default.txn-info.csv
et quand je l'obtiendrai réellement depuis ApplicationContext
Je remplace la valeur par le paramètre passé pour obtenir le bean de ApplicationContext
D'où vient txnLogFile? Cela créera de toute façon une instance singleton. Si vous avez 3 implémentations différentes, vous devrez utiliser @Qualifier pour les distinguer. Vous pouvez toujours utiliser ApplicationContext pour obtenir ce dont vous avez besoin et y fournir des arguments de contrctor. Vous pouvez également utiliser
@Bean
avec un qualificatif comme dans answer.txnLogFile provient du fichier de propriétés. Et il existe trois fichiers journaux différents. En fonction des trois transactions diff, j'injecterai taxLogFile à transactionManager qui écrira dans txnLogFile
Vous pouvez également utiliser
@Value
directement sur l'argument du constructeur.@Antoniossss qui ne lira qu'une seule valeur, donc je dois avoir trois impl de TransactionManager
Oui, c'est pourquoi vous devez soit distinguer ces valeurs par implémentation, soit obtenir des beans du contexte d'application en fournissant la chaîne requise comme arg. Dans les deux cas, un qualificatif est nécessaire.
@Antoniossss et si j'enregistre TransactionManager et obtient le bean en utilisant applicationContext en passant le paramètre comme ci-dessous?
@Value ("$ {app.type-a.txn-log-file}") private String txnLogFile; Contexte ApplicationContext privé @Autowired; TransactionManager transactionManager = context.getBean (TransactionManager.class, txnLogFile);
C'est ce que je dis que tu peux faire depuis le début (mon premier commentaire)
continuons cette discussion dans le chat .