0

I want to refresh bean (destroy, initialize) if some property is changed, for example db url connection. The problem is that this bean might be already injected in other beans in CDI container. I have 2 thoughts about this: 1. If bean is proxied - destroy target for this proxy, re-initialize target inside this proxy. 2. For @Singleton and @Dependent beans, because they are not proxied, I can wrap such beans in proxy and do the same as above. The reason I want to wrap it in proxy is that when property changed and I want to recreate real object, I should also know all dependent beans that have dependency on my bean. So my questions are: 1. How to replace real object inside proxy in CDI? or 2. If I dont want to keep proxy as I explained above, how to create proxy object for my bean and re-inject it to all dependent beans in CDI container?

This is my previous question: Re-inject CDI bean if some injected property changed

Again, I use CDI (Weld), not Spring IoC, so I can not use @RefreshScope from Spring cloud config, but I think my expected functionality can be similar with using custom scope.

Igor Dumchykov
  • 347
  • 1
  • 15

1 Answers1

0

For @DependedSCoped beans you can use class MyBean {

   @Inject
   private Instance<MYType> myTypeInst;

   // This will ensure, that the bean is always fresh created.
   // But the property value on the former instance will be lost
   // So the changable value has to be provided another way to the created bean
   public void do SomeThing(){
      MyType bean = myTypeInst.get();

      myTypeInst.destroy(bean);
   }
}

If you use a @Depended scoped bean, then you must be aware that the injection target gets its instance which is exclusively for this bean, so who is changing the value? Is the @Dependend scope the right scope for your use case?

It should not be necessary to provide an own proxy or hack into an existing one, just find the proper scope for your use case and implement the bean properly. If a connection url can change then the bean managing the connection must be aware of a change and recreate the connection and the beans using this bean need to retrieve the connection each time the use it.

Maybe you could provide an description of your use case, then we maybe can you provide you with an better answer.

Conclusion

As the use case became clear (see comments below), it resulted in the intention to implement a custom scope, because CDI doesn't seem to provide a suitable scope for this use case. I recommend to try to find a provided CDI scope if possible and implement a custom scope only if necessary, because you will have to take care about the lifecycle of your beans, management of your scope and how the beans, managed by your scope, can and will be used by an application. If not implemented with care a custom scope could cause problems such as memory leaks, if for instance your beans are not properly discarded after usage.

Thomas Herzog
  • 506
  • 2
  • 6
  • I have centralized configuration server and client. There is a scheduler in client part, that fetches properties from configuration server. If some property changed (let`s say db connection url), then client generates event . There is a listener that handles this event. Once event comes, listener should find bean with injected url and re-inject this property. Because url is used by some DbConnection bean, it should be destroyed and recreated with new url. When I say destroy and recreate I mean that there are PreDestroy and PostConstruct logic that should be called during bean recreation. – Igor Dumchykov Apr 01 '19 at 01:01
  • Ok, now I understand the user case. – Thomas Herzog Apr 01 '19 at 09:00
  • Are you sure you cannot achieve that with CDI scopes other than @Depended? Is it valid that the DBBean is request scoped which means that the db connection does not change within a request? Each request a CDI Bean gets a new DBBean instance. If not than maybe the CDIBean using the DBBean should call getConnection() on the DBBean and the DBBean decides when to create a new connection due to a url change. The event sets the property on a @ApplicationScoped Config bean which is used by the DBBean, where the DBBean retrieves the connection url for each request, when it gets instantiated. – Thomas Herzog Apr 01 '19 at 09:10
  • Yes, you`re right. But there is one small additional requirement I forgot to tell: I`m writing common library for CDI based web applications. They will include it as a maven dependency. DBBean was an example bean used in web application. So during lib implementation I should rely on the most generic way to handle property change event. I think that custom scope creation would be the best solution in my case. – Igor Dumchykov Apr 01 '19 at 10:59
  • How about implementing producer for different scopes which are qualified with @RequestScopedDBConnection and so on? Another way is to dynamically add/remove all beans from the bean manager, which I think will only affect beans newly injected and not already injected ones. I will take look for such an implementation, I think I saw one ones – Thomas Herzog Apr 01 '19 at 13:42
  • Maybe this is helping you as well https://stackoverflow.com/questions/8420070/how-to-create-and-destroy-cdi-weld-managed-beans-via-the-beanmanager – Thomas Herzog Apr 01 '19 at 13:47
  • I also start to think you need an own scope or use an existing one, so that you can access the bean instances via Instance or via your own scope to modify the beans properties. Nevertheless you need to take care how the beans are accessed and when the property gets changed, this could cause problems. @Dependend scoped beans shouldn't be accessible anymore after injection. Maybe this article and github repository helps you to implement your custom scope https://tomitribe.io/projects/microscoped, https://github.com/tomitribe/microscoped – Thomas Herzog Apr 01 '19 at 17:32
  • Oh, yeh, I saw this article. And I think I`ll use it if will decide to create custom scope. – Igor Dumchykov Apr 01 '19 at 18:08
  • Then good luck :) I always wanted to implement a custom scope myself. – Thomas Herzog Apr 01 '19 at 18:17