我有@Autowired
服务,必须在静态方法中使用。我知道这是错的,但我不能改变当前的设计,因为它需要大量的工作,所以我需要一些简单的黑客。我无法将randomMethod()
更改为非静态,我需要使用此自动装配的bean。有什么线索怎么做?
@Service
public class Foo {
public int doStuff() {
return 1;
}
}
public class Boo {
@Autowired
Foo foo;
public static void randomMethod() {
foo.doStuff();
}
}
答案 0 :(得分:121)
您可以通过以下解决方案之一来完成此操作:
这种方法将构造需要一些bean作为构造函数参数的bean。在构造函数代码中,您可以使用值got作为构造函数执行的参数来设置静态字段。样品:
@Component
public class Boo {
private static Foo foo;
@Autowired
public Boo(Foo foo) {
Boo.foo = foo;
}
public static void randomMethod() {
foo.doStuff();
}
}
这里的想法是在bean由spring配置之后将bean移交给静态字段。
@Component
public class Boo {
private static Foo foo;
@Autowired
private Foo tFoo;
@PostConstruct
public void init() {
Boo.foo = tFoo;
}
public static void randomMethod() {
foo.doStuff();
}
}
答案 1 :(得分:38)
您必须通过静态应用程序上下文访问器方法解决此问题:
@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);
}
}
然后您可以以静态方式访问bean实例。
public class Boo {
public static void randomMethod() {
StaticContextAccessor.getBean(Foo.class).doStuff();
}
}
答案 2 :(得分:6)
你可以做的是@Autowired
一个setter方法,并让它设置一个新的静态字段。
public class Boo {
@Autowired
Foo foo;
static Foo staticFoo;
@Autowired
public void setStaticFoo(Foo foo) {
Boo.staticFoo = foo;
}
public static void randomMethod() {
staticFoo.doStuff();
}
}
当处理bean时,Spring会将Foo
实现实例注入实例字段foo
。然后它还会将相同的Foo
实例注入setStaticFoo()
参数列表,该列表将用于设置静态字段。
这是一个糟糕的解决方法,如果在Spring处理randomMethod()
的实例之前尝试使用Boo
,则会失败。
答案 3 :(得分:3)
很糟糕但你可以使用ApplicationContextAware
接口获取bean。类似的东西:
public class Boo implements ApplicationContextAware {
private static ApplicationContext appContext;
@Autowired
Foo foo;
public static void randomMethod() {
Foo fooInstance = appContext.getBean(Foo.class);
fooInstance.doStuff();
}
@Override
public void setApplicationContext(ApplicationContext appContext) {
Boo.appContext = appContext;
}
}
答案 4 :(得分:1)
创建静态上下文的最简单方法自然是在应用程序启动时。这将防止需要使用附加类进行不自然的实现。
sudo apt-get update
sudo apt install python3-pip
然后,在任何需要静态访问 bean 的地方,都可以使用 ApplicationContext 来获取类的实例。
@SpringBootApplication
public class MyApplication {
private static ApplicationContext appContext;
public static void main(String[] args) {
appContext = SpringApplication.run(MyApplication.class, args);
}
public static ApplicationContext getAppContext() {
return appContext;
}
}
问候..
答案 5 :(得分:0)
这是基于@Pavel's answer的,以解决从静态getBean方法访问时Spring上下文未初始化的可能性:
@Component
public class Spring {
private static final Logger LOG = LoggerFactory.getLogger (Spring.class);
private static Spring spring;
@Autowired
private ApplicationContext context;
@PostConstruct
public void registerInstance () {
spring = this;
}
private Spring (ApplicationContext context) {
this.context = context;
}
private static synchronized void initContext () {
if (spring == null) {
LOG.info ("Initializing Spring Context...");
ApplicationContext context = new AnnotationConfigApplicationContext (io.zeniq.spring.BaseConfig.class);
spring = new Spring (context);
}
}
public static <T> T getBean(String name, Class<T> className) throws BeansException {
initContext();
return spring.context.getBean(name, className);
}
public static <T> T getBean(Class<T> className) throws BeansException {
initContext();
return spring.context.getBean(className);
}
public static AutowireCapableBeanFactory getBeanFactory() throws IllegalStateException {
initContext();
return spring.context.getAutowireCapableBeanFactory ();
}
}
这里最重要的是initContext
方法。它确保上下文将始终被初始化。但是,请注意,initContext
将成为代码中争用点,因为它已同步。如果您的应用程序是高度并行化的(例如:高流量站点的后端),那么这可能不是一个好的解决方案。
答案 6 :(得分:-2)
使用AppContext。确保在上下文文件中创建一个bean。
private final static Foo foo = AppContext.getApplicationContext().getBean(Foo.class);
public static void randomMethod() {
foo.doStuff();
}