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);
...
}
}