this is simple question,
how to get servlet context parameter when spring instantiate the bean?
my servlet context xml
<beans:bean id="ApplicationInfo" class="xx.xx.xx.ApplicationInfo"/>
In my code
public class ApplicationInfo{
ApplicationInfo()
{
//get context.xml or web.xml parameter
String xxx = .......;
}
}
my pom.xml
<org.springframework-version>3.2.11.RELEASE</org.springframework-version>
<org.aspectj-version>1.6.9</org.aspectj-version>
<org.slf4j-version>1.5.10</org.slf4j-version>
<org.springsecurity-version>3.2.5.RELEASE</org.springsecurity-version>
<org.springjpa-version>1.1.0.RELEASE</org.springjpa-version>
<hibernate.version>4.1.6.Final</hibernate.version>
<postgresql.version>9.1-901-1.jdbc4</postgresql.version>
<tiles-version>2.2.2</tiles-version>
<jackson-json-version>2.1.0</jackson-json-version>
Note: i tried to get servlet context by using #annotation ,however it is nullpointer.
If you want to access autowired bean in constructor, you have to use constructor type injection:
#Component
public class ApplicationInfo {
private final FooService fooService;
#Autowired
public ApplicationInfo(ServletContext servletContext, FooService fooService) {
this.fooService = fooService;
// do something here
}
}
If you have to (or want to) stick to XML beans definition you've got to make your class implement ServletContextAware interface, which makes Spring automatically set this dependency through setter. Instead of accessing it in constructor, you do it in method annotated with #PostConstruct which is fired when bean is fully initialized:
public class ApplicationInfo implements ServletContextAware {
private final FooService fooService;
private ServletContext servletContext;
public ApplicationInfo(FooService fooService) {
this.fooService = fooService;
}
#PostConstruct
public void init() {
// now you fooService and servletContext are set
}
#Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
}
<bean class="demo.ApplicationInfo">
<constructor-arg name="fooService" ref="fooService" />
</bean>
<bean id="fooService" class="demo.FooService"/>
Try with #Value annotation
public class ApplicationInfo {
#Value("${parameterName}")
private String parameter;
}
Related
I am developing a SpringBoot project and I want to get the bean by its name using applicationContext. I have tried many solution from web but could not succeed. My Requirement is that I have a controller
ControllerA
and inside the controller I have a method getBean(String className). I want to get instance of registered bean. I have hibernate entities and I want to get an instance of the bean by passing the name of class only in getBean method.
Please help if someone know the solution.
You can Autowire the ApplicationContext, either as a field
#Autowired
private ApplicationContext context;
or a method
#Autowired
public void context(ApplicationContext context) { this.context = context; }
Finally use
context.getBean(SomeClass.class)
You can use ApplicationContextAware.
ApplicationContextAware:
Interface to be implemented by any object that wishes to be notified
of the ApplicationContext that it runs in. Implementing this interface
makes sense for example when an object requires access to a set of
collaborating beans.
There are a few methods for obtaining a reference to the application context. You can implement ApplicationContextAware as in the following example:
package hello;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public ApplicationContext getContext() {
return applicationContext;
}
}
Update:
When Spring instantiates beans, it looks for ApplicationContextAware implementations, If they are found, the setApplicationContext() methods will be invoked.
In this way, Spring is setting current applicationcontext.
Code snippet from Spring's source code:
private void invokeAwareInterfaces(Object bean) {
.....
.....
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}
}
Once you get the reference to Application context, you get fetch the bean whichever you want by using getBean().
actually you want to get the object from the Spring engine, where the engine already maintaining the object of your required class at that starting of the spring application(Initialization of the Spring engine).Now the thing is you just have to get that object to a reference.
in a service class
#Autowired
private ApplicationContext context;
SomeClass sc = (SomeClass)context.getBean(SomeClass.class);
now in the reference of the sc you are having the object.
Hope explained well. If any doubt please let me know.
Even after adding #Autowire if your class is not a RestController or Configuration Class, the applicationContext object was coming as null. Tried Creating new class with below and it is working fine:
#Component
public class SpringContext implements ApplicationContextAware{
private static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws
BeansException {
this.applicationContext=applicationContext;
}
}
you can then implement a getter method in the same class as per your need to get the bean. Like:
applicationContext.getBean(String serviceName,Interface.Class)
Using SpringApplication.run(Class<?> primarySource, String... arg) worked for me. E.g.:
#SpringBootApplication
public class YourApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(YourApplication.class, args);
}
}
As an alternative approach you can use ConfigurableApplicationContext to get bean of any class which is annotated with #Component, #Repository or #Service.
Let's say you want to get a bean of the class BaseComponent :
#Service
public class BaseComponent {
public String getMessage() {
return "hello world";
}
}
Now you can use ConfigurableApplicationContext to get the bean:
#Component
public class DemoComponent {
#Autowired
ConfigurableApplicationContext applicationContext;
public BaseComponent getBeanOfBaseComponent() {
return applicationContext.getBean(BaseComponent.class);
}
}
You can use the ApplicationContextAware class that can provide the application context.
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext ctx = null;
public static ApplicationContext getApplicationContext() {
return ctx;
}
#Override
public void setApplicationContext(final ApplicationContext ctx) throws BeansException {
ApplicationContextProvider.ctx = ctx;
}
/**
* Tries to autowire the specified instance of the class if one of the specified
* beans which need to be autowired are null.
*
* #param classToAutowire the instance of the class which holds #Autowire
* annotations
* #param beansToAutowireInClass the beans which have the #Autowire annotation
* in the specified {#classToAutowire}
*/
public static void autowire(Object classToAutowire, Object... beansToAutowireInClass) {
for (Object bean : beansToAutowireInClass) {
if (bean == null) {
ctx.getAutowireCapableBeanFactory().autowireBean(classToAutowire);
}
}
}
}
If you are inside of Spring bean (in this case #Controller bean) you shouldn't use Spring context instance at all. Just autowire className bean directly.
BTW, avoid using field injection as it's considered as bad practice.
One API method I use when I'm not sure what the bean name is org.springframework.beans.factory.ListableBeanFactory#getBeanNamesForType(java.lang.Class<?>). I simple pass it the class type and it retrieves a list of beans for me. You can be as specific or general as you'd like to retrieve all the beans associated with that type and its subtypes, example
#Autowired
ApplicationContext ctx
...
SomeController controller = ctx.getBeanNamesForType(SomeController)
Easy way in configration class call the BEAN annoted method . Yes u heard it right---- :P calling SpringBoot #Bean annoted method return the same bean from config .I was trying to call a logout in #predestroy method in config class from a bean and direcltly called the method to get the same bean .
P.S. : I added debug in the #bean annotated method but it didn't entered the method even when i called it.Sure to blame -----> Spring Magic <----
You can use ServiceLocatorFactoryBean. First you need to create an interface for your class
public interface YourClassFactory {
YourClass getClassByName(String name);
}
Then you have to create a config file for ServiceLocatorBean
#Configuration
#Component
public class ServiceLocatorFactoryBeanConfig {
#Bean
public ServiceLocatorFactoryBean serviceLocatorBean(){
ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
bean.setServiceLocatorInterface(YourClassFactory.class);
return bean;
}
}
Now you can find your class by name like that
#Autowired
private YourClassfactory factory;
YourClass getYourClass(String name){
return factory.getClassByName(name);
}
Just use:
org.springframework.beans.factory.BeanFactory#getBean(java.lang.Class)
Example:
#Component
public class Example {
#Autowired
private ApplicationContext context;
public MyService getMyServiceBean() {
return context.getBean(MyService.class);
}
// your code uses getMyServiceBean()
}
I tried searching here on SO but i couldn't find a solution. I have some XML metadata like the following.
<bean class="javax.servlet.ServletContext" id="servletContext" />
<bean class="com.abc.ProductController">
<property name="servletContext" ref="servletContext"/>
</bean>
With this configuration I am getting an exception saying that "javax.servlet.ServletContext" is an interface and it couldn't create a bean with the id servletContext. The ProductController class is in some jar which I can't modify but I want it as a bean in my application. It has ServletContext property autowired.
If you need to create a bean for ServletContext in a XML config spring application, you could use a BeanFactory<ServletContext> implementing ServletContextAware
public class ServletContextFactory implements FactoryBean<ServletContext>,
ServletContextAware{
private ServletContext servletContext;
#Override
public ServletContext getObject() throws Exception {
return servletContext;
}
#Override
public Class<?> getObjectType() {
return ServletContext.class;
}
#Override
public boolean isSingleton() {
return true;
}
#Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
}
You can then declare :
<bean class="org.app.ServletContextFactory" id="servletContext" />
<bean class="com.abc.ProductController">
<property name="servletContext" ref="servletContext"/>
</bean>
Just autowire the context in your controller:
#Autowired
private ServletContext context;
You cannot reference the servlet context in your XML like this because its lifecycle is controlled by the servlet container.
The solution is to have com.abc.ProductController implement ServletContextAware and then Spring will set it for you.
With java config use ServletContextFactory created by Serge Ballesta above and:
#Configuration
public class WebAppConfiguration {
#Autowired
private ServletContextFactory servletContextFactory;
#Bean
public ServletContextFactory servletContextFactory() {
return new ServletContextFactory();
}
}
I'm used to using Spring to do my dependency injection like so:
<context:component-scan base-package="org.emmerich.myapp" />
and then annotating my dependent classes with Autowired like so:
public class DependentClass {
#Autowired
private Dependency dependency;
}
However, with the changes in Hibernate 4.0, we're now advised to use the new Integrator interface for service discovery. This includes adding event listeners for triggers such as postUpdate, postDelete etc.
Unfortunately, this doesn't play nicely with dependency injection through annotated dependencies. I have the following setup:
An integrator I have defined to add my listener to the ServiceFactory. This is referenced in the file META-INF/services/org.hibernate.integrator.spi.Integrator.
public class MyIntegrator implements Integrator {
private MyListener listener;
public MyIntegrator() {
listener = new MyListener();
}
#Override
public void integrate(Configuration configuration,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
final EventListenerRegistry eventRegistry =
serviceRegistry.getService(EventListenerRegistry.class);
eventRegistry.prependListeners(EventType.POST_COMMIT_INSERT, listener);
}
I also have defined the class MyListener, which looks like your typical event listener.
#Component
public class MyListener implements PostInsertEventListener {
#Autowired
private Dependent dependent;
public void onPostInsert(PostInsertEvent event) {
// dependent == null
}
}
Unforunately, as shown by the comment, this doesn't work. I guess it's because I'm instantiating MyListener inside MyIntegrator, it doesn't pick up the component and doesn't autowire components. However, if I try this:
#Component
public class MyIntegrator {
#Autowired
private MyListener listener;
...
}
Then the listener isn't autowired.
Firstly, it feels wrong whilst using Spring to have to do new MyListener(). I expect to be able to define that as an autowired dependency and have Spring create a singleton for me. My question is this:
What's the best approach to using dependency injection with the new Integrator interface? The Integrators are used to build a SessionFactory, and so when they're asked to integrate themselves I guess there isn't an application context available. Because of that, any beans I require in the Integrator need to be created the "old fashioned" way and won't receive the autowiring on them.
I'm quite new to the world of Spring, would you say this is something that I should expect to see? I understand that I'm in a different scope of the application when I'm in the SessionFactory, but is there a way to obtain a reference to the bean and enable autowire even though I'm creating it via new?
The solution I came up with used ApplicationContextAware. It meant that MyListener received a reference to the ApplicationContext whenever the context was available, and I referenced the beans from the context on method calls, rather than on bean construction. Creating a bean with new doesn't limit this, so Spring still gives me the application context:
#Component
public class MyListener implements PostInsertEventListener, ApplicationContextAware {
private static ApplicationContext context;
public void onPostInsert(PostInsertEvent event) {
// getDependent() == correct!
}
public void setApplicationContext(ApplicationContext context) throws BeanException {
this.context = context;
}
public Dependent getDependent() {
return context.getBean(Dependent.class);
}
}
Is there a better way?
As stated in the comment i went another way of integrating Spring managed HibernateEventListeners. Here's the code:
The identifier interface for Spring managed Hibernate event listeners:
public interface HibernateEventListener { }
The HibernateIntegrator:
#Service
public class HibernateSpringIntegrator {
private static final Logger log = LoggerFactory.getLogger(HibernateSpringIntegrator.class);
#Autowired
private HibernateEntityManagerFactory entityManagerFactory;
#Autowired
private HibernateSpringIntegratorRegistry hibernateSpringIntegratorRegistry;
#PostConstruct
public void registerListeners() {
log.debug("Registering Spring managed HibernateEventListeners");
EventListenerRegistry listenerRegistry = ((SessionFactoryImpl) entityManagerFactory
.getSessionFactory()).getServiceRegistry().getService(
EventListenerRegistry.class);
List<HibernateEventListener> eventListeners = hibernateSpringIntegratorRegistry
.getHibernateEventListeners();
for (HibernateEventListener hel : eventListeners) {
log.debug("Registering: {}", hel.getClass());
if (PreInsertEventListener.class.isAssignableFrom(hel.getClass())) {
listenerRegistry.appendListeners(EventType.PRE_INSERT,
(PreInsertEventListener) hel);
}
if (PreUpdateEventListener.class.isAssignableFrom(hel.getClass())) {
listenerRegistry.appendListeners(EventType.PRE_UPDATE,
(PreUpdateEventListener) hel);
}
if (PreDeleteEventListener.class.isAssignableFrom(hel.getClass())) {
listenerRegistry.appendListeners(EventType.PRE_DELETE,
(PreDeleteEventListener) hel);
}
if (PostInsertEventListener.class.isAssignableFrom(hel.getClass())) {
listenerRegistry.appendListeners(EventType.POST_INSERT,
(PostInsertEventListener) hel);
}
if (PostUpdateEventListener.class.isAssignableFrom(hel.getClass())) {
listenerRegistry.appendListeners(EventType.POST_UPDATE,
(PostUpdateEventListener) hel);
}
if (PostDeleteEventListener.class.isAssignableFrom(hel.getClass())) {
listenerRegistry.appendListeners(EventType.POST_DELETE,
(PostDeleteEventListener) hel);
}
// Currently we do not need other types of eventListeners. Else this method needs to be extended.
}
}
}
The "Registry":
#Component
public class HibernateSpringIntegratorRegistry {
#Autowired(required = false)
private List<HibernateEventListener> hibernateEventListeners;
public List<HibernateEventListener> getHibernateEventListeners() {
if (hibernateEventListeners == null) {
return Collections.emptyList();
}
return hibernateEventListeners;
}
}
And here's an example implementation:
#Component
public class MailGenerationEventListener implements HibernateEventListener,
PostDeleteEventListener, PostInsertEventListener, PostUpdateEventListener {
#Override
public void onPostDelete(PostDeleteEvent event) {
Class<?> entityClass = event.getEntity().getClass();
...
}
#Override
public void onPostInsert(PostInsertEvent event) {
Class<?> entityClass = event.getEntity().getClass();
...
}
#Override
public void onPostUpdate(PostUpdateEvent event) {
Class<?> entityClass = event.getEntity().getClass();
...
}
}
During an upgrade from hibernate 3.6 to 4.2, we needed to have a custom validator that uses spring-managed beans by doing the following configuration:
<!-- Make our validators use DI if necessary -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<!-- other props -->
<property name="hibernateProperties">
<map>
<entry key="javax.persistence.validation.factory" value-ref="validator" />
</map>
</property>
</bean>
I have a requestScope bean, regular Java bean, and Spring configuration just like the code shown below. May I know how can I access the bean's property from regular Java code that is configured with Spring?
Managed Bean
#ManagedBean(name="requestBean")
public class RequestBean {
private String theID;
/** getter and setter of theID **/
}
Spring Bean
public class SpringBean {
private RequestBean theBean = null;
// how could I access the RequestBean.theID from this class ??
}
Spring configuration
<bean id="springBean" class="org.huahsin.SpringBean"/>
Maybe I do not understand the question, but I think it is simply by calling the getter:
public class SpringBean {
private RequestBean theBean = null;
...
public void aCallingMethod() {
if (theBean != null) {
theBean.getTheId(); // <-- here it is !!
}
}
}
EDIT
To inject the request bean into the Spring bean, either you use an #Autowired annotation:
public class SpringBean {
#Autowired
private RequestBean theBean = null;
...
}
Either you inject it in your XML file:
<bean id="springBean" class="org.huahsin.SpringBean">
<property name="theBean" ref="requestBean"/>
</bean>
I want to inject an ApplicationContext itself to a bean.
Something like
public void setApplicationContext(ApplicationContect context) {
this.context = context;
}
Is that possible in spring?
Previous comments are ok, but I usually prefer:
#Autowired private ApplicationContext applicationContext;
Easy, using the ApplicationContextAware interface.
public class A implements ApplicationContextAware {
private ApplicationContext context;
public void setApplicationContext(ApplicationContext context) {
this.context = context;
}
}
Then in your actual applicationContext you only need to reference your bean.
<bean id="a" class="com.company.A" />
Yes, just implement the ApplicationContextAware -interface.
I saw some comments above about #Autowired not working still. The following may help.
This will not work:
#Route(value = "content", layout = MainView.class)
public class MyLayout extends VerticalLayout implements RouterLayout {
#Autowired private ApplicationContext context;
public MyLayout() {
comps.add(context.getBean(MyComponentA.class)); // context always null :(
}
You must do this:
#Autowired
public MyLayout(ApplicationContext context) {
comps.add(context.getBean(MyComponentA.class)); //context is set :)
}
or this:
#PostConstruct
private void init() {
comps.add(context.getBean(MyComponentA.class)); // context is set :)
}
Also note that Upload is another component that must be set within the scope of #PostConstruct. This was a nightmare for me to figure out. Hope this helps!
I almost forgot to mention that the #Scope annotation may be necessary for your Bean, as seen below. This was the case when using Upload within a Bean because the UI is not instantiate/attached prior to the Bean being created and will cause a Null Reference Exception to be thrown. It won't do so when using #Route, but will when using #Component - so the latter is not an option and if #Route is not viable, then I would recommend using #Configuration class to create the bean with the prototype scope.
#Configuration
public class MyConfig {
#Bean
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
public MyComponentA getMyBean() {
return new MyComponentA();
}
}
Special solution: get Spring beans from any (non Spring) classes
#Component
public class SpringContext {
private static ApplicationContext applicationContext;
#Autowired
private void setApplicationContext(ApplicationContext ctx) {
applicationContext = ctx;
}
public static <T> T getBean(Class<T> componentClass) {
return applicationContext.getBean(componentClass);
}
}