How to use @Autowired service, in an object created with the factory / strategy pattern (created at runtime)?

huangapple 未分类评论50阅读模式
英文:

How to use @Autowired service, in an object created with the factory / strategy pattern (created at runtime)?

问题

考虑一个名为Action的接口,以及两个实现类:StupidActionSmartAction

SmartAction需要使用另一个服务,但由于Action是在运行时创建的,所以@Autowired注释不起作用(服务为null)。

Spring中使用策略模式是否有问题?是否有一个好的解决方案来解决这个问题?

我可以将"StupidAction"也设置为一个服务,并且不实例化它。我也可以将自动装配的服务传递给"doSomething"方法的参数中。但这两种解决方案都不太理想。

一些代码示例:

public interface Action {
    void doSomething();
}

public class StupidAction implements Action {

    @Autowired
    private MyService myService;  // 这是null的,因为StupidAction是在运行时实例化的。

    public void doSomething() {
        myService.changeSomething();
    }
}

// 伪代码
@RestController
@RequestMapping(path = "/")
public class WorkflowController {

    @GetMapping("")
    ResponseEntity someAPI() {    
        Action action = new SmartAction(); // 在运行时创建
        action.doSomething(); // NullPointerExc
    }
}
英文:

Consider an interface Action, and 2 implementing classes: StupidAction and SmartAction.

SmartAction needs to use another service, but because an Action is created at runtime, the @Autowired annotation doesn't work (the service is null).

Is it wrong to use the Strategy pattern with Spring? Is there a nice solution for this issue?

I could set "StupidAction" as a service as well, and not instantiate it. I could as well pass the autowired services to "doSomething" in method parameters. But both solutions are really dirty.

Some code example:

public interface Action {
	void doSomething();
}

public class StupidAction implements Action{

	@Autowired
	private MyService myService;  // THIS IS NULL. because StupidAction is instanciated at runtime.

	public void doSomething(){
		myService.changeSomething()
	}
}

//Pseudo code
@RestController
@RequestMapping(path = "/")
public class WorkflowController {

	@GetMapping("")
    ResponseEntity someAPI() {	
		Action action = new SmartAction(); //create on runtime
		action.doSomething(); //NullPointerExc
	}
}

答案1

得分: 0

你可以使用BeanFactory按名称动态从上下文中获取bean:

@Service
public class Service {

  @Autowired BeanFactory beanFactory;

  public void foo(){
    DynamicBean bean = beanFactory.getBean("bean_name", DynamicBean.class);
  }
}
英文:

You can get the bean from the context by name dynamically using BeanFactory:

@Service
public class Service {

  @Autowired BeanFactory beanFactory;

  public void foo(){
    DynamicBean bean = beanFactory.getBean("bean_name", DynamicBean.class)
  }
}

答案2

得分: -2

您可以从一个实现了ApplicationContextAware接口的Util服务中获取Bean

@Service
public class BeanUtility implements ApplicationContextAware {
    private static ApplicationContext context;

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

控制器实现如下

@RestController
@RequestMapping(path = "/")
public class WorkflowController {

    @Autowired
    BeanUtility beanUtility;

    @GetMapping("action")
    ResponseEntity someAPI() {
        MyService myService = BeanUtility.getMyBean(MyService.class); // 使用工具类获取所需的Bean
        Action action = new SmartAction(myService); // 基于构造函数的依赖注入
        return new ResponseEntity<String>(action.doSomething(), HttpStatus.CREATED);
    }
}

接下来是SmartAction类的实现如下

@Service
public class SmartAction implements Action{

    private MyService myService;

    public SmartAction(MyService myService){
        this.myService = myService;
    }

    @Override
    public String doSomething() {
        return "智能操作:" + myService.changeSomething();
    }
}
英文:

You can get the bean from a Util service which is ApplicationContextAware.

@Service
public class BeanUtility implements ApplicationContextAware {
    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
    public static &lt;T extends Object&gt; T getMyBean(Class&lt;T&gt; beanClass) {
        return context.getBean(beanClass);
    }
}

The controller implementation as follows:

@RestController
@RequestMapping(path = &quot;/&quot;)
public class WorkflowController {

    @Autowired
    BeanUtility beanUtility;

    @GetMapping(&quot;action&quot;)
    ResponseEntity someAPI() {
        MyService myService = BeanUtility.getMyBean(MyService.class); // use the util class to get a Bean of your choice
        Action action = new SmartAction(myService); // Constructor based DI
        return new ResponseEntity&lt;String&gt;(action.doSomething(), HttpStatus.CREATED);
    }
}

Followed by the implementation of SmartAction class as below:

@Service
public class SmartAction implements Action{

    private MyService myService;

    public SmartAction(MyService myService){
        this.myService = myService;
    }

    @Override
    public String doSomething() {
        return &quot;Smart action : &quot; + myService.changeSomething();
    }
}

huangapple
  • 本文由 发表于 2020年5月19日 20:22:53
  • 转载请务必保留本文链接:https://java.coder-hub.com/61890975.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定