I am using Spring3.1
My application will have kind of bean-manager.
That manager will be able to retrieve request and on each request I need to create new instance of bean dynamically which will be initiate with it's own unique params.
The params will be retrieved via the request method.
This bean must be alive and work asynchronously. (For example it will listen to jms calls, execute methods by demand and so on..)
Moreover I want to have the option to destroy beans also.
Those bean could be resemble as sessions so when the user log off i will destroy those beans.
I understand that I have to create some kind of bean-list or beans pool and manage it with some kind of manager.
How can I create those beans dynamically and have them remain them alive until I destroy them?
Any idea how could I implement such thing?
Well in this sense, the easiest way would be to create a StaticApplicationContext setting its parent context as the common context (the one holding the beans you want to share over all). This you could reach by doing something like:
StaticApplicationContext innerContext = new StaticApplicationContext(parentContext);
after this, you probably want to declare the bean you want to instantiate over Spring in order to attach all the AOP stuff, Autowiring and other functionalities, therefore you will need to do something like:
innerContext.registerSingleton("beanName", beanClass);
After registering you could instantiate the bean like:
innerContext.getBean(beanClass);
Of course there is the implementation of scope Session for spring and therefore I advise you to check the WebApplicationContext documentation, method loadParentContext that you basically pass the ServletContext as paramenter.
I've also found many trouble in creating a bean dynamically at run-time and used it anywhere in application..
Here is complete code
static ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "Spring-Question.xml" });
static StaticApplicationContext innerContext = new StaticApplicationContext(appContext);
Create the bean and set the values e.g.
innerContext.registerSingleton("beanName", Test.class);
Test test = innerContext.getBean(Test.class);
test.setA(3);
test.setB(4);
Then Re-Use the bean anywhere in application....
Test test = innerContext.getBean(Test.class);
System.out.println(test.setB(4));
Related
I am new to Spring and have a project where I am trying to inject something like the following beans:
ProductHandle selectedProduct
List<ProductHandle > allProducts
When I try to have a List<ProductHandle> autowired into another class, it injects a List containing selectedProduct, rather than the list I actually want. This is even though the name of the autowired property is called allProducts, so I thought this would identify the correct bean.
How would I go about achieving what I want?
--
Edited to show that it isn't just a case with Strings - this is a more generic and hopefully less offensive case..
--
Note beans are being registered as so, since the values are being parsed from command line args.
mySelectedProduct is a ProductHandle
allMyProducts is a List<ProductHandle>
try (final AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
ctx.registerBeanDefinition("selectedProducts", BeanDefinitionBuilder
.rootBeanDefinition(ProductHandle.class, "create")
.addConstructorArgValue(mySelectedProduct)
.getBeanDefinition());
ctx.registerBeanDefinition("allProducts", BeanDefinitionBuilder
.rootBeanDefinition(Lists.class, "asList")
.addConstructorArgValue(allMyProducts)
.getBeanDefinition());
ctx.refresh();
final MyApp app = ctx.getBean(MyApp.class);
app.run();
}
Using standard data structures as Spring beans is an antipattern, don't do it. (Read here about "stringly typed" software)
Either inject the list as a #Value, or wrap it in a custom object that expresses the intent.
Regarding your updated question:
If you have a bean of type X, and register a dependency of type List<X>, Spring will inject a list of all dependencies of the supplied type.
While this is a very handy feature, it's also one more reason never to define standard data structures (like Lists) as Spring Bean. Wrap your list in a custom object and you should be fine.
Also: ProductHandle sounds like it's a business object. Usually, you should not let Spring manage these, but rather the services that act on business objects. Typically, Spring would know about a ProductRepository, or a ProductService, but not a Product or ProductHandle.
The web layer is a notable exception to this rule, but even there, business objects should be method parameters, not Spring beans.
Env:
Wildfly 8.2.0 Final
JDK 8
Java EE 7
Please note that by 'POJO' i am referring to the classes that serve the other classes i.e other than value objects, entities.
This question was on back of my head for some time. Just wanted to put it out.
Based on CDI and Managed Beans specs and various other books/articles, its pretty clear that CDI injection starts with a 'managed' bean instance. By 'managed' i mean servlet, EJBs etc. which are managed by a container. From there, it injects POJOs (kind of crawl through layers) till every bean gets its dependencies. This all makes very sense to me and i see very little reason why developers ever need to use "new" to create an instance of their dependent POJO's.
One scenario that comes to my mind is when developer would like to have logic similar to
if(something) {
use-heavy-weight-A-instance
} else {
use-heavy-weight-B-instance
}
But, that also can be achieved via #Produces.
Here is one scenario that i verified to be true in wildfly 8.2.0 Final i.e. CDI is not able to inject bean when the JSP has
<%!
#Inject
BeanIntf bean;
%>
But, the alternative to use a servlet works fine.
That said, would like to know if there is any scenario(s) where a developer has to use 'new'. As i understand, by using 'new', developer owns the responsibility of fulfilling dependencies into that bean and all its dependent beans, and their dependent beans etc..
Thanks in advance,
Rakesh
When using CDI or other container you don't use new, because you expect a bunch of service coming from the container.
For CDI these main services are:
Injection of dependent beans (get existing instance or create a new
instance)
Lifecycle callback management (#PostConstruct and
#PreDestroy)
Lifecycle management of your instance (a #RequestScoped bean will make container produce an instance leaving until the end of request)
Applying interceptors and decorators on your instance
Registering and managing observers methods
Registering and managing producers methods
Now, on some rare occasion, you may want to add a part of these services to a class you instantiate yourself (or that another framework like JPA instantiate for you).
BeanManager bm = CDI.current().getBeanManager();
AnnotatedType<MyClass> type = bm.createAnnotatedType(MyClass.class);
InjectionTarget<MyClass> it = bm.getInjectionTargetFactory(type).createInjectionTarget(null);
CreationalContext<MyClass> ctx = bm.createCreationalContext(null);
MyClass pojo = new MyClass();
injectionTarget.inject(instance, ctx); // will try to satisfied injection points
injectionTarget.postConstruct(instance); // will call #PostConstruct
With this code you can instantiate your own MyClass containing injection points (#Inject) and lifecycle callbacks (#PostConstruct) and having these two services honored by the container.
This feature is used by 3rd party frameworks needing a basic integration with CDI.
The Unmanaged class handle this for you, but still prevent you to do the instantiation ;).
I'm wondering if there is possibility to recreate a bean which was already created in java configuration on web app startup.
What I want to do is to reconfigure bean settings.
For example I create new bean with path to database:
#Bean
public TestBean getTestBean() {
TestBean tb = new TestBean("some_path_taken_from_external_point");
return tb;
}
During runtime I want to change the path. Let's assume that this bean doesn't have the setter method for database path.
I will have some kind of event and a listener for this event. Listener should reinitialize TestBean with new path.
Is this possible?
I was thinking of some kind of wrapper. In such case I would have class TestBeanWrapper which will have method get() which will return TestBean instance and recreate(String path) which will create new object with given path.
I'm not sure exactly if such wrapper would work for me, as the TestBean is a class from external library, and I'm not sure if it's not injected somewhere (but probably it's not injected).
More possible is that the other beans may rely on TestBean, so they also must be reinitialized (in case if they won't have setters for my TestBean).
Is this even possible in Spring (4.1) ? What is the best approach for such cases?
So I'm still unsure why you would want to change the path but I have 2 suggestions:
1. Look at setting the scope on the Bean.
By setting the scope on the bean, you can regenerate the bean based on context. Look at Bean Scopes for more information.
2. Look at maybe using a controller or a service.
Controllers and services allow getters and setters which may give you more control.
I have a java file "DatabaseMan.java" that helps connect to a database and connects helper functions. How can I make it such that it is created once for the life of my spring application, and I can call of its methods "getAllRows" for example, in each of my other resource classes?
Should I be declaring a bean in my Application.java or using some sort of annotation on my "DatabaseMan" class to indicate that it is "injectable"/"resusable"?
I see the following Spring3 example:
http://www.mkyong.com/spring3/spring-3-javaconfig-example/
The issue is, do I have to include this within every single resource:
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
HelloWorld obj = (HelloWorld) context.getBean("helloBean");
obj.printHelloWorld("Spring3 Java Config");
Is there a better way to get to the "HelloWorld" with less code and more annotation in Spring 4?
Remember, the ApplicationContext is a container to manage all your beans and their inter-dependencies. It is the entry point to your application. Once you've set it up, all the managed objects are linked up and ready to go.
Is there a better way to get to the "HelloWorld" with less code and more annotation in Spring 4?
It depends where you want to get it. If you want to get it from outside the ApplicationContext, then you need to do what you did. If you want to get into another bean, just inject it and the ApplicationContext will do the rest.
#Component
class SomeOtherBean {
#Autowired
private HelloWorld helloWorldBean;
// do something with it
}
Writing a small web-app in Grails I encountered a problem with global objects. I have a class which runs threads - ExecutorService with queuing.
The problem is where to create an object of this class, to have it available in Controller?
I've tried at init (BootStrap) but there's no chance then of getting its instance anywhere else.
In general - what I need is an object in one single instance for whole application, with access from Model and/or Controller.
In general - what I need is an object in one single instance for whole application, with access from Model and/or Controller.
The standard way to achieve this is to declare the object as a Spring bean in grails-app/conf/spring/resources.groovy
threadPool(java.util.concurrent.Executors) { bean ->
bean.factoryMethod = "newCachedThreadPool"
}
Then in controllers/services/etc. you can inject this bean the same as you would with grails services, i.e.
def threadPool
But in this case you may find it easier simply to use the executor plugin, which defines such a bean for you and handles the intricacies of ensuring there is a valid GORM session available to the background tasks.
Why not wrap your Executorservice inside a Spring Bean, or using something like:
grailsApplication.controllerClasses.each {controller ->
controller.metaClass.executorService = { ->
executorService
}
}
Actually I have come to something before checking answers.
For a given domain class (Example) and controller (ExampleController) create
ExampleService
and simply include all the needed things there. Set behaviour to #Singleton (default).
Then in Controller inject the instance as follows:
def exampleService