Is there a way in Spring to get an object programmatically as if it was injected by the xml file.
Here is what i mean
I have this class called securityDelegate. It's instances are always created by spring
<bean id="securityDelegate" class="securityBusinessDelegate" lazy-init="true">
<property name="securityServiceEJB" ref="securityServiceEJB"/>
<property name="securityService" ref="securityService"/>
</bean>
I need to use an instance of this class in a SessionListener, and as I understand, since this is at a servlet level, I can't inject an instance of securityDelegate into my HttpSessionListener implementation.
What I would like to do is to retrieve an instance through java code, inside my implementation, to do something like this
public class SessionListener implements HttpSessionListener {
//other methods
#Override
public void sessionDestroyed(HttpSessionEvent se) {
//get an instance of securityBusinessDelegate here
securityBusinessDelegate.doSomething();
}
}
I seem to recall this was possible last time I used spring (3+ years ago), but I could be confused. Maybe setting up a factory?
ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(se.getServletContext.());
ctx.getBean("securityDelegate");
For completeness:
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
public class SessionListener implements HttpSessionListener {
#Override
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext servletCtx = se.getSession().getServletContext();
ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletCtx);
YourClass securityBusinessDelegate = ctx.getBean(YourClass.class);
securityBusinessDelegate.doSomething();
}
}
Yep, use a factory. Just a much more complicated one. DI/IoC Geniuses.
Related
I have an application that consists of 2 modules.
First of them is main one and it can work without second module installed.
I have beans with default implementation defined in beans.xml file of main module. And when installing second module I want to keep the ids of those beans but change the implementation to use new classes.
What is the best way to do that?
beans.xml of first module:
...
<bean id="myCoolService" class="com.blabla.defaultCoolServiceImpl">
...
and after the installation of second module I want to use the implementation of myCoolService that is defined in second module.
Upd:
Spring version is 3.2.4.
I need to make as little changes as possible so I need to continue using xml-driven configuration.
One way of doing this is introducing a common interface (I guess one should already be present):
public interface MyInterface {
//...
}
And then in the main module annotate the default implementation with #Service
#Service
public class DefaultImplementation implements MyInterface {
//...
}
Then, if one of your modules needs to override this implementation, use the #Primary-annotation:
#Service
#Primary
public class OverridingImplementation implements MyInterface {
//...
}
Then, the following code:
#Inject
private MyInterface myInterface;
will inject DefaultImplementation if OverridingImplementation is not scanned, and inject OverridingImplementation (without complaining about multiple beans) if it is scanned.
One way to achieve this is going through a proxy, that redirects to the proper implementation. The proxy would normally redirect to the default. It will redirect to module 2 if it is available.
To help the proxy figure out what is available, you may need to have
a member that always points to the default implementation using "name" property.
have a method to register a different bean as the alternate implementation.
For example
Inside MyProxy:
#Autowired
public void setDefaultWorker(Worker defaultWorker) {
this.defaultWorker = defaultWorker;
}
private Worker defaultWorker;
private Worker alternateWorker;
public void registerAlternateWorker(Worker alternateWorker) {
this.alternateWorker = alternateWorker;
}
//To use the worker
private Worker getWorker() {
return alternateWorker == null? defaultWorker : alternateWorker;
}
In Module 1, your default implementation bean should be declared as having the defaultWorker as name
<bean id="defaultWorker" class="MyDefaultWorkerImpl"/>
Module 2 can register itself to the proxy registry on startup using SmartLifeCycle.
if possible,use :
<bean id="myCoolService" class="${IMPL_CLASS_NAME}"/>
Define impl class in a property file.
IMPL_CLASS_NAME=com.blabla.SecondMduleCoolServiceImpl
OR other approach could be :
Lets say your defaultCoolServiceImpl and SecondMduleCoolServiceImpl implement ICoolService interface
You define these bean and an implementation of FactoryBean as below :
<bean id="mydefaultServiceimpl" class="com.blabla.defaultCoolServiceImpl">
<bean id="secondModuleCoolserviceimpl" class="com.blabla.SecondMduleCoolServiceImpl">
<bean id="myCoolService" class="com.blabla.ImplSelector"/>
public class ImplSelector implements FactoryBean<ICoolService>, ApplicationContextAware {
private ApplicationContext iApplicationContext;
// #Value("#{corePropertyConfigurer['defaultOrCool']}") you can injcet via property file.
private String defaultOrCool = "cool" ;
#Override
public ICoolService getObject() throws Exception {
if (StringUtils.equals(defaultOrCool, "default")) {
return iApplicationContext.getBean("mydefaultServiceimpl", ICoolService.class);
}
return iApplicationContext.getBean("secondModuleCoolserviceimpl", ICoolService.class);
}
#Override
public Class<?> getObjectType() {
return ICoolService.class;
}
#Override
public boolean isSingleton() {
return true;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
iApplicationContext = applicationContext;
}
}
Then you can access myCoolService via autowiring or applicationContext.getBean("myCoolService", ICoolService.class);
I am new to Spring. I have at work in spring-config.xml this :
<bean id="statusEmailSender" class="my.package.email.StatusEmailSenderImpl">
<property name="mailSender" ref="mailSender"/>
<property name="templateMessage" ref="templateMessage"/>
</bean>
In some classes already defined I see something like this:
#Autowired
private StatusEmailSender statusEmailSender;
And it works. When I do it in my own class, I get a NullPointerException.
I know the reason: I am creating my class with new():
return new EmailAction(config,logger);
My class looks like this:
public class EmailAction{
#Autowired
StatusEmailSender statusEmailSender;
public EmailAction(...)
{
...
}
}
Do you know how I can get around this? This is legacy code, and it's extremely difficult to get around the new EmailAction() call.
You want use a spring bean inside a non-spring class(legacy code). In order to do that you need to make the Spring's ApplicationContext (which holds BeanFactory where spring beans are residing) available to legacy code.
For that you need to create a spring bean something like:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context;
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
}
public static ApplicationContext getApplicationContext() {
return context;
}
}
and define this bean inside your Spring configuration file (or if you are using annotation driven, annotate bean with #Component)
<bean id="springContext" class="com.util.SpringContext />
Since SpringContext exposes a static method, the legacy code can access it.for example if the legacy code needs spring bean EmailAction, call like:
EmailAction emailAction= (EmailAction)SpringContext.getApplicationContext.getBean(EmailAction.class);
now the emailAction will contain all its dependencies set.
Why don't you just autowire your EmailAction class when you need it?
EmailAction.java:
#Component
public class EmailAction{
// ...
}
WhereYouNeedIt.java:
public class WhereYouNeedIt{
#Autowired
EmailAction emailAction;
// access emailAction here
}
In my jsp, I have a custom tag
<ex:SelfService />
which intrun calls the java class
public class SelfServiceClass extends SimpleTagSupport{
#Autowired
private ReloadablePropertyManagerImpl reloadableProperty;
public ReloadablePropertyManagerImpl getReloadableProperty() {
return reloadableProperty;
}
public void setReloadableProperty(
ReloadablePropertyManagerImpl reloadableProperty) {
this.reloadableProperty = reloadableProperty;
}
public void doTag() throws IOException {
JspWriter out = getJspContext().getOut();
out.println(getReloadableProperty().getPropertyValue("print.service"));
}
}
And in my spring.xml I have configured the bean,
<bean id="reloadableProperty" class="com.testing.portal.util.ReloadablePropertyManagerImpl" />
But I am getting null pointer exception when I call getPropertyValue() on reloadableProperty object.
Any help will be much appreciated.
Since your class is not managed by Spring you have to load the ReloadablePropertyManagerImpl from the application context by yourself. In order to do so you should create a class which implements ApplicationContextAware with a static getter for the context.
See more in this sample.
Is Spring aware of SelfServiceClass class? It has to be. You either annotate it with #Component or it is returned by a #Configuration as a #Bean or include it as you did with reloadebleProperty in the xml, i.e.: make it a spring managed bean
No one so far was capable of providing a working correct example of interface injection in Spring Framework.
Martin Fowler article is not for mortals, everything else just words positioned in a very confusing way. I have surfed over THIRTY articles, where people either tell "Spring doesn't directly supports for interface injection"("and because I don't know exactly how I will only describe setter and constructor injections") or either "I will discuss it in my other threads" or either there will be few comments below saying that it is wrong example. I don't ask for explanation, I BEG for example.
There are three types of injection: Constructor, Setter and Interface. Spring doesn't support the latest directly(as I have observed people saying). So how is it done exactly?
Thank You,
According to Variants of DI in spring
DI exists in two major variants, Constructor-based dependency injection and Setter-based dependency injection.
Also see Interface injection is not implemented in Spring clearly states it.
So there are only two variants of DI. So if documentation says nothing about interface injection, its clear that its not there. Those who believe that interface injection is done by providing setter method in interface answer me:
Why spring ref doc left mention of interface injection?
Why can't interface injection via providing setter method NOT considered as setter injection itself. Why create special term for that when introduction of interface doesn't affect anything, I mean its still configured the same way. If they were different then how can one find it via seeing the config. Shouldn't it be transparent that in config and not seeing the impl that actually configured class implements some interface ?
Just like Instantiation using an instance factory method and Instantiation using an static factory method, some bean attributes should clarify the interface injection?
With interface injection an interface explicitly defines the point where a dependency can be set:
interface InjectPerson {
public void injectHere(Person p);
}
class Company implements InjectPerson {
Person injectedPerson;
public void injectHere(Person p) {
this.injectedPerson = p;
}
}
There are 3 types of dependency injections:-
1. Constructor Injection(E.g Pico Container, Spring supports it).
2. Setter Injection(E.g Spring supports it).
3. Interface Injection(E.g Avalon, Spring does not support it).
Spring supports only constructor and setter based injection.
Looks like you got confused in the different types(3) and what spring supports(2 of them).
Hi I tried with a very simple approach that may clarify your answer.
following is the code that i have built on using two interfaces and and two bean classes.
first interface with name Job.
public interface Job {
public void setmyJob(String myJob);
public String getmyJob();
}
and one class to implement this interface with name as MyJob
public class MyJob implements Job {
public String myJob;
public MyJob() {
System.out.println("From MyJob default Constructor and the ID= "+this);
}
public void setmyJob(String myJob) {
this.myJob=myJob;
}
public String getmyJob() {
return myJob;
}
}
In the next step i created another Interface with name as Service
public interface Service {
public void setJob(Job job);
public Job getJob();
}
and then again another class to implement this Service Interface.
public class MyService implements Service {
public Job job;
public void setJob(Job job) {
this.job=job;
System.out.println("Hello from Myservice: Job ID="+job);
}
public Job getJob() {
return job;
}
}
then i created on main class with the main function and written the code as follows:
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApplication {
public static void main(String...a) {
BeanFactory beanfactory=new ClassPathXmlApplicationContext("Beans.xml");
MyService myservice=(MyService)beanfactory.getBean("myservice");
System.out.println("Before print");
System.out.println(myservice.getJob().getmyJob());
}
}
in my Beans.xml file i mentioned the code as follows and it worked.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="myjob" class="MyJob">
<property name="myJob" value="My First String"/>
</bean>
<bean id="myservice" class="MyService">
<property name="job" ref="myjob"/>
</bean>
</beans>
I have also reffered to another online tutorials and then got this kind of solution. please let me know if you have any problem with this code. it is working for me.
I think, that the confusion around interface injection is caused by missunderstanding what the term "interface injection" actually means. In my understanding, interface injection describes the ability of a bean contener to inject a new interface to the bean, no matter that the class definition of this bean is not implementing it.
All examples presented here show how to create a bean out of concrete class, and then how to inject it into another bean. The fact, that in all cases bean is injected into a field defined as an interface does not matter- all operations are done with beans created out of concrete instances.
I can provide also another catchy example:
package creditCards;
interface PaymentCard {
Boolean isDebitAllowed();
}
<bean id="card" class="creditCards.PaymentCard">
<lookup-method name="isDebitAllowed" bean="boolValue"/>
</bean>
<bean id="boolValue" class="java.lang.Boolean">
<constructor-arg type="boolean" value="true"/>
</bean>
As you see here, it is even possible to create a bean out of interface! Still, it is not a interface injection, as IoC contener initializes instanse of this bean by its own. In other words, card bean is an initialized object, not an interface, what makes, that the selected answer for this question is correct.
I think someone answered your questions here
I also didn't know what Interface injection is until I read this statement from "Pro Spring MVC with web flow book"
"Note that interface-based dependency injection isn’t supported by the Spring Framework. This
means that we need to specify which concrete implementation to inject for a certain interface."
Please check the below example for iterface injection.
There is a shape interface and 2 concrete classes which imiplements shape namely square and rectangle.
The interface
package di.interfaceinjection;
public interface Shape {
public String shapeName();
public void displayName();
}
2 Implemented classes
package di.interfaceinjection;
public class Square implements Shape {
#Override
public String shapeName() {
return "Square";
}
#Override
public void displayName() {
System.out.println("Square");
}
}
package di.interfaceinjection;
public class Rectangle implements Shape{
#Override
public String shapeName() {
return "Rectangle";
}
#Override
public void displayName() {
System.out.println("Rectangle");
}
}
Now, we have a class which sets the shape.
public class ShapeSetter {
private Shape shape;
public Shape getShape() {
return shape;
}
public void setShape(Shape shape) {
this.shape = shape;
}
}
and finally the configuration
<bean id="shape1" class="di.interfaceinjection.ShapeSetter">
<property name="shape" ref="square"></property>
</bean>
<bean id="shape2" class="di.interfaceinjection.ShapeSetter">
<property name="shape" ref="rectangle"></property>
</bean>
<bean id="square" class="di.interfaceinjection.Square"></bean>
<bean id="rectangle" class="di.interfaceinjection.Rectangle"></bean>
Here,
we are injecting different shapes.
package di.interfaceinjection;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class InterfaceInjeection {
/**
* #param args
*/
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext("intro.xml");
ShapeSetter shape = (ShapeSetter)appContext.getBean("shape2");
shape.getShape().displayName();
}
}
I'd like to use FactoryBeans and scopes together. Specifically, I'd like the object created and returned by a FactoryBean to be placed into a specified (perhaps custom) scope. The issue is that doing the following:
<bean class="x.y.z.TestFactoryBean" scope="test" />
Results in the FactoryBean itself being scoped, and has somewhat unpredictable behaviour on the object created by the factory. I understand why this is; the factory itself is a first-class spring-managed bean, and has its own lifecycle. However, I can't find a way to specify that the object returned from the factory should itself be scoped.
On the other hand, this does exactly what I want (as long as TestFactoryBean does NOT implement the FactoryBean interface):
<bean class="x.y.z.TestFactoryBean" name="testFactory">
<bean class="x.y.z.TestBean" factory-bean="testFactory"
factory-method="getObject" scope="test" />
So the real question is, how can I make Spring behave like it does for the 2nd example above, but using real FactoryBeans?
You can't easily use a custom scope on a bean returned from a FactoryBean.
From Spring's Java documentation:
FactoryBeans can support singletons and prototypes
If you want the FactoryBean's returned bean to have the prototype scope, then you must implement the isSingleton() method like this:
public class TestFactoryBean implements FactoryBean<TestBean> {
// the rest of the required methods are removed for simplicity reasons..
public boolean isSingleton() {
return false;
}
}
To support a custom scope, you have to implement the logic yourself and it will not be very intuitive, since the FactoryBean only provides the isSingleton() method. I will rather recommend using another solution than FactoryBean for beans with custom scope.
Hope this helps!
I solved the same issue using custom holder bean.
Factory bean:
#Component
#Configurable()
public class EventBusFactory implements FactoryBean<EventBus> {
#Override
public EventBus getObject() throws Exception {
return new SimpleEventBus();
}
#Override
public Class<?> getObjectType() {
return EventBus.class;
}
#Override
public boolean isSingleton() {
return false;
}
}
Bean holder:
#Configurable
#Component
#Scope("session")
public class EventBusHolder {
#Autowired
private EventBus eventBus;
public EventBus getEventBus() {
return eventBus;
}
public void setEventBus(EventBus eventBus) {
this.eventBus = eventBus;
}
}
And then I use holder instead of the required entity.
#Component
#Configurable
#Scope("session")
public class UicPlaceController extends PlaceController {
#Autowired
public UicPlaceController(EventBusHolder eventBus) {
super(eventBus.getEventBus());
}
...
}
The solution looks a little bit ugly, but still, it solves the issue.