Spring application context available everywhere. - Set the application context in a static variable

Rather than "trying" to inject or pass generic Spring beans wherever needed, especially in a non-Spring managed class, is it good practice to set the Spring application context in a static variable to get it from anywhere? This makes it possible, for example, to get a single one-off JdbcTemplate in a non-Spring managed class (or a Hibernate factory session). Is there a good reason not to do this?

eg:

@Component
public class SpringContext implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContext.applicationContext = applicationContext;
    }

    public static JdbcTemplate getJdbcTemplate() {
        return applicationContext.getBean(JdbcTemplate.class);
    }

    public static SessionFactory getSessionFactory() {
        return applicationContext.getBean(SessionFactory.class);
    }

    public static Session getCurrentSession() {
        SessionFactory sf = applicationContext.getBean(SessionFactory.class);
        return sf.getCurrentSession();
    }

}

      

In another class not managed by Spring:

public class MyClass {

    public Integer method1() {
        String sql = "select 1 from dual";
        Integer n = SpringContext.getJdbcTemplate().queryForObject(sql, Integer.class);
        return n;
    }

}

      

+3


source to share


3 answers


This seems to contradict Spring's intended use and the concept of dependency injection. While you can do this, I think the best solution is to insert those beans where needed.



I find it prudent to initialize the context once, refer to the "root" bean, and that the bean will essentially be an application and reference (directly or indirectly) all other beans in the system.

+1


source


What you want is a singleton, that is, a class in which only one instance exists, which is also a Spring managed singleton (singleton scoped bean). I found a very elegant solution to this problem when I used Spring a few years ago. Let's say your singleton looks like this:

public final class MySingletonClass{
  private static MySingletonClass instance = new MySingletonClass();

  public static MySingletonClass getInstance(){
    return instance;
  }

  @Autowired
  private JdbcTemplate jdbcTemplate;
  @Autowired
  private SessionFactory sessionFactory;
  @Autowired
  private DataSource dataSource;

  // getters and other methods omitted
}

      

You can make Spring manage this singleton by simply adding the following line to your application context:

<bean class="com.mypackage.MySingletonClass" factory-method="getInstance"/>

      



Your singleton will now have all of the above Spring managed objects automatically (if available in the context) and can be used by any non-Spring managed class:

class MyClass {
  // Can only be called after Spring initialized.
  void doSomething() {
    DataSource ds = MySingletonClass.getInstance().getDataSource();
    // ...
  }
}

      

Any object you think should be a real single-line can use the pattern described above. This preserves Spring's approach to object lifecycle management and dependency injection while keeping a true singleton object safe. Moreover, the singleton will be Spring managed, so all its dependencies will be wired correctly or the application will fail when the application starts.

0


source


If you have a web application, you can use a class org.springframework.web.context.support.WebApplicationContextUtils

from Spring. It provides a method to get the root WebApplicationContext.

0


source







All Articles