如何将Spring上下文作为方法参数传递?

时间:2018-10-11 15:29:10

标签: java spring spring-boot

我需要一些有关Spring的帮助(SpringBoot 1.3.2.RELEASE,Spring 4.3.11.RELEASE)。 用例很特殊,需要解释。

我有一个Spring应用程序,用于管理客户发送的请求。为了处理这些请求,我们需要使用带有@Autowired批注声明的服务。非常经典。

最近,我们决定处理来自其他国家/地区的新型请求。 关键是面对不同情况和不同类型的请求,我们决定实施策略模式。 ->根据请求的类型,我们执行在运行时选择的策略。每个策略都包含在一个具体的类中,并且所有策略共享一个相同的接口。

所以,我有:

  • 一个完全完成请求处理的主类。为了完成其工作,此类用于调用使用@Autowired注解声明的somes服务。

现在我有:

  • 仅初始化请求处理的主类。去做 它的工作,该类将在运行时根据某些条件实例化一个策略。
  • 具有2种方法的IStrategy(接口)将被实施 按我的两个具体班级
  • 2个具体的类(以及更多类)将完成这项工作。 非常重要的一点是,这些具体的类将在加载Spring上下文之后在运行时实例化。

问题在于,在加载Spring上下文之后,将无法再使用@Autowired注释。 我想在我的具体策略类中使用的所有服务都无法再通过@Autowired调用,并且保持为NULL。

我找到了一种解决方法,即将所需的服务作为参数传递给具体的策略类,但是我必须作为参数传递的服务数量因一种策略而异。

我认为我应该改为传递整个Spring上下文,但是我不知道该怎么做。而且我也不知道如何从上下文访问所有带注释的服务。

PS:我不显示代码行,因为我认为实际上没有必要。如果您认为使用代码更加明确,我会发送一些。

非常感谢。

3 个答案:

答案 0 :(得分:0)

您应该声明一个工厂来映射依赖关系,而不是将服务声明为Bean,它将在将服务的具体实例返回到注入器之前检查请求。 在这里看看:

https://grokonez.com/spring-framework/spring-core/use-spring-factory-method-create-spring-bean

答案 1 :(得分:0)

您可以使用下面的类来静态获取应用程序上下文和Beans

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

@Service
public class BeanUtil implements ApplicationContextAware {

    private static ApplicationContext context;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
    public static <T> T getBean(Class<T> beanClass) {
        return context.getBean(beanClass);
    }



}

答案 2 :(得分:0)

大家很快回答我。 首先,对于您最近对所有评论的回答如此,我必须道歉。上一次冲刺的工作量很大,而新冲刺的效果并不好^^

我的需要是在Spring上下文完成创建和加载应用程序的所有部分之后,在对象上创建。 作为策略模式的一部分,我必须在运行时实例化一个类,具体取决于必须处理的请求文件中的某些值。此类需要使用@Autowired批注声明的许多服务,但是所有自动装配的对象仍为'null',因为在上下文加载后被调用。

这是我首先要使用的代码。 没有Spring没关系。

Function<Document, IStrategy> func = doc -> {
        String strategyToApply = "";
        IStrategy strategy = null;
        switch(doc.getPlace()) {
            case "Paris":
                strategyToApply = "strategies_classes.ProcessParis";
                break;
            case "New York":
                strategyToApply = "strategies_classes.ProcessNewYork";
                break;
            }
            case "Roma":
                ...
        try {
            **Class<?> classToUse = Class.forName(strategyToApply);
            strategy = (IStrategy) classToUse.newInstance();**
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return strategy;
};

Consumer<Document> consumerStrategy = doc -> {
    IStrategy strategy = func.apply(doc);
    strategy.bookRequest(doc);
};
documents.stream()
    .forEach(consumerStrategy);

我终于找到了魔法对象。当Spring对象的生命周期不符合我们自己的概念时,这是一个很好的解决方法。

要使用它,只需使用@Autowired进行声明:

@Autowired
private AutowireCapableBeanFactory autowireBeanFactory;

请注意,AutowireCapableBeanFactory是一个Spring对象,您无需在其他任何地方声明!!

然后,使用起来非常简单(我设计了一种全新的服务,与您在上面看到的完全不同,但是它的作用相同):

public <T> T getStrategyToUse(Entity bookingCtr, Funder funder, StrategyEnum strategy) throws FunctionalException {
        String strategyToApply = null;
        strategyToApply = strategyDao.getClassToApply(bookingCtr, funder, strategy);
        Class<?> classToUse;
        try {
            classToUse = Class.forName(strategyToApply);
            T strat = (T) **autowireBeanFactory.getBean**(classToUse);
            return (T) strat;
        } catch (ClassNotFoundException e) {
            LOGGER.error("The indicated Strategy class was not found", e);
        }
        return null;
    }

在运行时加载时,将立即实例化所选的类,并且其所有自动装配对象将不再为空。

我希望这会有所帮助。