用例首先,为什么我们需要在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;
}
@Override
public ReportPart call() {
return this.reportPartGenerator.generateReportPart(reportRequestPart);
}
}
第二个用例是ActiveRecord模式,说一下Spring Roo附带的示例,请考虑以下方法,其中Pet类需要自身持久化并需要实体管理器来执行此操作:
@Transactional
public 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;
@Override
public 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;
@Override
public 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() {
}
@Override
public 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注释的类的任何依赖关系,即使构造完全在容器外部完成也是如此:
@Override
public 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