Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 402 Vote(s) - 3.45 Average
  • 1
  • 2
  • 3
  • 4
  • 5
@Autowired and static method

#1
I have `@Autowired` service which has to be used from within a static method. I know this is wrong but I cannot change the current design as it would require a lot of work, so I need some simple hack for that. I can't change `randomMethod()` to be non-static and I need to use this autowired bean. Any clues how to do that?

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

public class Boo {
@Autowired
Foo foo;

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

Reply

#2
What you can do is `@Autowired` a setter method and have it set a new static field.

public class Boo {
@Autowired
Foo foo;

static Foo staticFoo;

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

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

When the bean gets processed, Spring will inject a `Foo` implementation instance into the instance field `foo`. It will then also inject the same `Foo` instance into the `setStaticFoo()` argument list, which will be used to set the static field.

This is a terrible workaround and will fail if you try to use `randomMethod()` before Spring has processed an instance of `Boo`.
Reply

#3
You can do this by following one of the solutions:

## Using constructor @Autowired ##

This approach will construct the bean requiring some beans as constructor parameters. Within the constructor code you set the static field with the value got as parameter for constructor execution. Sample:

@Component
public class Boo {

private static Foo foo;

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

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

## Using @PostConstruct to hand value over to static field ##

The idea here is to hand over a bean to a static field after bean is configured by spring.

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

#4
You have to workaround this via static application context accessor approach:

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

}

Then you can access bean instances in a static manner.

public class Boo {

public static void randomMethod() {
StaticContextAccessor.getBean(Foo.class).doStuff();
}

}
Reply

#5
Use AppContext. Make sure you create a bean in your context file.



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

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

#6
This builds upon [@Pavel's answer][1], to solve the possibility of Spring context not being initialized when accessing from the static getBean method:

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

The important piece here is the `initContext` method. It ensures that the context will always get initialized. But, do note that `initContext` will be a point of contention in your code as it is synchronized. If your application is heavily parallelized (for eg: the backend of a high traffic site), this might not be a good solution for you.

[1]:

[To see links please register here]

Reply

#7
The easiest way to create a static context is naturally, when the application starts up. This will prevent the need for an unnatural implementation with an additional class.

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

Then, anywhere you need to access a bean statically, you can use the ApplicationContext to get the instance of the class.

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

Regards..
Reply

#8
It is not the best but you can get the bean by using the `ApplicationContextAware` interface. Something like :

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



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through