I found similar question here Spring - how to inject a bean into class which is created many times at runtime? and Why is Spring's ApplicationContext.getBean considered bad? but neither really answers my case.
Example code:
public interface AppNameProvider
{
String getAppName();
}
public class DefaultAppNameProvider implements AppNameProvider
{
private String appName;
public String getAppName()
{
return appName;
}
public setAppName(String appName)
{
this.appName = appName;
}
}
<bean id="appNameProvider" class="some.package.DefaultAppNameProvider">
<property name="appName" value="MyApplication"/>
</bean>
public class MyException extends RuntimeException
{
// Imagine obligatory constructors here...
public String getAppName()
{
// Inject appNameProvider somehow here
return appNameProvider.getAppName();
}
}
I have a provider bean declared in xml. In the example the value is simply declared in xml for simplicity. I have a custom exception which needs to receive something from a bean. How to inject such bean into the exception class. I obviously can't declare exception as a Spring bean. The appName is just a simple example, it can be anything else. You might wonder why a hypothetic caller of myException.getAppName() wouldn't just simply call appNameProvider.getAppName()? Because it's not intended so, e.g. there might be different provider in each exception etc.
I would like to know how to inject the bean into such exception. I can add setter and set the provider at the exception throw time. But I have to know which provider to use from outside (in my app code) and I would have to do it redundantly everywhere where I want to throw this exception. Ideally I would like to declare which provider to use for the exception in the xml.
Ultimately the question can be widened so that instead of exception we think of any runtime object which is not a bean itself.
PS I'm not scared of having hardcoded dependencies to Spring in the code. I use Spring and I want to embrace it - not avoid it.
Inject the provider in the class which throws the exception
Provide a constructor/setter by which to set the provider to the exception
throw new MyException(provider)
It's a while since I've done it, but if you are using / can use annotation based config and aspectJ you can annotate a class as #Configurable which will allow you get Spring to inject dependencies each time an instance of the class is created.
http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html#aop-atconfigurable
You can create a component and inject the property in it. For example you can define DefaultAppNameProvider as a component and thus you can autowire other components in it. You can then provide using a singleton design pattern with a private constructor a static method called getInstance. In the class MyException you can access the DefaultAppNameProvider property using DefaultAppNameProvider.getInstance().getAppName().
Example code for the singleton component.
#Component
public class DefaultAppNameProvider {
private static DefaultAppNameProvider instance;
private DefaultAppNameProvider() {
instance = this;
}
public static DefaultAppNameProvider getInstance() {
return instance;
}
private String appName;
public String getAppName()
{
return appName;
}
public setAppName(String appName)
{
this.appName = appName;
}
}
I have been looking around in the mean time. I found this. In the end I used the following solution.
According to 1 created an ApplicationContextProvider:
public class ApplicationContextProvider implements ApplicationContextAware
{
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext()
{
return applicationContext;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
ApplicationContextProvider.applicationContext = applicationContext;
}
}
Then AppNameProviderFactory which maps providers to the keys. Key can be exception name:
public class AppNameProviderFactory
{
private Map<String,AppNameProvider> map;
public void setMap(Map<String, AppNameProvider> map)
{
this.map = map;
}
public AppNameProvider getAppNameProvider(String key)
{
return map.get(key);
}
}
And in xml I define the mappings:
<bean id="appNameProviderFactory" class="some.domain.AppNameProviderFactory">
<property name="map">
<map>
<entry key="MyException" value-ref="appNameProvider"/>
</map>
</property>
</bean>
And finally in the exception class:
public class MyException extends RuntimeException
{
// Imagine obligatory constructors here...
public String getAppName()
{
final ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
AppNameProviderFactory factory = (AppNameProviderFactory) applicationContext.getBean("appNameProviderFactory");
return factory.getAppNameProvider("MyException").getAppName();
}
}
This way I have configuration in xml, decoupled from business code. I can have as many exceptions with different providers as needed.
Thanks all for suggestions.
PS Error handling and NPE handling ommited for simplicity.
Related
I was new to Springboot application using the #Autowired to perform the dependency injection. We can use #Autowired directly by initiate that class object for class that has none or default parameterless constructor. But what if a class has some parameter in its constructor, and I would like to initiate it during runtime conditionally and automatically, is it possible to do that?
For example
#Component
public class SomeContext {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Component
public class SomeBuilder {
private final SomeContext ctx;
#Autowired
public SomeBuilder(SomeContext ctx) {
this.ctx = ctx;
}
public void test() {
System.out.println("ctx name: " + ctx.getName());
}
}
#Service
public class SomeService {
#Autowired
SomeBuilder someBuilder;
public void run(SomeContext ctx) {
if (ctx != null) {
// I want someBuilder to be initiated here in someway with my input ctx
// but NOT doing through new with constructor like below
// someBuilder = new SomeBuilder(ctx);
someBuilder.test(); // ctx name: null, I would expect to see "ctx name: someUser", while ctx was injected into someBuilder in any possible way
}
}
}
#RestController
public class HelloWorldController
{
#Autowired
SomeService someService;
#RequestMapping("/")
public String hello() {
SomeContext someContext = new SomeContext();
someContext.setName("someUser");
someService.run(someContext);
return "Hello springboot";
}
}
I'm not sure I've got your question right, but from the code it looks like you really want to create a new instance of SomeBuilder every time you call the run method of SomeService.
If so, I think the first thing to understand is that in general the injection magic happens only if the class is managed by Spring by itself. Read, if spring creates the object of the class - it will inject stuff into it otherwise you're on your own here.
The next thing to understand is that, if you have a object of class SomeBuilder managed by spring and you want to inject SomeContext into it, this SomeContext instance has to be managed by spring as well.
Bottom line, spring can deal only with objects that it manages. These objects are stored in a 'global registry' of all the objects called ApplicationContext in spring.
Now Spring has a concept of prototype scope vs. singleton scope. By Default all the beans are singletons, however you can easily alter this behavior. This has two interesting consequences:
You Can create prototype objects being injected into the singleton upon each invocatino (of method run in your case, so the SomeBuilder can and I believe should be a prototype)
Prototype objects are not stored in the application contexts so the capabilities of injecting stuff in there during the runtime are rather limited
With all this in mind:
If you want to create SomeContext like you do in the controller, its not managed by spring, so you can't use Injection of spring as is into the builder.
The builder is a singleton, so if you inject it with a regular #Autowire into another singleton (SomeService in your case), you'll have to deal with the same instance of the builder object - think about concurrent access to the method run of SomeService and you'll understand that this solution is not really a good one.
So these are the "inaccuracies" in the presented solution.
Now, in terms of solution, you can:
Option 1
Don't manage builders in Spring, not everything should be managed by spring, in this case you'll keep your code as it is now.
Option 2
and this is a the solution, although pretty advanced one:
Use Java Configuration to create prototype beans in runtime with an ability to inject parameters into the bean.
Here is an example:
// Note, I've removed all the annotations, I'll use java configurations for that, read below...
public class SomeBuilder {
private final SomeContext ctx;
public SomeBuilder(SomeContext ctx) {
this.ctx = ctx;
}
public void test() {
System.out.println("ctx name: " + ctx.getName());
}
}
Now the class SomeService will also slightly change:
public class SomeService {
private Function<SomeContext, SomeBuilder> builderFactory;
public void run(SomeContext ctx) {
SomeBuilder someBuilder = builderFactory.apply(ctx);
someBuilder.test();
}
}
And now you should "glue" it to spring in an advanced way with Java Configurations:
#Configuration
public class MyConfiguration {
#Bean
public Function<SomeContext, SomeBuilder> builderFactory() {
return ctx -> someBuilder(ctx);
}
#Bean
#Scope(value = "prototype")
public SomeBuilder someBuilder(SomeContext ctx) {
return new SomeBuilder(ctx);
}
#Bean
public SomeService someService() {
return new SomeService(builderFactory());
}
}
For more details with a really similar example, see this tutorial
In a java-spring web-app I would like to be able to dynamically inject beans.
For example I have an interface with 2 different implementations:
In my app I'm using some properties file to configure injections:
#Determines the interface type the app uses. Possible values: implA, implB
myinterface.type=implA
My injections actually loaded conditionally relaying on the properties values in the properties file. For example in this case myinterface.type=implA wherever I inject MyInterface the implementation that will be injected will be ImplA (I accomplished that by extending the Conditional annotation).
I would like that during runtime - once the properties are changed the following will happen (without server restart):
The right implementation will be injected. For example when setting myinterface.type=implB ImplB will be injected where-ever MyInterface is used
Spring Environment should be refreshed with the new values and re-injected as well to beans.
I thought of refreshing my context but that creates problems.
I thought maybe to use setters for injection and re-use those setters once properties are re-configured. Is there a working practice for such a requirement?
Any ideas?
UPDATE
As some suggested I can use a factory/registry that holds both implementations (ImplA and ImplB) and returns the right one by querying the relevant property.
If I do that I still have the second challenge - the environment. for example if my registry looks like this:
#Service
public class MyRegistry {
private String configurationValue;
private final MyInterface implA;
private final MyInterface implB;
#Inject
public MyRegistry(Environmant env, MyInterface implA, MyInterface ImplB) {
this.implA = implA;
this.implB = implB;
this.configurationValue = env.getProperty("myinterface.type");
}
public MyInterface getMyInterface() {
switch(configurationValue) {
case "implA":
return implA;
case "implB":
return implB;
}
}
}
Once property has changed I should re-inject my environment. any suggestions for that?
I know I can query that env inside the method instead of constructor but this is a performance reduction and also I would like to think of an ider for re-injecting environment (again, maybe using a setter injection?).
I would keep this task as simple as possible. Instead of conditionally load one implementation of the MyInterface interface at startup and then fire an event that triggers dynamic loading of another implementation of the same interface, I would tackle this problem in a different way, that is much simpler to implement and maintain.
First of all, I'd just load all possible implementations:
#Component
public class MyInterfaceImplementationsHolder {
#Autowired
private Map<String, MyInterface> implementations;
public MyInterface get(String impl) {
return this.implementations.get(impl);
}
}
This bean is just a holder for all implementations of the MyInterface interface. Nothing magic here, just common Spring autowiring behavior.
Now, wherever you need to inject a specific implementation of MyInterface, you could do it with the help of an interface:
public interface MyInterfaceReloader {
void changeImplementation(MyInterface impl);
}
Then, for every class that needs to be notified of a change of the implementation, just make it implement the MyInterfaceReloader interface. For instance:
#Component
public class SomeBean implements MyInterfaceReloader {
// Do not autowire
private MyInterface myInterface;
#Override
public void changeImplementation(MyInterface impl) {
this.myInterface = impl;
}
}
Finally, you need a bean that actually changes the implementation in every bean that has MyInterface as an attribute:
#Component
public class MyInterfaceImplementationUpdater {
#Autowired
private Map<String, MyInterfaceReloader> reloaders;
#Autowired
private MyInterfaceImplementationsHolder holder;
public void updateImplementations(String implBeanName) {
this.reloaders.forEach((k, v) ->
v.changeImplementation(this.holder.get(implBeanName)));
}
}
This simply autowires all beans that implement the MyInterfaceReloader interface and updates each one of them with the new implementation, which is retrieved from the holder and passed as an argument. Again, common Spring autowiring rules.
Whenever you want the implementation to be changed, you should just invoke the updateImplementations method with the name of the bean of the new implementation, which is the lower camel case simple name of the class, i.e. myImplA or myImplB for classes MyImplA and MyImplB.
You should also invoke this method at startup, so that an initial implementation is set on every bean that implements the MyInterfaceReloader interface.
I solved a similar issue by using org.apache.commons.configuration.PropertiesConfiguration and org.springframework.beans.factory.config.ServiceLocatorFactoryBean:
Let VehicleRepairService be an interface:
public interface VehicleRepairService {
void repair();
}
and CarRepairService and TruckRepairService two classes that implements it:
public class CarRepairService implements VehicleRepairService {
#Override
public void repair() {
System.out.println("repair a car");
}
}
public class TruckRepairService implements VehicleRepairService {
#Override
public void repair() {
System.out.println("repair a truck");
}
}
I create an interface for a service factory:
public interface VehicleRepairServiceFactory {
VehicleRepairService getRepairService(String serviceType);
}
Let use Config as configuration class:
#Configuration()
#ComponentScan(basePackages = "config.test")
public class Config {
#Bean
public PropertiesConfiguration configuration(){
try {
PropertiesConfiguration configuration = new PropertiesConfiguration("example.properties");
configuration
.setReloadingStrategy(new FileChangedReloadingStrategy());
return configuration;
} catch (ConfigurationException e) {
throw new IllegalStateException(e);
}
}
#Bean
public ServiceLocatorFactoryBean serviceLocatorFactoryBean() {
ServiceLocatorFactoryBean serviceLocatorFactoryBean = new ServiceLocatorFactoryBean();
serviceLocatorFactoryBean
.setServiceLocatorInterface(VehicleRepairServiceFactory.class);
return serviceLocatorFactoryBean;
}
#Bean
public CarRepairService carRepairService() {
return new CarRepairService();
}
#Bean
public TruckRepairService truckRepairService() {
return new TruckRepairService();
}
#Bean
public SomeService someService(){
return new SomeService();
}
}
By using FileChangedReloadingStrategy your configuration be reload when you change the property file.
service=truckRepairService
#service=carRepairService
Having the configuration and the factory in your service, let you can get the appropriate service from the factory using the current value of the property.
#Service
public class SomeService {
#Autowired
private VehicleRepairServiceFactory factory;
#Autowired
private PropertiesConfiguration configuration;
public void doSomething() {
String service = configuration.getString("service");
VehicleRepairService vehicleRepairService = factory.getRepairService(service);
vehicleRepairService.repair();
}
}
Hope it helps.
If I understand you correctly then the goal is not to replace injected object instances but to use different implementations during interface method call depends on some condition at run time.
If it is so then you can try to look at the Sring TargetSource mechanism in combination with ProxyFactoryBean. The point is that proxy objects will be injected to beans that uses your interface, and all the interface method calls will be sent to TargetSource target.
Let's call this "Polymorphic Proxy".
Have a look at example below:
ConditionalTargetSource.java
#Component
public class ConditionalTargetSource implements TargetSource {
#Autowired
private MyRegistry registry;
#Override
public Class<?> getTargetClass() {
return MyInterface.class;
}
#Override
public boolean isStatic() {
return false;
}
#Override
public Object getTarget() throws Exception {
return registry.getMyInterface();
}
#Override
public void releaseTarget(Object target) throws Exception {
//Do some staff here if you want to release something related to interface instances that was created with MyRegistry.
}
}
applicationContext.xml
<bean id="myInterfaceFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="MyInterface"/>
<property name="targetSource" ref="conditionalTargetSource"/>
</bean>
<bean name="conditionalTargetSource" class="ConditionalTargetSource"/>
SomeService.java
#Service
public class SomeService {
#Autowired
private MyInterface myInterfaceBean;
public void foo(){
//Here we have `myInterfaceBean` proxy that will do `conditionalTargetSource.getTarget().bar()`
myInterfaceBean.bar();
}
}
Also if you want to have both MyInterface implementations to be Spring beans, and the Spring context could not contains both instances at the same time then you can try to use ServiceLocatorFactoryBean with prototype target beans scope and Conditional annotation on target implementation classes. This approach can be used instead of MyRegistry.
P.S.
Probably Application Context refresh operation also can do what you want but it can cause other problems such as performance overheads.
This may be a duplicate question or at least very similar, anyway I answered this sort of question here: Spring bean partial autowire prototype constructor
Pretty much when you want a different beans for a dependency at run-time you need to use a prototype scope. Then you can use a configuration to return different implementations of the prototype bean. You will need to handle the logic on which implementation to return yourself, (they could even be returning 2 different singleton beans it doesn't matter) But say you want new beans, and the logic for returning the implementation is in a bean called SomeBeanWithLogic.isSomeBooleanExpression(), then you can make a configuration:
#Configuration
public class SpringConfiguration
{
#Bean
#Autowired
#Scope("prototype")
public MyInterface createBean(SomeBeanWithLogic someBeanWithLogic )
{
if (someBeanWithLogic .isSomeBooleanExpression())
{
return new ImplA(); // I could be a singleton bean
}
else
{
return new ImplB(); // I could also be a singleton bean
}
}
}
There should never be a need to reload the context. If for instance, you want the implementation of a bean to change at run-time, use the above. If you really need to reload your application, because this bean was used in constructors of a singleton bean or something weird, then you need to re-think your design, and if these beans are really singleton beans. You shouldn't be reloading the context to re-create singleton beans to achieve different run-time behavior, that is not needed.
Edit The first part of this answer answered the question about dynamically injecting beans. As asked, but I think the question is more of one: 'how can I change the implementation of a singleton bean at run-time'. This could be done with a proxy design pattern.
interface MyInterface
{
public String doStuff();
}
#Component
public class Bean implements MyInterface
{
boolean todo = false; // change me as needed
// autowire implementations or create instances within this class as needed
#Qualifier("implA")
#Autowired
MyInterface implA;
#Qualifier("implB")
#Autowired
MyInterface implB;
public String doStuff()
{
if (todo)
{
return implA.doStuff();
}
else
{
return implB.doStuff();
}
}
}
You can use #Resource annotation for injection as originally answered here
e.g.
#Component("implA")
public class ImplA implements MyInterface {
...
}
#Component("implB")
public class ImplB implements MyInterface {
...
}
#Component
public class DependentClass {
#Resource(name = "\${myinterface.type}")
private MyInterface impl;
}
and then set the implementation type in properties file as -
myinterface.type=implA
Be aware that - if interesting to know about - FileChangedReloadingStrategy makes your project highly dependent on the deployment conditions: the WAR/EAR should be exploded by container and your should have direct access to the file system, conditions that are not always met in all situations and environments.
You can use Spring #Conditional on a property value. Give both Beans the same name and it should work as only one Instance will be created.
Have a look here on how to use #Conditional on Services and Components:
http://blog.codeleak.pl/2015/11/how-to-register-components-using.html
public abstract class SystemService {
}
public class FooSystemService extends FileSystemService {
}
public class GoSystemService extends FileSystemService {
}
#Configuration
public class SystemServiceConf {
#Bean
#Conditional(SystemServiceCondition.class)
public SystemService systemService(#Value("${value.key}") value) {
switch (value) {
case A:
return new FooSystemService();
case B:
return new GoSystemService();
default:
throw new RuntimeException("unknown value ");
}
}
}
public class SystemServiceCondition implements Condition {
#Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return true;
}
}
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
In a very large legacy application I have interfaces and classes that do not implement those interfaces.
The interfaces are generated based on the class so the signatures are the same (except the interface adds another exception on top) and the names are similar (so it's easy to find the class name from the interface name).
To get an implementation of the interface we do a bunch of processing and logging calls but basically use java.lang.reflect.Proxy to delegate to the class. Simplified it looks like this:
// This will create a proxy and invoke handler that calls HelloWorld.doSomething
HelloWorldInterface i = MyProxyUtil.getInstance(HelloWorldInterface.class);
i.doSomething();
public interface HelloWorldInterface {
public void doSomething() throws Exception;
}
public class HelloWorld {
public void doSomething() {
//something
}
}
Is it possible with Spring annotation processing, to generically #Autowire all fields of type *Interface and have spring use MyProxyUtil.getInstance(*Interface.class) to inject the implementation?
Such that
#Autowire HelloWorldInterface a;
HelloWorldInterface b = MyProxyUtil.getInstance(HelloWorldInterface.class);
#Autowire AnotherInterface c;
AnotherInterface d = MyProxyUtil.getInstance(AnotherInterface.class);
a == b
c == d
Yes, you need to implement a AutowireCandidateResolver.
For example:
public class ProxyAutowiredCandidateResolver extends SimpleAutowireCandidateResolver {
#Override
public Object getSuggestedValue(DependencyDescriptor descriptor) {
String dependencyClassName = descriptor.getDependencyType().getSimpleName();
if (dependencyClassName.endsWith("Interface")) {
return MyProxyUtil.getInstance(descriptor.getDependencyType());
}
return super.getSuggestedValue(descriptor);
}
}
You could use a BeanFactoryPostProcessor to configure it in the application context:
public class AutowireCandidateResolverConfigurer implements BeanFactoryPostProcessor {
private AutowireCandidateResolver autowireCandidateResolver;
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
DefaultListableBeanFactory bf = (DefaultListableBeanFactory) beanFactory;
bf.setAutowireCandidateResolver(autowireCandidateResolver);
}
public AutowireCandidateResolver getAutowireCandidateResolver() {
return autowireCandidateResolver;
}
public void setAutowireCandidateResolver(
AutowireCandidateResolver autowireCandidateResolver) {
this.autowireCandidateResolver = autowireCandidateResolver;
}
}
<bean id="autowireCandidateResolverConfigurer" class="AutowireCandidateResolverConfigurer">
<property name="autowireCandidateResolver">
<bean class="ProxyAutowiredCandidateResolver" />
</property>
</bean>
If I'm reading this correctly, you should be able to define them in a JavaConfig #Configuration annotated class and then use them elsewhere.
From the docs (Spring):
#Configuration
public class AppConfig {
#Bean
public MyService myService() {
return new MyServiceImpl();
}
}
You could do something similar:
#Configuration
public class InterfaceConfig {
#Bean
public HelloWorldInterface helloWorldInterface() {
return MyProxyUtil.getInstance(HelloWorldInterface.class);
}
}
At that point, Spring would use that definition whenever that bean was needed.
You'd have to link in the #Configuration class somehow (classpath scanning, programmatically, etc), but that depends on how you're setting up your application context.
I think this should work. I've used JavaConfig quite a bit, but never quite like this. But it seems reasonable.
Given the following:
public class ResourceOne implements AutoCloseable {...}
with an instance of ResourceOne instantiated in (Spring) XML config.
How should this object (when autowired) be used with the "try-with-resources Statement", since you are required to instantiate the resource in the try block?
One approach could be to use a reference (see below), but this isn't really optimal.
public class Test {
#Autowired
ResourceOne test;
//...
public void execute()
{
//...
try (ResourceOne localTest = test)
{
localTest.init()
localTest.readLine();
//...
}
}
AFAIK I think the approach that you have taken seems to be the only way.
try (ResourceOne localTest = test)
{
localTest.init()
localTest.readLine();
//...
}
I am assuming that you have your autowired resource declared with prototype scope though right.
#Bean
#Scope(value="prototype", proxyMode=ScopedProxyMode.DEFAULT)
public Resource1 resource1() {
return new Resource1();
}
A solution could be to autowire the spring application context and have it retrieve an instance of the bean at runtime.
public class Test {
#Autowired
ApplicationContext applicationContext
//...
public void execute()
{
//...
try (ResourceOne localTest = applicationContext.getBean(ResourceOne.class))
{
localTest.init()
localTest.readLine();
//...
}
}
This way you don't risk having a non-functional instance of ResourceOne in your code that could potentially be used again from another method and result in an exception because is't already been closed.