各种情境下获得Spring Application Context

1. How to get Spring application context

最开始我想写一个public static void main, 去直接run一个bean的方法,所以我需要给它提供一个spring application context。总结有以下几种方法:

1.1 ClassPathXmlApplicationContext

但其实我没有config.xml文件,所以不行

@Component
public class Main {
	public static void main(String[] args) {
        ApplicationContext context = 
            new ClassPathXmlApplicationContext("META-INF/config.xml");

        Main p = context.getBean(Main.class); // using this instead of 'new Main()'
        p.start(args);
    }
    
    @Autowired
    private MyBean myBean;
    private void start(String[] args) {
        System.out.println("my beans method: " + myBean.getStr());
    }
}

@Service 
public class MyBean {
    public String getStr() {
        return "string";
    }
}

1.2 Autowired ApplicationContext

我用这个还是不行,applicationContext是null,猜测是因为我没有也不需要@SpringBootApplication。

@SpringBootApplication
public class Application implements CommandLineRunner {

    @Autowired
    private ApplicationContext applicationContext;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println(applicationContext.getDisplayName());
        System.out.println(applicationContext.getId());

        MyBean myBean = applicationContext.getBean(MyBean.class);
        System.out.println(myBean.getApplicationId());
    }
}

1.3 ApplicationContextAware

不过仍然不是我需要的,因为我是想独立于整个spring项目写一个static main class,单独运行。所以需要static方法。

When Spring instantiates beans, it looks for ApplicationContextAware implementations, If they are found, the setApplicationContext() methods will be invoked.

In this way, Spring is setting current applicationcontext.

@Component
public class ApplicationContextProvider implements ApplicationContextAware {

    private ApplicationContext applicationContext;

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

 public ApplicationContext getContext() {
        return applicationContext;
    }
}

Code snippet from Spring’s source code:

private void invokeAwareInterfaces(Object bean) {
        .....
        .....
 if (bean instanceof ApplicationContextAware) {                
  ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
   }
}

Once you get the reference to Application context, you get fetch the bean whichever you want by using getBean().

1.4 Access Bean in Static Method: Implement InitializingBean or use @PostConstruct

这个有点像我需要的,但是没有提供Spring Application Context这个大环境的样子,public static main仍然不能正确获得bean

My approach is for the bean one wishes to access to implement InitializingBean or use @PostConstruct, and containing a static reference to itself.

@Service
public class MyBean implements InitializingBean {
    private static MyBean instance;

    @Override
    public void afterPropertiesSet() throws Exception {
        instance = this;
    }

    public static MyBean get() {
        return instance;
    }
}

Usage in your static class would therefore just be:

MyBean myBean = MyBean.get();

他并没有给出@PostConstruct的方法,但我在其它地方看到了
@PostConstruct get Spring Application Context

当然,同理,不是我需要的,因为我需要的不是整个项目中access spring context,而是需要在一个独立的static main class里构造一个context给我的某个bean用。

@Component
public class StaticContextAccessor {

    private static StaticContextAccessor instance;

    @Autowired
    private ApplicationContext applicationContext;

    @PostConstruct
    public void registerInstance() {
        instance = this;
    }

    public static <T> T getBean(Class<T> clazz) {
        return instance.applicationContext.getBean(clazz);
    }

}

1.5 ContextLoader.getCurrentWebApplicationContext

同样的stack Overflow链接,不同的回答,但是感觉我需要的不是WebApplicationContext??没有尝试这个,应该是不行的,见代码里注释有提到,“For Spring boot application”,
用的不是:

 WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();

而是:

//for spring boot apps
ApplicationContext context = SpringApplication.run(Application.class, args)

Define your bean using xml configuration (old school):

<bean id="someBean1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName"><value>${db.driver}</value></property>     
    <property name="url"><value>${db.url}</value></property>
    <property name="username"><value>${db.username_seg}</value></property>
    <property name="password"><value>${db.password_seg}</value></property>
</bean> 

Or define it with java instead xml (new school)

@Bean(name = "someBean2")
public MySpringComponent loadSomeSpringComponent() {

  MySpringComponent bean = new MySpringComponent();
  bean.setSomeProperty("1.0.2");
  return bean;
}

Accessing spring bean in static method

import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;

public class TestUtils {

  public static void getBeansFromSpringContext() {
    WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
    //for spring boot apps
    //ApplicationContext context = SpringApplication.run(Application.class, args)
    DataSource datasource  = (DataSource)context.getBean("someBean1");
    MySpringComponent springBean  = (MySpringComponent)context.getBean("someBean2");
  }
}   

1.6 Run SpringBootApplicatoin

https://stackoverflow.com/questions/31899272/spring-autowired-not-working-with-applicationcontext)
https://stackoverflow.com/questions/31399924/spring-boot-autowired-in-main-class-is-getting-null
https://stackoverflow.com/questions/28615285/manually-loading-application-context-to-write-getbean-in-spring-boot-applicati

这三个链接给了我灵感,总的来说,还是要run一下application

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(Application.class, args);
      	...
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值