在Spring容器外部连接对象依赖项

有几种有趣的方法可以设置在Spring容器外部实例化的对象的属性和依赖关系。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值