How can I create the spring bean after all other beans? - spring

For example, I have 3 beans in my spring configuration: A, B, C. And I want to create bean B and C as usual. And than (when all others beans were created) I want to ask spring to create bean A.
Any suggestion ?
Thanks.

Spring framework triggers a ContextRefreshedEvent once the contexts has been fully refreshed and all the configured beans have been created.
You could try to create a listener to catch that event and initialise bean A.
#Component
public class ContextRefreshedEventListener implements
ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
// Init your bean here
}
}

You should try #DependsOn adnotation
For example
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />

I know it's not really a bean ordering answer, but maybe you can achieve your goal with a #PostConstruct method that will be called just after a bean is constructed, dependencies are injected and all properties are set.
best nas

Easier way to do this would be using #Lazy annotation to your bean. This makes your bean do not get initialized eagerly during context initialization. In simple words,your bean will get created when you ask for it, not before.
#Bean
#Lazy
public A beanA() {
//some code here
}

Related

Mocked object in a whole spring Batch test

I want to test a whole Spring Batch but Ihave a problem. I have a service to delete rows in a DB and in a LDAP.
For the BD I have implemented a H2 in-memory database so no problems.
For the LDAP it's more difficult to have a in-memory LDAP so I want to fake the DAO LDapRepository calling method "delete" (LDapRepository is the interface and LDapRepositoryImpl annotated by #Repository the implementation)
So I tried to inject a mock in my configuration but it doesn't work.
The test fails with a null pointer exception when I try to make the fake call ldapRepository.removePerson (so ldapRepository is not correctly injected).
How is it possible to substitute the bean LDapRepository in my configuration ?
Here's the test code :
#ContextConfiguration(locations = {"classpath:purge/job-test.xml"})
public class PurgeJobTest {
#Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
#InjectMocks
#Qualifier(value = "ldapRepositoryImpl")
private LdapRepository ldapRepository;
#Test
public void testExampleJob() throws Exception {
Mockito.doNothing().when(ldapRepository.removePerson(any(String.class)));
JobParameters jobParameters = new JobParametersBuilder()
.addString("fichierJob", "/purge/job-test.xml")
.addString("nomJob", "purgeJob").toJobParameters();
JobExecution exec =jobLauncherTestUtils.launchJob(jobParameters);
assertEquals(BatchStatus.COMPLETED, exec.getStatus());
}
}
OK so I admit my question was a little tricky but I want to share the answer to other people who faced a similar problem.
The null pointer exception was quite logic. Indeed the bean was not recognized in the context because nowhere it was correctly injected in it.
It's a common pitfall related by example in this post Injecting Mockito Mock objects using Spring JavaConfig and #Autowired.
or this other post : Injecting Mockito mocks into a Spring bean
So in my job-test.xml I commented the component-scan in which my "real" LdapRepository" and LdapRepositoryImpl were declared and replace them with :
<bean id="ldapRepository" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="purge.batch.repository.LdapRepository" />
</bean>
<bean id="ldapRepositoryImpl" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="purge.batch.repository.LdapRepositoryImpl" />
</bean>
(I could have place these bean declaration before the component-scan to give it priority)
And that works like a charm !

Constructor injection in Spring

I'm working on a code where a class A is constructing an object of class B using parameterized constructor of class B. As of now, class B is not yet spring injected. The requirement is that I should always have a new non-singleton object of class B. The code somewhat looks like this:
class A{
private List<ClassB> classBList = new ArrayList<ClassB>();
void parseInfo(File f, Element e){
ClassB b = new ClassB(this,f,e);
classBList.add(b);
}
}
How should my spring-config look like if i have to inject class B using spring?
Define the bean as prototype
<!-- A bean definition with singleton scope -->
<bean id="classBBean" class="ClassB" scope="prototype"/>
Use applicationContext getBean method to create bean each time by passing arguments.
class A implements ApplicationContextAware{
private List<ClassB> classBList = new ArrayList<ClassB>();
#Autowired
private ApplicationContext appContext;
void parseInfo(File f, Element e){
ClassB b = (ClassB)appContext.getBean("classBBean",new Object[]{this,f,e});
classBList.add(b);
}
}
If I understand correctly, you are asking about Spring scopes
Basically, you need to declare your bean with scope prototype if it's a general spring application
<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="prototype">
<!-- collaborators and configuration for this bean go here -->
</bean>
or request, if it's a web spring application
<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="request">
<!-- collaborators and configuration for this bean go here -->
</bean>
For more examples look at
http://www.tutorialspoint.com/spring/spring_bean_scopes.htm

How to use the same bean in two different spring contexts?

I have two spring contexts and I need to use the same bean in both of them. Is there a way to share a bean between two contexts without making a parent context?
I don't think what you want is a good idea. If you have the same bean in two contexts, then which context manages the bean's lifecycle? By having a common parent owning the bean, you have a clear, unambiguous answer to that important question: the bean belongs to the parent context.
Now, if you know the beans will belong to context A and only want to bind them to some name in context B, I guess you could hack some kind of "guest" bean factory or whatever, that does something like:
Java:
public class GuestBeanFactory {
private ApplicationContext guestBeanContext;
#Inject
public void setGuestBeanContext(ApplicationContext guestBeanContext) {
this.guestBeanContext = guestBeanContext;
}
private String guestBeanName;
#Inject
public void setGuestBeanName(String guestBeanName) {
this.guestBeanName = guestBeanName;
}
public Object getBean() {
return guestBeanContext.getBean(guestBeanName);
}
}
applicationContext.xml:
<beans ...>
...
<bean id="myGuestFactory" class="GuestBeanFactory" scope="singleton">
<property name="guestBeanContext" ref="...get a reference to the guest bean and inject it here" />
<property name="guestBeanName" value="name-of-this-bean-inside-guestBeanContext"/>
</bean>
<bean id="myGuestBean" factory-bean="myGuestFactory" factory-method="getBean"/>
...
</beans>
This way, guestBeanContext manages name-of-this-bean-inside-guestBeanContext, but the "host" context can access that bean using the name myGuestBean.

Possibilities of resolving backing beans in JSF and Spring

I use org.springframework.web.jsf.el.SpringBeanFacesELResolver in my JSF + Spring application. Every backing bean needs an interface to be resolved. I guess that it's interface type of dependency injection.
#{bean.text}
public interface IBean {
String getText();
}
#Named
#Scope("session")
public class Bean implements IBean {
public String getText() {
return "Hello World!";
}
}
I would like to get rid of the interface. It's kind of bureaucracy for me. Is it possible?
I finally solved it. The problem was in beans with scope depending on HTTP (request, session). By default interfaces should be manually created. This can be avoided by using proxies.
If using component scan:
<context:component-scan base-package="..." scoped-proxy="targetClass" />
Or in bean definition:
<bean ...>
<aop:scoped-proxy>
</bean>
See chapter 4.5.4.5 Scoped beans as dependencies in Spring documentation. http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html

Dynamic Dependency Injection Spring

I have following code inside my class
public void startListeners() throws Exception {
List<QueueConfiguration> queueConfigs = queueConfigResolver.getQueueConfigurations();
for(QueueConfiguration queueConfig : queueConfigs){
//TODO : work on this make it more testable
ICustomListener readerListener = new MyCustomListener(queueConfig);
readerListeners.add(readerListener);
readerListener.start();
}
}
I am using Spring for dependency injection(not in this case but overall). Now there two problems with this code.
I cannot put mock for each of the listeners created, while testing.
I dont want to use ApplicationContext.getBean() because it will have same affect. AFAIK spring cannot do this dynamically , but any other pointers?
As far as I can understand, you want to create a new bean instead of
ICustomListener readerListener = new MyCustomListener(queueConfig);
If that is the case, creating a factory for mycustomlistener and using
public abstract TestClient createTestClient();
to create your beans, and defining
<bean id="testClient" class="com.myproject.testbeans.TestClient" scope="prototype">
</bean>
<bean id="testClientFactory" class="com.myproject.testbeans.TestClientFactory">
<lookup-method name="createTestClient" bean="testClient" />
</bean>
in your context will solve your problem. This way, every time the createTestClient method of the factory is called, a new bean is created and given to your code. However, you have to give the config object via a setter instead of the constructor.

Resources