I have a Java Spring Configuration class like this. I want to set a variable that several of my beans depend on, turn it into a bean, and use it as a dependency. How can I make the setVariable() method happen first? I'm converting my code from Guice, where this variable was being set in the overridden 'Configuration' method. Does Spring have something like that?
#Configuration
class SpringConfiguration{
String variable;
public void setVariable(){
variable = System.getenv("whatever")
}
#Bean
public void variable(){
return variable;
}
#Bean
public void myService(){
return new MyService(variable);
}
#Bean
public void myService2(){
return new MyService2(variable);
}
You can do something like this :
#Configuration
class SpringConfiguration {
#Bean(name="variable")
public String geVariable() {
return System.getenv("whatever");
}
#Bean
#DependsOn("variable")
public MyService getMyService() {
return new MyService(geVariable());
}
#Bean
#DependsOn("variable")
public MyService2 getMyService2() {
return new MyService2(geVariable());
}
}
Like that you can insure that variable will be initialized before service1 and service2, note that DependsOn in this case is just for clarification purposes.
Related
I want to use a mechanism for create a one time compute function. I try to use Spring Caching. But it does not working. Please help me to solve this problem. My code like as below,
Gradle Dependency
compile 'org.springframework.boot:spring-boot-starter-cache'
Main Class of Spring Boot Application
#SpringBootApplication
#EnableCaching
public class Application {
public static ApplicationContext applicationContext;
public static void main(String[] args) {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
// todo: Try to save response text and request body
applicationContext = SpringApplication.run(Application.class, args);
}
#Bean
WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/**")
.addResourceLocations("classpath:/")
.setCacheControl(CacheControl.maxAge(3600, TimeUnit.SECONDS).noTransform().mustRevalidate());
}
};
}
}
My Coputational property and Test method
public String test(){
return hello();
}
#Cacheable("hello")
public String hello(){
System.out.println("hello");
return "Hello";
}
The #Cacheable annotation caches the values when it is called from outside your #Bean so calling it from another method inside your bean will not work.
try something like
#Bean
public class CachingBean {
#Cacheable("hello")
public String hello(){
System.out.println("hello");
return "Hello";
}
}
#Service
public class CallerService {
#Autowired
private CachingBean cachingBean;
// Setters, constructors...
public String test(){
return cachingBean.hello();
}
}
And then it should work.
That's because the #Cacheable annotation creates a proxy around the method call when it is injected as a Bean, so a direct call (to an instance created directly) or an internal call are not intercepted and the caching mechanism does not even see those calls.
I still sometimes forget about it and get biten by it at the beginning :).
Cheers!
Consider the following piece of code
public interface Iface1 { }
public interface Iface2 { }
public class A implements Iface1, Iface2 {
}
#Configuration
public class AutoConfig {
#Bean
Iface1 provideIface1Impl() {
return new A(); // instance no 1234
}
#Bean
#ConditionalOnBean(A.class)
#Autowired
Iface2 provideIface2Impl(A aImpl) {
return aImpl;
}
}
I would like the second #Bean method to be autowired with the instance from the first one (1234) and I'd like the second #Bean method to return the same instance, so that I can use the same instance for clients of Iface1 and Iface2.
Current problem is that spring doesn't run the second #Bean because there is no #Bean of type A.class - the created bean is considered as Iface1 even though it is of type A.
Just define bean A. When injecting IFace1 and Iface2 they will automatically resolve to A (if A is the only implementation of course).
#Bean
public A a() {
return new A();
}
I think you should try to define only one #Bean. It will create a singleton:
#Bean
public A a() {
return new A();
}
Then just use the name of this bean in #Qualifier annotation:
#Autowired
#Qualifier("a")
private Iface1 iface1;
#Autowired
#Qualifier("a")
private Iface2 iface2;
Additionally to what others have answered, I'd like to cover that part of the question that touches bean's dependencies.
To inject a dependency to a #Bean-annotated method, there are two ways:
Call another #Bean-method directly
Add parameter to the method
Examples of both:
#Configuration
public class AppConfig {
#Bean
public Foo foo() {
return new Foo();
}
#Bean
public Bar bar() {
return new Bar(foo());
}
#Bean
public Baz baz(Foo foo) {
return new Baz(foo);
}
}
So your provideIface2Impl could look like this:
#Bean
Iface2 provideIface2Impl(A aImpl) {
return aImpl;
}
// or...
#Bean
Iface2 provideIface2Impl() {
return (Iface2)provideIface1Impl();
}
But don't use it this way, it will lead to subtle bugs like double-proxying or "No unique bean of type" error, etc. Prefer what Gorazd suggested.
Case 1
Let's consider the following Spring configuration:
#Configuration
public class MyConf1 {
#Bean
public Foo getFoo() {
// Foo class is defined as part of an external lib.
return new Foo();
}
#Bean
public Bar getBar() {
return new Bar(getFoo());
}
}
For some reasons, I need to invoke a Foo's method (i.e. myFoo.shutdown();) when MyConf1 is destroyed.
Is there any way to perform this operation without retrieving the bean instance directly from the application context (via ApplicationContext.getBean())?
Case 2
Again, let's consider a second Spring configuration class:
#Configuration
public class MyConf2 {
#Bean
public ScheduledJob scheduledJob() {
Timer jobTimer = new Timer(true);
return new ScheduledJob(jobTimer);
}
}
This time, I need to invoke jobTimer.cancel() before destroying MyConf2. Indeed, I can instantiate jobTimer outside scheduledJob(), or making it a method's parameter, as scheduledJob(Timer jobTimer).
It will then be possible to define a proper destroyer method for MyConf2. However, I would like to know if there are other ways to proceed.
Any good suggestion?
Note: Foo, Bar, Timer, ScheduledJob classes are defined externally. Thus, there is no possibility to explicitly define an inner destroy method. As assumption, I can modify only MyConf1 and MyConf2.
I would suggest defining a destroy() method (annotated with #PreDestroy) in Foo class
Similarly, modify ScheduledJob class like
public class ScheduledJob {
private Timer timer;
public ScheduledJob(Timer timer){
this.timer = timer;
}
#PreDestroy
public void destroy(){
timer.cancel();
}
}
And add destroyMethod param in #Bean
#Configuration
public class MyConf2 {
#Bean(destroyMethod = "destroy")
public ScheduledJob scheduledJob() {
Timer jobTimer = new Timer(true);
return new ScheduledJob(jobTimer);
}
}
Please see the following page http://forum.spring.io/forum/spring-projects/container/48426-postconstruct-and-predestroy-in-javaconfig
DisposableBean should help you with case #1.
You can implement the DestructionAwareBeanPostProcessor interface that can adds a before-destruction callback when the bean is destroy.In that interface,the method postProcessBeforeDestruction is do that,see the following:
#Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
System.out.println("before destory:"+bean);
}
#Override
public boolean requiresDestruction(Object bean) {
return true;
}
Pay attention to that the method requiresDestruction should return true,otherwise the method postProcessBeforeDestruction will not call when bean should destroy.
And i have a test:
public static void main(String[] args){
ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:application-main.xml");
applicationContext.registerShutdownHook();
}
The postProcessBeforeDestruction really call when the bean is destroy.The output is :
before destory:com.zhuyiren.spring.learn.util.Handler#55141def
before destory:com.zhuyiren.spring.learn.controller.TestControleler#47eaca72
before destory:com.zhuyiren.spring.learn.service.impl.TestServiceImpl#7b2bbc3
before destory:com.zhuyiren.spring.learn.service.impl.TwoServiceImpl#48f2bd5b
before destory:com.zhuyiren.spring.learn.controller.ConverConroller#72967906
before destory:org.springframework.context.event.DefaultEventListenerFactory#1a482e36
before destory:org.springframework.context.event.EventListenerMethodProcessor#77fbd92c
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;
}
}
Assume we have two spring config files: ConfigA.java and ConfigB.java.
Here's how ConfigA.java may look like:
#Configuration
class ConfigA {
#Scope("prototype")
#Bean public Foo fooPrototype() {
return new Foo(params);
}
}
And now I want to inject a few instances of Foo to a number of singleton-scoped beans declared in ConfigB.java:
#Configuration
#Import(ConfigA.class)
class ConfigB {
#Bean public Bar bar() {
return new Bar(*** how to inject Foo instance here? ***);
}
#Bean public Buzz buzz() {
return new Buzz(*** how to inject Foo instance here? ***);
}
}
If I had a single configuration file, I would simply replace the blocks enclosed in asterisks with fooPrototype().
But, how to inject different Foo instances to bar() and buzz() beans provided fooPrototype() is declared in a different configuration file?
This looks similar to the example in the Spring documentation ยง5.12.5 Composing Java-based configurations.
This same page gives a solution: You can autowire the configuration beans.
#Configuration
#Import(ConfigA.class)
class ConfigB {
#Autowired ConfigA configA;
#Bean public Bar bar() {
return new Bar(configA.fooPrototype());
}
#Bean public Buzz buzz() {
return new Buzz(configA.fooPrototype());
}
}
Can't you just pass fooPrototype as a method arg? E.g.:
#Bean public Bar bar(Foo fooPrototype) {
return new Bar(fooPrototype);
}
#Bean public Buzz buzz(Foo fooPrototype) {
return new Buzz(fooPrototype);
}