@ 自动有线和静态方法

我有 @Autowired服务,必须从一个静态方法内使用。我知道这是错误的,但我不能改变目前的设计,因为它将需要大量的工作,所以我需要一些简单的黑客为此。我不能改变 randomMethod()为非静态的,我需要使用这个自动连接的 bean。有什么线索吗?

@Service
public class Foo {
public int doStuff() {
return 1;
}
}


public class Boo {
@Autowired
Foo foo;


public static void randomMethod() {
foo.doStuff();
}
}
162920 次浏览

您可以使用 @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 处理 Boo的实例之前使用 randomMethod(),那么这个解决方案将会失败。

这很糟糕,但是你可以通过使用 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;
}
}

您必须通过静态应用程序上下文访问器方法来解决这个问题:

@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();
}


}

你可以通过下面的一个解决方案来做到这一点:

使用构造函数@Autowired

这种方法将构造需要一些 bean 作为构造函数参数的 bean。在构造函数代码中,设置静态字段,并将获得的值作为构造函数执行的参数。样本:

@Component
public class Boo {


private static Foo foo;


@Autowired
public Boo(Foo foo) {
Boo.foo = foo;
}


public static void randomMethod() {
foo.doStuff();
}
}

使用@PostConstruction 将值传递给 static 字段

这里的想法是在 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();
}
}

使用 AppContext。确保在上下文文件中创建了一个 bean。

private final static Foo foo = AppContext.getApplicationContext().getBean(Foo.class);


public static void randomMethod() {
foo.doStuff();
}

这是在 @ Pavel 的回答的基础上构建的,以解决从静态 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将成为代码中的一个争论点,因为它是同步的。如果您的应用程序是高度并行的(例如: 高流量站点的后端) ,这可能不是一个好的解决方案。

创建静态上下文的最简单方法自然是在应用程序启动时。这将防止需要带有附加类的非自然实现。

@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;
}
}

然后,在需要静态访问 bean 的任何地方,都可以使用 ApplicationContext 获取类的实例。

public class Boo {
public static void randomMethod() {
MyApplication.getAppContext()
.getBean(Foo.class).doStuff();
}
}

问候。