How to create a bean after ServletContext initialized in Spring Boot? - spring

I have a bean, which implements ServletContextAware and BeanFactoryPostProcessor interfaces. I need this this bean register into the applicationContext after the ServletContext finished initialization, because I use some parameters in the servletContext to init this bean.
I am using the Spring Boot, the bean name is SpringBeanProcessorServletAware. I have add it into a configuration bean.
#Bean
public static SpringBeanProcessorServletAware springBeanProcessor() {
SpringBeanProcessorServletAware p = new SpringBeanProcessorServletAware();
return p;
}
My issue is that the bean is created before my container set servletContext to it. Then I can't get the parameters from the servletContext. How to control that the bean must be created after my servletContext has been created completely?

Related

Spring Kotlin Bean DSL - register bean only if other bean is present?

I want to register bean (MyBean) only if another bean (anotherBeanThatShouldBePresent) is present in the context.
How I can achieve that?
bean {
MyBean(
anotherBeanThatShouldBePresent = ref()
)
}
You can use ObjectProvider to create bean depending on another bean
bean {
provider<OtherBeanOnWhichIDepend>().ifAvailable {
bean<MyCustomBean>()
}
}
With this code I will register MyCustomBean only if OtherBeanOnWhichIDepend bean is available

Why spring beans registered using registerSingleton() are not visible in getBeanDefinitionNames()?

When Spring bean is registered using ConfigurableListableBeanFactory.registerSingleton() method, it's not available in ApplicationContext.getBeanDefinitionNames().
Is it by design? Maybe I can use some other method to get registered beans?
You can register and destroy your singleton using DefaultListableBeanFactory
Inject the ApplicationContext by #Autowired Spring annotation
Initialize a ConfigurableApplicationContext object
ConfigurableApplicationContext configContext = ConfigurableApplicationContext) applicationContext;
Initialize a DefaultListableBeanFactory object by using configContext
DefaultListableBeanFactory beanRegistry = (DefaultListableBeanFactory) configContext.getBeanFactory();
Use beanRegistry instance to handle your Spring beans
//Register a singleton bean
beanRegistry.registerSingleton(beanName,object);
//Destroy a singleton bean from context
beanRegistry.destroySingleton(beanName);
As the name getBeanDefinitionNames implies it will return the names of all BeanDefinitions available in the ApplicationContext. A BeanDefinition is the recipe on how to create a bean.
When using registerSingleton to register an arbitrary bean you created outside the scope of the ApplicationContext this obviously doesn't have a BeanDefinition and hence it will not be available in that list of names.

not able to set the value for autowired parameter

I have datasource autowired with setters. Trying to return datasource value with Bean declaration in Spring javaconfig file. For some reason, it is not identifying and showing the error:
Property 'dataSource' required
Any idea? Here is my Bean in the javaconfig file:
#Bean(name = "dataSource")
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("xyz");
dataSource.setUsername("xyz");
dataSource.setPassword("xyz");
return dataSource;
}
and the log trace:
Error creating bean with name 'featureStoreSpringJDBC' defined
in URL [jar:file:/C:home/WEB-INF/lib/ff4j-store-springjdbc.jar!
/org/ff4j/store/FeatureStoreSpringJDBC.class]:
Initialization of bean failed; nested exception
is org.springframework.beans.factory.BeanInitializationException
Property 'dataSource' is required for bean 'featureStoreSpringJDBC'
Please note that the attribute dataSource is not annotated with the #Autowired annotation, as a consequence you must explicitely invoke setter and initialize the FeatureStore in javaconfig.
The reason is you should defined the whole FF4J as a bean in the java config.In version before 1.3 it was autowired but we got issues with spreading of javaConfig.

Is it possible to inject beans using an XML file in Spring?

I am trying to inject a bean into an application using an XML file. The main function has
try(ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring/application.xml")) {
context.registerShutdownHook();
app.setResourceLoader(context);
app.run(args);
} catch (final Exception ex) {
ex.printStackTrace();
}
I also have a Person POJO and is set in the xml file.
The xml defination is as follows:
<context:annotation-config/>
<bean id="person" class="hello.service.Person" p:name="Ben" p:age="25" />
<bean class="hello.HelloBeanPostProcessor"/>
The link to my repo is:
https://bitbucket.org/rkc2015/gs-scheduling-tasks-complete
It is the default guide from Spring boot that does a scheduled task.
I'm trying to inject the Person POJO defined in the xml file into a scheduled task.
I am currently getting this error:
Error creating bean with name 'scheduledTasks': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private hello.service.Person
hello.service.ScheduledTasks.person; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type [hello.service.Person] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for
this dependency. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Can anyone please help? I am new to Spring.
You can use #ImportResource annotation to import xml configurations.
Documentation link
#SpringBootApplication
#EnableScheduling
#ImportResource("/spring/application.xml")
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication app = new SpringApplication(Application.class);
app.run();
}
}
If this is through spring bean you should have used #component annotation for you bean definition or else i application.xml you should have defined scheduledTasks bean also and with it member variable of person so that both beans are created and can be autowired.

Can't Autowire ServletContext

I'm new with Spring, and I'm trying to use the #Autowire annotation for the ServletContext with my class attribute:
#Controller
public class ServicesImpl implements Services{
#Autowired
ServletContext context;
I defined the bean for this class in my dispatcher-servlet.xml:
<bean id="services" class="com.xxx.yyy.ServicesImpl" />
But when I try to run a JUnit test it gives the following error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [javax.servlet.ServletContext] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I thought that the ServletContext injection was automatic with spring... How can I solve this?
Thanks!
EDIT: I want to use the servletContext to call the getRealPath() method. Is there any alternative?
Implement the ServletContextAware interface and Spring will inject it for you
#Controller
public class ServicesImpl implements Services, ServletContextAware{
private ServletContext context;
public void setServletContext(ServletContext servletContext) {
this.context = servletContext;
}
You'll probably want to take a look at MockServletContext which can be used in unit tests.
ServletContext is not a Spring bean and it can, therefore, not be injected unless you implement ServletContextAware.
If one thinks in modules or layers then the servlet context shouldn't be available outside the web module/layer. I suppose your ServicesImpl forms part of the business or service layer.
If you gave a little more context we might be able to suggest better alternatives.

Resources