I stuck with a simple refactoring from plain Java to Spring. Application has a "Container" object which instantiates its parts at runtime. Let me explain with the code:
public class Container {
private List<RuntimeBean> runtimeBeans = new ArrayList<RuntimeBean>();
public void load() {
// repeated several times depending on external data/environment
RuntimeBean beanRuntime = createRuntimeBean();
runtimeBeans.add(beanRuntime);
}
public RuntimeBean createRuntimeBean() {
// should create bean which internally can have some
// spring annotations or in other words
// should be managed by spring
}
}
Basically, during load container asks some external system to provide him information about number and configuration of each RuntimeBean and then it create beans according to given spec.
The problem is: usually when we do in Spring
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
Container container = (Container) context.getBean("container");
our object is fully configured and have all dependencies injected. But in my case I have to instantiate some objects which also needs dependency injection after I execute load() method.
How can I achieve that?
I am using a Java-based config. I already tried making a factory for RuntimeBeans:
public class BeanRuntimeFactory {
#Bean
public RuntimeBean createRuntimeBean() {
return new RuntimeBean();
}
}
Expecting #Bean to work in so called 'lite' mode. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html Unfortunately, I found no difference with simply doing new RuntimeBean();
Here is a post with a similar issue: How to get beans created by FactoryBean spring managed?
There is also http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Configurable.html but it looks like a hammer in my case.
I also tried ApplicationContext.getBean("runtimeBean", args) where runtimeBean has a "Prototype" scope, but getBean is an awful solution.
Update 1
To be more concrete I am trying to refactor this class:
https://github.com/apache/lucene-solr/blob/trunk/solr/core/src/java/org/apache/solr/core/CoreContainer.java
#see #load() method and find "return create(cd, false);"
Update 2
I found quite interesting thing called "lookup method injection" in spring documentation:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-lookup-method-injection
And also an interesting jira ticket https://jira.spring.io/browse/SPR-5192 where Phil Webb says https://jira.spring.io/browse/SPR-5192?focusedCommentId=86051&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-86051 that javax.inject.Provider should be used here (it reminds me Guice).
Update 3
There is also http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.html
Update 4
The issue with all these 'lookup' methods is they don't support passing any arguments.. I also need to pass arguments as I would do with applicationContext.getBean("runtimeBean", arg1, arg2). Looks like it was fixed at some point with https://jira.spring.io/browse/SPR-7431
Update 5
Google Guice have a neat feature for it called AssistedInject. https://github.com/google/guice/wiki/AssistedInject
Looks like I found a solution. As I am using java based configuration it is even simpler than you can imagine. Alternative way in xml would be lookup-method, however only from spring version 4.1.X as it supports passing arguments to the method.
Here is a complete working example:
public class Container {
private List<RuntimeBean> runtimeBeans = new ArrayList<RuntimeBean>();
private RuntimeBeanFactory runtimeBeanFactory;
public void load() {
// repeated several times depending on external data/environment
runtimeBeans.add(createRuntimeBean("Some external info1"));
runtimeBeans.add(createRuntimeBean("Some external info2"));
}
public RuntimeBean createRuntimeBean(String info) {
// should create bean which internally can have some
// spring annotations or in other words
// should be managed by spring
return runtimeBeanFactory.createRuntimeBean(info);
}
public void setRuntimeBeanFactory(RuntimeBeanFactory runtimeBeanFactory) {
this.runtimeBeanFactory = runtimeBeanFactory;
}
}
public interface RuntimeBeanFactory {
RuntimeBean createRuntimeBean(String info);
}
//and finally
#Configuration
public class ApplicationConfiguration {
#Bean
Container container() {
Container container = new Container(beanToInject());
container.setBeanRuntimeFactory(runtimeBeanFactory());
return container;
}
// LOOK HOW IT IS SIMPLE IN THE JAVA CONFIGURATION
#Bean
public BeanRuntimeFactory runtimeBeanFactory() {
return new BeanRuntimeFactory() {
public RuntimeBean createRuntimeBean(String beanName) {
return runtimeBean(beanName);
}
};
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
RuntimeBean runtimeBean(String beanName) {
return new RuntimeBean(beanName);
}
}
class RuntimeBean {
#Autowired
Container container;
}
That's it.
Thanks everyone.
i think that your concept is wrong by using
RuntimeBean beanRuntime = createRuntimeBean();
you are bypassing Spring container and resorting to using regular java constructor therefore any annotations on factory method are ignored and this bean is never managed by Spring
here is the solution to create multiple prototype beans in one method, not pretty looking but should work, I autowired container in RuntimeBean as proof of autowiring shown in log also you can see in log that every bean is new instance of prototype when you run this .
'
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
Container container = (Container) context.getBean("container");
container.load();
}
}
#Component
class Container {
private List<RuntimeBean> runtimeBeans = new ArrayList<RuntimeBean>();
#Autowired
ApplicationContext context;
#Autowired
private ObjectFactory<RuntimeBean> myBeanFactory;
public void load() {
// repeated several times depending on external data/environment
for (int i = 0; i < 10; i++) {
// **************************************
// COMENTED OUT THE WRONG STUFFF
// RuntimeBean beanRuntime = context.getBean(RuntimeBean.class);
// createRuntimeBean();
//
// **************************************
RuntimeBean beanRuntime = myBeanFactory.getObject();
runtimeBeans.add(beanRuntime);
System.out.println(beanRuntime + " " + beanRuntime.container);
}
}
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public RuntimeBean createRuntimeBean() {
return new RuntimeBean();
}
}
// #Component
class RuntimeBean {
#Autowired
Container container;
} '
A simple approach:
#Component
public class RuntimeBeanBuilder {
#Autowired
private ApplicationContext applicationContext;
public MyObject load(String beanName, MyObject myObject) {
ConfigurableApplicationContext configContext = (ConfigurableApplicationContext) applicationContext;
SingletonBeanRegistry beanRegistry = configContext.getBeanFactory();
if (beanRegistry.containsSingleton(beanName)) {
return beanRegistry.getSingleton(beanName);
} else {
beanRegistry.registerSingleton(beanName, myObject);
return beanRegistry.getSingleton(beanName);
}
}
}
#Service
public MyService{
//inject your builder and create or load beans
#Autowired
private RuntimeBeanBuilder builder;
//do something
}
Instead of using SingletonBeanRegistry you can use this:
BeanFactory beanFactory = configContext.getBeanFactory();
Anyway SingletonBeanBuilder extends HierarchicalBeanFactory and HierarchicalBeanFactory extends BeanFactory
You don't need the Container because all of the runtime objects should be created, held and managed by ApplicationContext. Think about a web application, they are much the same. Each request contains external data/environment info as you mentioned above. What you need is a prototype/request scoped bean like ExternalData or EnvironmentInfo which can read and hold runtime data through a static way, let's say a static factory method.
<bean id="externalData" class="ExternalData"
factory-method="read" scope="prototype"></bean>
<bean id="environmentInfo" class="EnvironmentInfo"
factory-method="read" scope="prototype/singleton"></bean>
<bean class="RuntimeBean" scope="prototype">
<property name="externalData" ref="externalData">
<property name="environmentInfo" ref="environmentInfo">
</bean>
If you do need a container to save the runtime objects, code should be
class Container {
List list;
ApplicationContext context;//injected by spring if Container is not a prototype bean
public void load() {// no loop inside, each time call load() will load a runtime object
RuntimeBean bean = context.getBean(RuntimeBean.class); // see official doc
list.add(bean);// do whatever
}
}
Official doc Singleton beans with prototype-bean dependencies.
It is possible to register beans dynamically by using BeanFactoryPostProcesor. Here you can do that while the application is booting (spring's application context has been initialized). You can not register beans latest, but on the other hand, you can make use of dependency injection for your beans, as they become "true" Spring beans.
public class DynamicBeansRegistar implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (! (beanFactory instanceof BeanDefinitionRegistry)) {
throw new RuntimeException("BeanFactory is not instance of BeanDefinitionRegistry");
}
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// here you can fire your logic to get definition for your beans at runtime and
// then register all beans you need (possibly inside a loop)
BeanDefinition dynamicBean = BeanDefinitionBuilder.
.rootBeanDefinition(TheClassOfYourDynamicBean.class) // here you define the class
.setScope(BeanDefinition.SCOPE_SINGLETON)
.addDependsOn("someOtherBean") // make sure all other needed beans are initialized
// you can set factory method, constructor args using other methods of this builder
.getBeanDefinition();
registry.registerBeanDefinition("your.bean.name", dynamicBean);
}
#Component
class SomeOtherClass {
// NOTE: it is possible to autowire the bean
#Autowired
private TheClassOfYourDynamicBean myDynamicBean;
}
As presented above, you can still utilize Spring's Dependency Injection, because the post processor works on the actual Application Context.
Related
I am new at spring MVC framework and i am currently working in a web application that uses a session scoped bean to control some data flow.
I can access these beans in my application context using #Autowired annotation without any problem in the controllers. The problem comes when I use a class in service layer that does not have any request mapping (#RequestMapping, #GetMapping nor #PostMapping) annotation.
When I try to access the application context directly or using #Autowired or even the #Resource annotation the bean has a null value.
I have a configuration class as follow:
#Configuration
#EnableAspectJAutoProxy
#EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class, basePackages = "com.quantumx.nitididea.NITIDideaweb.repository")
public class AppConfig implements WebMvcConfigurer {
#Bean (name = "lastTemplate")
#SessionScope
public LastTemplate getlastTemplate() {
return new LastTemplate();
}
//Some extra code
}
The POJO class is defined as :
public class LastTemplate {
private Integer lastId;
public LastTemplate(){
}
public Integer getLastId() {
return lastId;
}
public void setLastId(Integer lastId) {
this.lastId = lastId;
}
}
The I have a Test class that is annotated as service and does not have any request mapping annotated method:
//#Controller
#Service
public class Test {
// #Autowired
// private ApplicationContext context;
// #Autowired
#Resource(name = "lastTemplate")
public LastTemplate lastTemplate;
// #Autowired
// public void setLastTemplate(LastTemplate lastTemplate) {
// this.lastTemplate = lastTemplate;
// }
public Test() {
}
// #RequestMapping("/test")
public String testing() {
// TemplateForma last = (TemplateForma) context.getBean("lastInsertedTemplate");
// System.out.println(last);
System.out.println(lastTemplate);
// System.out.println(context.containsBean("lastTemplate"));
// System.out.println(context.getBean("lastTemplate"));
System.out.println("Testing complete");
return "Exit from testing method";
// return "/Messages/Success";
}
}
As you can see, there is a lot of commented code to show all the ways i have been trying to access my application context, using an Application context dependency, autowiring, declaring a resource and trying with a request mapping. The bean is null if no controller annotation and request mapping method is used and throws a java null pointer exception when I use the context getBean() methods.
Finally I just test my class in a controller that i have in my app:
#RequestMapping("/all")
public String showAll(Model model) {
Test test = new Test();
test.testing();
return "/Administrator/test";
}
Worth to mention that I also tried to change the scope of the bean to a Application scope and singleton, but it not worked. How can access my application context in a service class without mapping a request via controller?
Worth to mention that I also tried to change the scope of the bean to a Application scope and singleton, but it not worked
It should have worked in this case.
How can access my application context in a service class without mapping a request via controller?
Try one of these :-
#Autowired private ApplicationContext appContext;
OR
Implement ApplicationContextAware interface in the class where you want to access it.
Edit:
If you still want to access ApplicationContext from non spring managed class. Here is the link to article which shows how it can be achieved.
This page gives an example to get spring application context object with in non spring managed classes as well
What worked for me is that session scoped bean had to be removed in the application configuration declaration and moved to the POJO definition as follows:
#Component
#SessionScope
public class LastTemplate {
private Integer lastId;
public LastTemplate(){
}
public Integer getLastId() {
return lastId;
}
public void setLastId(Integer lastId) {
this.lastId = lastId;
}
}
The I just call the bean using #Autowired annotation.
I have a spring boot application with cucumber. I would like to perform certain events within the test BEFORE the start-SmartLifecycle event of the beans is called.
Given Something that needs to happen before beans are started
And Beans start up now
Then Life is good
Is there any way to achieve this?
By default, it looks like Spring initializes and starts all the beans before any Cucumber statements are executed.
Example:
class Context {
#Bean
SomeBean someBean() { return new SomeBean(); }
}
class SomeBean implements SmartLifecycle {
#Override
void start() {
// some meaningful work that depends on setup that needs to be done beforehand
}
// rest of interface implementation
}
Cucumber definitions file:
#ContextConfiguration(classes = Context.class)
class CucumberFeatures {
#Autowired
private SomeBean someBean;
#Given("Something that needs to happen before beans are started")
public void something() {
// ...
}
#Given("Beans start up now")
public void beansStarted() {
// This should start beans in their defined order now
}
#Then("Life is good")
public void lifeIsGood() { ... }
}
You can't test a dependency injection container while using that same container to inject dependencies into your test. Injecting dependencies requires the application context to have been refreshed already.
So you have to create an instance of the ApplicationContext manually and manage it's life-cycle yourself.
I have a component defined with prototype scope. I want to use that component in my service class. I want spring to provide me a new instance of that Bean everytime I call for it.
Component Class:
#Getter
#Setter
#Component
#Scope("prototype")
public class ProtoTypeBean {
//.. Field variables
}
Service Class:
#AllArgsConstructor
#Service
public class ServiceClass {
ProtoTypeBean prototypeBean;
ArrayList<ProtoTypeBean> prototypeBeans;
public void demoMethod(ArrayList<String> someArrayList) {
for(var singleString: someArrayList) {
prototypeBean.setFieldValue(singleString);
prototypeBeans.add(prototypeBean);
}
System.out.println(prototypeBeans.toString());
}
}
By using this configuration, I am getting the same instance of ProtoTypeBean in my prototypeBeans ArrayList. The question is, how would I make Spring understand to give me a new instance of prototypeBean every time I am calling it into the foreach loop?
I found I can use ApplicationContext.getBean() to get a new instance of the Bean in foreach loop but I also heard that it's a bad practice. So kindly help me with the best practice.
Use an ObjectProvider to lazily get the result you want. However the first prototype scoped bean will not be represented in the list of beans as, well they are prototype scoped.
#AllArgsConstructor
#Service
public class ServiceClass {
private final ObjectProvider<ProtoTypeBean> provider;
public void demoMethod(ArrayList<String> someArrayList) {
PrototypeBean pb = provider.getIfUnique();
for(var singleString: someArrayList) {
pb.setFieldValue(singleString);
pb.add(prototypeBean);
}
System.out.println(prototypeBean.toString());
}
}
Also if you don't need all the dependency injection, proxy creation etc. for your object then why bother. There is nothing wrong with just the new keyword in a Spring application. Not everything has to be managed by Spring.
Set up your prototype bean similar to this:
#Getter
#Setter
#Component
#Scope("prototype")
public class ProtoTypeBean {
final private String param;
public ProtoTypeBean(final String p) {
this.param = p;
}
}
Now, in your service class use a BeanFactory to create the beans for you:
#Service
#AllArgsConstructor
public class ServiceClass {
private final BeanFactory factory;
private List<ProtoTypeBean> prototypeBeans;
#Autowired
public ServiceClass(final BeanFactory f) {
this.factory = f;
}
public void demoMethod(List<String> someArrayList) {
this.prototypeBeans = someArrayList
.stream()
.map(param -> factory.getBean(ProtoTypeBean.class, param))
.collect(Collectors.toList());
}
}
I came across this issue recently. I am sure there must be a better way than mine, but this is how I did it:
public class ServiceClass {
ArrayList<ProtoTypeBean> prototypeBeans = new ArrayList<>();
#Autowired
ApplicationContext ctx;
public void demoMethod(ArrayList<String> someArrayList) {
for(var singleString: someArrayList) {
//magic is in below line.. getting a bean from ApplicatioContext.
ProtoTypeBean prototypeBean= ctx.getBean("protoTypeBean"); //Or ctx.getBean(ProtoTypeBean.class);
prototypeBean.setFieldValue(qBean.getFieldValue());
prototypeBeans.add(prototypeBean);
}
System.out.println(prototypeBeans.toString());
}
This way, Spring container always give you a new instance. And it is totally managed by Spring container.
The way you tried it, I tried that as well, but it would always inject one instance at the time of autowiring, hence defeating the purpose of prototyping.
You could have gone the route of using new Keyword. But then that is just regular Java instantiation and I think that new instance is not managed by Spring because it is annotated with #Component instead of #Configuration. I could be wrong here though.
As the question suggests, how do you Autowire a class with non SpringBoot managed class as constructor args.
The following is a code block illustrating this:
#Component
class Prototype
{
#Autowired
private Repository repository;
private NonSpringBootManagedBean bean;
Prototype(NonSpringBootManagedBean bean)
{
this.bean = bean;
}
}
#Component
class PrototypeClient
{
#Autowired
private ApplicationContext context;
private void createNewPrototype(NonSpringBootManagedBean bean)
{
// This throws an error saying no bean of type NonSpringBootManangedBean found
Prototype prototype = context.getBean(Prototype.class, bean);
}
}
The reason I am using ApplicationContext to obtain an instance of Prototype instead of using #Autowired is because I need a new instance of Prototype within the method createNewPrototype() every time it's invoked and not a singleton instance (Also, please advise if this way obtaining a new instance is incorrect).
Update:
As others have stated to move my creation of bean to a Java configuration class and adding method annotated by #Bean and instantiating the NonSpringBootManagedBean in the #Bean method. But I think this is not possible as this NonSpringBootManagedBean is passed by caller of PrototypeClient.createNewPrototype().
Update
I have updated my above code example with a more clarity. Please refer this now.
#Component
class Prototype
{
#Autowired
private Repository repository;
// Here Session is part of javx.websocket package and cannot be added as part of
// Java configuration class with a #Bean annotation
// In this case how can I use constructor injection?
private Session session;
Prototype(Session session)
{
this.session = session;
}
}
#Component
class PrototypeClient
{
#Autowired
private ApplicationContext context;
private void createNewPrototype(Session session)
{
Prototype prototype = context.getBean(Prototype.class, session);
}
}
#ServerEndpoint(value = "/resources")
class WebSocketController
{
private PrototypeClient client = ApplicationContext.getBean(PrototypeClient.class);
#OnMessage
void handleMessage(Session session, String message)
{
client.createNewPrototype(session);
}
}
Did you know that you can change your bean scope to be a prototype reference instead of a singleton. That way you can scope a single bean definition to any number of object instances.
https://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch04s04.html
private NonSpringBootManagedBean bean = new NonSpringBootManagedBean();
#Bean
public Prototype getPrototype(){
return new Prototype(bean);
}
Spring can not Autowire an Object if it is not aware of it. Some where there need to be #Component or #Bean or some other annotation like #Service etc to tell spring to manage the instance .
Also it is suggested that if you are using a private variable in Autowire it should be part of constructor(for constructor injection ) or a setter method must be provided(setter injection)
To solve your error : you can create a java config class and place it in you base pkg (same as #SpringBootApplication or add #ComponentScan("pkg in which config is present") on class with #SpringBootApplication)
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
#Configuration
public class myconfig {
#Bean
public NonSpringBootManagedBean nonSpringBootManagedBean()
{
return new NonSpringBootManagedBean();
}
}
Define a bean with scope prototype
That is each time injected as new instance.
In SpringBoot you can use the annotation #Scope("prototype") to your bean class Prototype.
#Component
#Scope("prototype")
class Prototype {
#Autowired
private Repository repository;
private NonSpringBootManagedBean bean;
Prototype() {
// you can only modify this 'NonSpringBootManagedBean' later
// because Spring calls constructor without knowing NonSpringBootManagedBean
this.bean = new NonSpringBootManagedBean();
// do something with 'repository' because its defined
}
public void setNonSpringBootManagedBean(NonSpringBootManagedBean bean) {
this.bean = bean;
}
}
Use instances of this bean
Via injection (e.g. #Autowired to constructor) you can use different instances of this prototypical bean within other beans.
#Component
class PrototypeClient {
// ApplicationContext still used?
#Autowired
private ApplicationContext context;
private Prototype prototypeInstance;
#Autowired // injects the new instance of Prototype
public PrototypeClient(Prototype p)
this.prototypeInstance = p;
// here you can change the NSBMB
modifyPrototype();
}
private void modifyPrototype(NonSpringBootManagedBean bean) {
this.prototypeInstance.setNonSpringBootManagedBean( new NonSpringBootManagedBean() );
}
}
Why is your exception thrown?
no bean of type NonSpringBootManangedBean found
Spring complains when trying to instantiate the bean of type Prototype
Prototype prototype = context.getBean(Prototype.class, bean);
because for calling its constructor it needs to pass an argument of type NonSpringBootManagedBean. Since all this bean-instantiating is done internally by Spring(Boot), you can not intercept and tell Spring: "Hey, use this bean of class NonSpringBootManagedBean" like you tried in method createNewPrototype(NonSpringBootManagedBean bean).
Why could'nt the NonSpringBootManagedBean be managed as bean by Spring(Boot)?
Autowiring in SpringBoot is a way of dependency-injection. This means a bean has been previously instantiated by SpringBoot, automatically at startup (when Spring boots). And this bean is now injected as dependency into another bean, etc. because this other bean depends on it.
If you tell us some more background, we could possibly bring light into your situation. This can be some answers to:
What is NonSpringBootManagedBean and why is it no managed bean?
What is Prototype and for which purpose does it use NonSpringBootManagedBean?
What is PrototypeClient and why does it create its own Prototype ?
I am not sure if I have understood the relationship and purpose between your objects/classes.
The user story is like this:
We have exposed some APIs through library jars which use the Spring Boot auto-configure mechanism. The APIs need some glue logic during initialization, so we put them under #PostConstruct block of some #Configurations and register them as auto-configured.
The user code is based on #SpringBootApplication, while they prefer to use #ComponentScan to define beans instead auto-configure.
So the issue comes, Spring always tries to load the beans defined by #ComponentScan first, then those auto-configured beans. So if any user bean relies on the API that not been initialized, it sure will fail.
It seems there's no way to define the bean order when mixing the auto-configured and component-scanned beans. The #Order, #AutoConfigureOrder, #AutoConfigureAfter, #AutoConfigureBefore annotation and Ordered interface only work among all auto configured beans.
Of course if user uses auto-configure for their beans too, it will work without problem. But from user's perspective, #ComponentScan looks a more natural and easier way, especially #SpringBootApplication implies the #ComponentScan of current java package.
Our current workaround is to eager load those API initialization configures at a very-early stage. For web context, it's ServletContextInitializer.onStartup(), and for other generic context, it's LoadTimeWeaverAware's #PostConstruct.
#Configuration
#ConditionalOnWebApplication
#AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class EagerInitWebContextInitializer implements ServletContextInitializer, PriorityOrdered
{
#Autowired
private ApplicationContext appContext;
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
String[] beanNames = appContext.getBeanNamesForAnnotation(EagerInitializer.class);
if (beanNames != null) {
// pre-load all eager initializers
for (String name : beanNames) {
appContext.getBean(name);
}
}
}
#Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
#Configuration
#ConditionalOnNotWebApplication
#AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class EagerInitGenericContextInitializer implements LoadTimeWeaverAware, PriorityOrdered
{
#Autowired
private ApplicationContext appContext;
#PostConstruct
protected void init() {
String[] beanNames = appContext.getBeanNamesForAnnotation(EagerInitializer.class);
if (beanNames != null) {
// pre-load all eager initializers
for (String name : beanNames) {
appContext.getBean(name);
}
}
}
#Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
#Override
public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
// does nothing
}
}
This actually works well. But just wondering is there any better way to achieve this or whether future Spring version can provide a similar systematic way?