天天看点

在完全由Spring管理的环境中使用Spring的Context获取Bean实例

在大型的应用中,常常会有很灵活的需求,而在使用了框架之后,虽然可以大大提高开发的效率,但同时,也把我们框到一个架子中了。

下面先说一下我遇到的问题,事情大概是这样的:

@Component
@Scope("prototype")
public class Action1 implements Action{
..... 
}

@Component
@Scope("prototype")
public class Action2  implements Action{
..... 
}
@Component
@Scope("prototype")
public class Action3  implements Action{
..... 
}      
@Component
@Scope("prototype")
public class ActionFactory{
  @Autowired
  public Action1 action1;
  @Autowired
  public Action2 action2;
  @Autowired
  public Action3 action3;
  ....
  
  public Action getAction(String action){
    ...根据条件返回actionx
  }
}      
@Componment
public Server implements Runnable{
  @Autowired
  public ActionFactory actionFactory;
  
  public void run(){
    ....
    Action action = actionFactory.getAction("actionx's name");
    new Thread(new ThreadTool(action)).start();
    ....
  }
}      

这是整个应用的一部分,应用启动的时候,我需要启动这个Server线程,这个Server线程中持 有一个ActionFactory实例,在run方法中,每次用ActionFactory实例获取某个Action的实例。话是这样讲没错了。但仔细分析一下,整个应用中只会有一个Server实例,也就是虽然ActionFactory上注解了Scope为Prototype,但其实整个生命周期还是只有一个ActionFactory实例,然后就出问题了,由于这个ActionFactory中保持了每个Action的一个实例作为一个域,所以在server中调用ActionFactory#getAction的时候,对与一个Action名称,返回的是同一个Action实例。这就麻烦了,线程不安全了。想了一下,也没有其他的方法(有更好的方法请留言),只能在ActionFactory里手动获取各个Action,或者干脆手动获取ActionFactory,因为在ActionFactory上加了Scope=Prototype,所以获取一次ActionFactory,就会重新获取ActionFactory所持有的所有的Action对象,而各个Action上也加了Scope=Prototype,所以每个Action对象也是新的。显然没有在ActionFactory里手动获取各个Action这种方法好。可以不用每次想获取一种Action的实例的时候,还获取其他的Action实例了。

正题:

如何在完全由Spring管理的环境中使用Spring的Context获取Bean实例?如何在一个singleton bean要引用另外一个非singleton bean?

此部分来自参考中的博客中的内容。

看了一下Spring提供了两种方式,其实是一种,跟Struts2获取Context的方法一致

  • 实现ApplicationContextAware接口
@Service
public class SpringContextHelper implements ApplicationContextAware {

    private ApplicationContext context;
    
    //提供一个接口,获取容器中的Bean实例,根据名称获取
    public Object getBean(String beanName)
    {
        return context.getBean(beanName);
    }
    @Override
    public void setApplicationContext(ApplicationContext context)
            throws BeansException {
        this.context = context;
        
    }

}      
  • 继承实现了ApplicationContextAware接口的ApplicationObjectSupport抽象类
@Service
public class SpringContextHelper2 extends ApplicationObjectSupport {
    
    //提供一个接口,获取容器中的Bean实例,根据名称获取
    public Object getBean(String beanName)
    {
        return getApplicationContext().getBean(beanName);
    }
    
}