用例首先,為什么我們需要在Spring容器之外進行依賴注入–我知道三個用例,其中我實例化了Spring容器之外的對象并需要注入依賴。
首先考慮使用Spring TaskExecutor執行一系列任務的情況,下面突出顯示的任務在Spring容器外部實例化:
List<Callable<ReportPart>> tasks = new ArrayList<Callable<ReportPart>>();List<ReportRequestPart> reportRequestParts = reportRequest.getRequestParts();for (ReportRequestPart reportRequestPart : reportRequestParts) {tasks.add(new ReportPartRequestCallable(reportRequestPart, reportPartGenerator));}List<Future<ReportPart>> responseForReportPartList;List<ReportPart> reportParts = new ArrayList<ReportPart>();try {responseForReportPartList = executors.invokeAll(tasks);for (Future<ReportPart> reportPartFuture : responseForReportPartList) {reportParts.add(reportPartFuture.get());}} catch (Exception e) {logger.error(e.getMessage(), e);throw new RuntimeException(e);}public class ReportPartRequestCallable implements Callable<ReportPart> {private final ReportRequestPart reportRequestPart;private final ReportPartGenerator reportPartGenerator;public ReportPartRequestCallable(ReportRequestPart reportRequestPart, ReportPartGenerator reportPartGenerator) {this.reportRequestPart = reportRequestPart;this.reportPartGenerator = reportPartGenerator;}@Overridepublic ReportPart call() {return this.reportPartGenerator.generateReportPart(reportRequestPart);}
}
第二個用例是ActiveRecord模式,說一下Spring Roo附帶的示例,請考慮以下方法,其中Pet類需要自身持久化并需要實體管理器來執行此操作:
@Transactionalpublic void Pet.persist() {if (this.entityManager == null) this.entityManager = entityManager();this.entityManager.persist(this);}
第三種用例是針對標記庫,該標記庫由Web容器實例化,但需要Spring的一些依賴。
解決方案 1.第一種方法實際上很簡單,即通過構造函數或設置器在對象實例化時提供依賴項。 這是我在第一個用例中使用的內容,在第一個用例中,任務具有兩個依賴關系,這些依賴關系由實例化任務的服務提供:
tasks.add(new ReportPartRequestCallable(reportRequestPart, reportPartGenerator));
2.第二種方法是創建一個知道Spring容器的工廠,聲明容器內的原型作用域所需的bean,并通過應用程序上下文的getBeans方法獲取這些bean,
將bean聲明為原型作用域bean:
<bean name='reportPartRequestCallable' class='org.bk.sisample.taskexecutor.ReportPartRequestCallable' scope='prototype'><property name='reportPartGenerator' ref='reportPartGenerator'></property></bean><bean name='reportPartRequestCallableFactory' class='org.bk.sisample.taskexecutor.ReportPartRequestCallableFactory'/>
和提供豆子的工廠:
public class ReportPartRequestCallableFactory implements ApplicationContextAware{private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public ReportPartRequestCallable getReportPartRequestCallable(){return this.applicationContext.getBean('reportPartRequestCallable', ReportPartRequestCallable.class);}
}
3.第三種方法是上述方法的一種變體,它是實例化bean,然后使用AutoWireCapableBeanFactory.autowireBean(instance)注入依賴項,方法是:
public class ReportPartRequestCallableFactory implements ApplicationContextAware{private GenericApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = (GenericApplicationContext)applicationContext;}public ReportPartRequestCallable getReportPartRequestCallable(){ReportPartRequestCallable reportPartRequestCallable = new ReportPartRequestCallable();applicationContext.getBeanFactory().autowireBean(reportPartRequestCallable);return reportPartRequestCallable;}
}
4.第四種方法是使用@Configurable ,但要注意的是它需要AspectJ才能工作。 Spring從本質上增強了類的構造函數,以按照上面第三種方法中明確完成的方式注入依賴項:
import org.springframework.beans.factory.annotation.Configurable;@Configurable('reportPartRequestCallable')
public class ReportPartRequestCallable implements Callable<ReportPart> {private ReportRequestPart reportRequestPart;@Autowired private ReportPartGenerator reportPartGenerator;public ReportPartRequestCallable() {}@Overridepublic ReportPart call() {return this.reportPartGenerator.generateReportPart(reportRequestPart);}public void setReportRequestPart(ReportRequestPart reportRequestPart) {this.reportRequestPart = reportRequestPart;}public void setReportPartGenerator(ReportPartGenerator reportPartGenerator) {this.reportPartGenerator = reportPartGenerator;}
}
還需要以下內容來配置負責@Configurable編織的Aspect:
<context:spring-configured/>
完成這些更改后,Spring會處理使用@Configurable注釋的類的任何依賴關系,即使構造完全在容器外部完成也是如此:
@Overridepublic Report generateReport(ReportRequest reportRequest) {List<Callable<ReportPart>> tasks = new ArrayList<Callable<ReportPart>>();List<ReportRequestPart> reportRequestParts = reportRequest.getRequestParts();for (ReportRequestPart reportRequestPart : reportRequestParts) {ReportPartRequestCallable reportPartRequestCallable = new ReportPartRequestCallable(); reportPartRequestCallable.setReportRequestPart(reportRequestPart);tasks.add(reportPartRequestCallable);}.......
結論
所有上述方法都有效地注入了在容器外部實例化的對象中的依賴項。 我個人更喜歡在有AspectJ支持的情況下使用方法4(使用@Configurable),否則我會使用方法2(隱藏在工廠后面并使用原型bean)。
祝您編程愉快,別忘了分享!
參考: all和其他博客中來自JCG合作伙伴 Biju Kunjummen的方法,用于連接Spring容器外部對象的依賴關系 。
翻譯自: https://www.javacodegeeks.com/2012/09/wire-object-dependencies-outside-spring.html