用例首先,为什么我们需要在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