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.
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.
Related
I can not understand the following documentation sentence
(...) the registration of new beans at runtime (concurrently with live
access to the factory) is not officially supported and may lead to
concurrent access exceptions, an inconsistent state in the bean
container, or both.
I understand that it can't be injected at runtime, but previously we can read in the documentation:
In addition to bean definitions that contain information on how to
create a specific bean, the ApplicationContext implementations also
permit the registration of existing objects that are created outside
the container (by users). This is done by accessing the
ApplicationContext’s BeanFactory through the getBeanFactory() method,
which returns the BeanFactory DefaultListableBeanFactory
implementation. DefaultListableBeanFactory supports this registration
through the registerSingleton(..) and registerBeanDefinition(..)
methods.
So how to implement this form of injection, not at the runtime. Now I'm confused.
I might not be the right person to answer this, but I would like to give a link where it has been answered beautifully, take a look might be the similar thing you asking.
bean injected dynamically
I'm studying spring beans and came across #Lookup, it says:
If we happen to decide to have a prototype Spring bean, then we are
almost immediately faced with the problem of how will our singleton
Spring beans access these prototype Spring beans?
hmm, I don't get it, because when I studied scope=prototype it says:
4.4.2 The prototype scope
The non-singleton, prototype scope of bean deployment results in the creation of a new bean instance every time a
request for that specific bean is made
so it seems i misinterpreted the words:
a request for that specific bean is made
actually programming in spring framework every line of the code is inside of some bean (i.e. #controller, #Service, etc), isn't it?
And almost all of them are singletons, isn't it?
So if I need prototype I just make scope=prototype and almost everytime it's injected to another bean (i.e. #controller, #Service, etc) isn't it?
So please give a real world scenarios, 1) when one should use #Lookup and 2) when it's not needed
Ok for the 1) the scenario:
#Component
#Scope("prototype")
public class SchoolNotification {
// ... prototype-scoped state
}
#Component
public class StudentServices {
// ... member variables, etc.
#Lookup
public SchoolNotification getNotification() {
return null;
}
// ... getters and setters
}
Please, show me scenario for the 2) case, and explain please the difference
Thank u
The implicit Bean scope in Spring is Singleton.
That means for a JVM instance, only a single instance of a Bean exists in memory (theoretically).
When you #Autowire a Prototype-scoped Bean inside a Singleton-scoped Bean, that Prototype one becomes a sort-of-singleton. Just think about it; a Singleton gets created, its injectable fields get Autowired, and that is it, the instance lives forever along with all its fields (keep in mind those Prototype-scoped fields are "pure" instances, they're not proxied).
#Lookup
is a proxy-driven annotation. What that means is Spring will extend your class using JDK proxies or CGLIB proxies, and it will override/implement the #Lookup-annotated method, providing its own version which uses a BeanFactory#getBean each time it is invoked.
The documentation is clear on this point
An annotation that indicates 'lookup' methods, to be overridden by the
container to redirect them back to the BeanFactory for a getBean call.
Thus, that means a fresh Bean instance is returned every time.
Just for your knowledge, another approach for working with Prototype-scoped Beans inside "other"-scoped Beans is using ProxyFactoryBean. The only difference is that the proxy is created at configuration-time, and then made available for direct #Autowireing, thus not requiring the definition of a #Lookup method, which sometimes is not wanted (usually by folks that are obsessed with clean code, like me).
I'm using Spring 3.1.1 and in my business logic, I have a loop which requires a new instance of a spring bean (prototype scope) for each iteration.
What is the best method to do this? Must I create my own BeanFactory class which I can inject once into my class, and call upon it every time to produce the bean upon request? When looking at the Spring 3 docs, it seems to imply that I should use ApplicationContext instead. However, using ApplicationContext makes my code Spring dependent.
What is the best method for something like this? Does Spring already provide a factory of sorts that I can leverage?
ApplicationContext is the factory. You don't have to inject it into your class; you instantiate one and use it to create the beans and wire up their dependencies.
I don't understand the comment "using ApplicationContext makes my code Spring dependent." Yes, it does. Do you think DI is worth it or not?
I think you should go with spring. Spring facilitates your need. You can use a method to lookup bean of specific type from application context. So if you make that bean to be prototype. then when you call this special method, you will be returned with a new instance of the bean you want.
You will find it indetails here!
You can use custom scope and make the injecting bean proxy, and on the custom scope bean listen to some dynamic events that can inject the underling proxy bean
I have some beans for which, in specific injections, I want to add a given interceptor.
I was naïvely thinking there was something like a #Interceptors annotation that could allow me to write
private #Interceptors(Logging.class, Connection.class) #Inject MyBean instance;
Unfortunatly, Weld documentation clearly states the opposite.
So, how could I inject an intercepted version of my bean ? Is it possible using a cdi Instance object ?
EDIT
Although LightGuard's answser is really relevant, it doesn't totally answser my question, so let me rephrase it.
I want to have an annotation that triggers some kind of method call event sending. For that, I created a CDI Interceptor, complete with its own interceptor binding (let's say interceptor is called SenderInterceptor, and the binding is called SenderBinding). What I want now is to add a CDI qualifier (let's call it SenderQualifier) that, when used for an injection, installs SenderInterceptor.
To be more clear, I want the following code to use SenderInterceptor
/* calling any method of that bean should trigger an event */
private #Inject #SenderQualifier MyBean aBean;
while this one doesn't
private #Inject MyBean aBean;
What I tried so far was
detecting fields requiring those injections using reflections library (that works)
create using seam solder an AnnotatedType from bean class (during the BeforeBeanDiscovery event) (the type is created, but not really distinguishable from the initial one) and giving that AnnotatedType the interceptor binding annotation.
create using seam solder (again) a Bean from generated AnnotatedType, and giving it the required qualifier annotation
All seems to worrk, except it's the original bean which gets injected.
I could of course replace original one with intercepted one, but there are some cases where such interception is not required, so I have to keep both AnnotatedType refering the same concrete type. I was thinking I coulld do that in CDI, but it doesn't seems to work (as original type is never replaced by intercepted one).
What you would need to do:
Add the interceptor to beans.xml so it's activated
Create an extension to add the interceptor binding or the interceptor annotation to the type in ProcessAnnotatedType life cycle event. You'll need to call getAnnotatedType, add the annotation(s) then call setAnnotatedType. I strongly recommend looking at Seam Solder or Apache DeltaSpike project for the AnnotatedTypeBuilder to make this easier.
Possibly, you could try #Inject MyInterceptedBean instance;, where the interceptors are listed with the MyInterceptedBean?
(Caveat: this does not look right, though, using inheritance for types that only differ in annotations ... probably acceptable when it's always the two stated same annotations and not different annotations in each case.)
Consider a line of code like this
AutomobileDriver ad=(AutomobileDriver)appContext.getBean("increaseSpeed");
Assume there is an IncreaseSpeed class which inherits from AutomobileDriver class
What does getBean do? What is the main function of this?
In "simple layman's terms":
This assumes that Spring was told to create an object instance (possibly in an XML config file) that is identified (by Spring) as with the id "increaseSpeed" and has a class or parent class of AutomobileDriver.
You are asking the Spring context for a reference to (a) by default, the previously created object (this is called a singleton) or (b) a new instance of that object (prototype).
In Spring, you can define a bean and give it an id. Usually, Spring would prefer that you use dependency injection to access the bean. However, Spring provides getBean as another way to access a bean by its id.
Basically, your code will return an instance of the bean with id "increaseSpeed".
This code is requesting the bean named increaseSpeed from the Spring Application Context. Think of the application context as the pool of available objects, which has been configured from your Spring configuration XML. When the application context is started, it creates the beans in the configuration. This call simply asks for the one which is already there. The application context returns this "bean" as a java.lang.Object so you have to cast it to the appropriate type.
You might see this call as an entry point in a Spring application. This call is needed to get the first object out from the application context - from there, this object may have links to other objects which have been injected by Spring.
A bean is a component that provides some functionality, the name of the bean indicates that it would be increase speed.
Those components are registered in a context called 'application context' and can be looked up by name. So if you want to increase the speed look at your apps-context for something that could do this.
More tecnical:
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/