I am new in spring and have to use spring annotations all through the project. I need to create a list of beans. I do not have option to use context.getBean("..") from the class where I have to create the list.
The problem is :
I have 3 classes: Processor, Reader, Writer. I have to create a list of writers inside the processor class.
This is what I am looking for : ( trying to #Autowire 'RoxourReader readerThread' and 'List writerThreads' but don't know how determine the size of the list and need to add the name as well)
package company.online.Roxour.api.operation;
{
#Component
#Scope("singleton")
public class RoxourProcessor
{
.........
private int PAYLOAD_SIZE;
private int MAX_READER_THREADS;
private int MAX_WORKER_THREADS;
#Autowired
ApplicationEnvironment applicationEnvironment;
#Autowired
RoxourUtil util;
//I wish to have something like this
#Autowired
RoxourReader readerThread
//I wish to have something like this
#Autowired
List<RoxourWriter> writerThreads;
#PostConstruct public void initialize()
{
PAYLOAD_SIZE = applicationEnvironment.getPayloadSize();
MAX_READER_THREADS = applicationEnvironment.getMaxReaderThreads();
MAX_WORKER_THREADS = applicationEnvironment.getMaxWorkerThreads();
}
..............
}
}
Reader class looks like :
package company.online.Roxour.api.operation;
{
#Component
#Scope("prototype")
public class RoxourReader extends Thread
{
.........
#Autowired
ApplicationEnvironment applicationEnvironment;
public RoxourReader( String name)
{
this.name = name;
}
..............
}
}
And the writer class looks like :
package company.online.Roxour.api.operation;
{
#Component
#Scope("prototype")
public class RoxourWriter extends Thread
{
.........
#Autowired
ApplicationEnvironment applicationEnvironment;
public RoxourWriter( String name)
{
this.name = name;
}
..............
}
}
context.xml has:
<!-- Scans within the base package of the application for #Components to configure as beans -->
<context:component-scan base-package="company.online.Roxour.api"/>
According to current implementation, this is the way we are creating the treads:
private void createAllThreads()
{
readerThread = new RoxourReader( "Reader " + 1 );
writerThreads= new RoxourWriter[ MAX_WORKER_THREADS ];
for ( int i = 0; i < MAX_WORKER_THREADS; i++ )
{
writerThreads[ i ] = new RoxourWriter( "Uploader " + i);
}
}
Is this possible? Please advise me a different approach with annotations otherwise.
Thanks
When you use a IoC framework like Spring, you leave the task of bean creation to Spring. So you shouldn't use new keyword, this is made by Spring automatically.
Instead you should get your beans through context.getBean("beanname") or
injecting the bean with #autowired.
Here there is an example or Spring with threads (There is 3 good examples)
http://www.mkyong.com/spring/spring-and-java-thread-example/
And here there is the definition of task executors.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html
To begin with,
public class RoxourReader extends Thread
{
is not a good idea, because you are not extending the Thread behavior. Instead make it
public class RoxourReader implements Runnable
{
and when you use the keyword new to create an object, then Spring is not actually managing it.
So change the lines
new RoxourReader... &
new RoxourWriter
to Autowired (or) getBeans methods like
private void createAllThreads()
{
readerThread = getReaderBean("readerBeanName");
writerThreads= new Runnable[MAX_WORKER_THREADS];
for ( int i = 0; i < MAX_WORKER_THREADS; i++ )
{
writerThreads[ i ] = getWriterBean("Uploader " + i);
}
}
And your getBeans methods would look like,
public Runnable getReaderBean(){
Runnable obj= applicationContext.getBean("RoxourReader");
return obj;
}
public Runnable getWriterBean(){
Runnable obj= applicationContext.getBean("RoxourWriter");
return obj;
}
Since your scope is Prototype for both reader and writer beans already, you will get a new bean instance.
Related
I'm new to spring and doing some study about proxyMode=ScopedProxyMode.TARGET_CLASS. I wrote a simple project to test this with singleton and prototype bean. But it prints a new prototype bean instance when I print the object.
public class SimplePrototypeBean {
private String name;
//getter setters.
}
Singleton bean
public class SimpleBean {
#Autowired
SimplePrototypeBean prototypeBean;
public void setTextToPrototypeBean(String name) {
System.out.println("before set > " + prototypeBean);
prototypeBean.setText(name);
System.out.println("after set > " + prototypeBean);
}
public String getTextFromPrototypeBean() {
return prototypeBean.getText();
}
}
Config class.
#Configuration
public class AppConfig {
#Bean
SimpleBean getTheBean() {
return new SimpleBean();
}
#Bean
#Scope(value = "prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
public SimplePrototypeBean getPrototypeBean(){
return new SimplePrototypeBean();
}
}
Unit test
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = AppConfig.class)
public class SimpleConfigTest {
#Test
public void simpleTestAppConfig() {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
for (String beanName : ctx.getBeanDefinitionNames()) {
System.out.println("Bean " + beanName);
}
SimpleBean simpleBean1 = (SimpleBean) ctx.getBean("getTheBean");
SimpleBean simpleBean2 = (SimpleBean) ctx.getBean("getTheBean");
simpleBean1.setTextToPrototypeBean("XXXX");
simpleBean2.setTextToPrototypeBean("YYYY");
System.out.println(simpleBean1.getTextFromPrototypeBean());
System.out.println(simpleBean2.getTextFromPrototypeBean());
System.out.println(simpleBean2.getPrototypeBean());
}
}
Output
Bean org.springframework.context.annotation.internalAutowiredAnnotationProcessor
Bean org.springframework.context.annotation.internalCommonAnnotationProcessor
Bean org.springframework.context.event.internalEventListenerProcessor
Bean org.springframework.context.event.internalEventListenerFactory
Bean appConfig
Bean getTheBean
Bean scopedTarget.getPrototypeBean
Bean getPrototypeBean
springCertification.com.DTO.SimpleBean#762ef0ea
springCertification.com.DTO.SimpleBean#762ef0ea
before set > springCertification.com.DTO.SimplePrototypeBean#2f465398
after set > springCertification.com.DTO.SimplePrototypeBean#610f7aa
before set > springCertification.com.DTO.SimplePrototypeBean#6a03bcb1
after set > springCertification.com.DTO.SimplePrototypeBean#21b2e768
null
null
springCertification.com.DTO.SimplePrototypeBean#17a7f733
See above output always showing new instance and the value in the text field is null. I'm running only once this app. So I'm expecting only 2 prototype instances will be created as I call simpleBean1 and simpleBean2. Can someone explain to me why this is happening and how to fix it to have only 2 prototype objects where simpleBean1 holds one prototypeBean and simpleBean2 holds another prototypeBean
Intro
Consider the following part of your code:
public class SimpleBean {
#Autowired
SimplePrototypeBean prototypeBean;
}
what do you expect the prototypeBean field to refer to?
Should it always be the same instance of a PrototypeBean?
Or should it enclose the prototype logic somehow?
Prototype means, every time we ask an IoC container for a bean it will return a new instance
When default configuration used (without specifying the proxyMode), the field will appear to us as the same prototype instance
But when you specify TARGET_CLASS or INTERFACES then not the PrototypeBean instance will be injected, but its proxy, (see Scoped beans as dependencies):
That is, you need to inject a proxy object that exposes the same public interface as the scoped object but that can also retrieve the real target object from the relevant scope (such as an HTTP request) and delegate method calls onto the real object.
and when the scope is prototype, then:
every method call on the shared proxy leads to the creation of a new target instance to which the call is then being forwarded.
That is when you call any method, incuding the toString method, on the SimplePrototypeBean bean, Spring creates a new target instance of SimplePrototypeBean underneath to invoke the method on.
Another mcve
You can try the following MCVE to gain the understanding:
#Component
#Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RandomHolder {
private final int random = ThreadLocalRandom.current().nextInt();
public int getRandom() {
return random;
}
}
And the class with main:
#SpringBootApplication
#AllArgsConstructor
public class SoApplication implements ApplicationRunner {
private final RandomHolder randomHolder;
public static void main(String[] args) {
SpringApplication.run(SoApplication.class, args);
}
#Override
public void run(ApplicationArguments args) {
System.out.println("random = " + randomHolder.getRandom());
System.out.println("random = " + randomHolder.getRandom());
}
}
It is a Spring Boot application
RandomHolder is a prototype bean in the IoC container (identical to the way you declared the getPrototypeBean bean)
The RandomHolder has one field which we expect to be the same.
When we run the application returned values from the getRandom method can be different, here is a sample output:
random = 183673952
random = 1192775015
as we now know, the randomHolder refers to a proxy, and when a method is invoked on it, the new target instance of RandomHolder is created and the method is invoked on it.
You can imagine that the proxy looks like this:
public class RandomHolderProxy extends RandomHolder {
private final Supplier<RandomHolder> supplier = RandomHolder::new;
#Override
public int getRandom() {
return supplier.get().getRandom();
}
}
that is, it has an ability to create RandomHolders and invokes methods on new instances of them.
Without proxyMode = ScopedProxyMode.TARGET_CLASS
when we drop the proxyMode argument:
the output is the same
random = 2628323
random = 2628323
Spring won't create a proxy, but will create a new instance every time it requested
If we add another component:
#AllArgsConstructor
#Component
public class ApplicationRunner2 implements ApplicationRunner {
private final RandomHolder randomHolder;
#Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner2: " + randomHolder.getRandom());
System.out.println("ApplicationRunner2: " + randomHolder.getRandom());
}
}
then the output could be:
random = -1884463062
random = -1884463062
ApplicationRunner2: 1972043512
ApplicationRunner2: 1972043512
So I'm expecting only 2 prototype instances will be created as I call simpleBean1 and simpleBean2.
Your expectation is a little bit inexact there, you have as many instances of prototype bean created as many times you have any methods invoked on.
Can someone explain to me why this is happening
I hope, my explanation was clear enough
and how to fix it to have only 2 prototype objects where simpleBean1 holds one prototypeBean and simpleBean2 holds another prototypeBean
The problem here is not in the prototype scope, but in the scope of SimpleBean: it is a singleton, so you have the same instance of SimpleBean when you do:
SimpleBean simpleBean1 = (SimpleBean) ctx.getBean("getTheBean");
just add an assertion to your test method:
SimpleBean simpleBean1 = (SimpleBean) ctx.getBean("getTheBean");
SimpleBean simpleBean2 = (SimpleBean) ctx.getBean("getTheBean");
Assertions.assertSame(simpleBean2, simpleBean1);
it won't fail.
Once again, hope this helps.
Let's imagine I have the next classes in the project based on Spring framework:
interface I {
String getName()
}
#Component
class I1 implements I {
#Override
String getName() {return "I1"}
}
#Component
class I2 implements I {
#Override
String getName() {return "I1"}
}
And I want to gather them all in the map using the #Autowired method:
#Component
public class A {
private Map<I> map = new HashMap<>()
#Autowired
public registerI(I i) {
map.put(i.getName(), i)
}
}
Should I make this method registerI synchronized? I mean, can Spring call this method in several threads simultaneously? Or this method will be called sequentially?
Thanks
You don't have to use synchronized because Spring bean initialization is single-threaded and thread-safe. You can think of gotchas like thread-scoped or lazy beans but for regular singleton beans initialization happens in one thread.
You might want to use synchronized to make sure that after registerI() method is called your object is safely published, although auto-wired constructor with final field is more readable.
#Component
public class A {
private final Map<String, I> map;
public A(List<I> list) {
map = list.stream().collect(Collectors.toMap(I::getName, i -> i));
}
}
You will get an exception during app startup because Spring cannot determine the correct implementation of interface "I" what you want to inject. You should use #Qualifier.
If you want to accomplish that scenario, this should be enough.
#Component
public static class A {
private Map<String,I> map = new HashMap<>();
public A(List<I> list) {
//map = list.stream().collect(Collectors.toMap(I::getName, x -> x));
for (I i : list) {
map.put(i.getName(), i);
}
}
}
You will end with only one value in the map.
The commented line works if there are not duplicate map keys.
You can autowire context and get all the interested beans from it in a #PostConstruct method and create a hashmap with it.
Or
If you want that Map to be shared amongst multiple classes, make it a #Bean
#Configuration
class SomeConfig{
#Autowire Context context;
#Bean(name = "mapBean")
public Map<String, MyCustomClassName1> mapBean() {
Map<String, MyCustomClassName1> map = new HashMap<>();
//populate the map here - from Context
return map;
}
}
Spring fills List by your beans. After you can create map in postConstruct
#Component
public class A {
#Autowired
private List<I> list;
#Autowired
private Map<String, I> map;
#PostConstruct
private void init(){
map = list.stream()
.collect(Collectors.toMap(I::getName, element->element);
}
}
Is there any way to get the number and some identification information of already created entities of particular Prototype-bean in Spring application?
Addition. In our project we have more then 400 prototype-beans and I would like to trace the state what beans were created during execution and the number of entities of each type.
I have found a way to see the actual picture about created prototype-beans.
I use free VisualVM memory profiler.
In the Sampler tab you can see all instances of created classes including singleton and prototype beans.
You'll see the names of your own packages and classes. In this case:
prototype is a package with my prototype-beans.
singleton is a package with my singleton-beans.
newclasses is a package with classes that I created by new operator.
Also after the garbage collector will clean up the memory you will see the result here.
you can do it by Publish and Listen Application Events.
create you own event.
when prototype bean was created send event from it.
create count ApplicationListener , and listen to income creation event.
here is example
Spring – Publish and Listen Application Events
Spring does not manage the complete lifecycle of a prototype bean: the container instantiates, configures, decorates and otherwise assembles a prototype object, hands it to the client and then has no further knowledge of that prototype instance.
Simple variant :
public class PrototypeCreationEvent extends ApplicationEvent {
private String beanName;
public PrototypeCreationEvent(Object source , String beanName) {
super(source);
this.beanName = beanName;
}
public String getBeanName(){
return beanName;
}
}
public class PrototypeCreationListener implements ApplicationListener<PrototypeCreationEvent> {
private ConcurrentMap<String,AtomicInteger> prototypeCreationStatistic = new ConcurrentHashMap<>();
//or from guava AtomicLongMap prototypeCreationStatistic = AtomicLongMap.create();
#Override
public void onApplicationEvent(PrototypeCreationEvent event) {
prototypeCreationStatistic.computeIfAbsent(event.getBeanName() , k->new AtomicInteger(0)).incrementAndGet();
System.out.println(event);
}
public ConcurrentMap<String,AtomicInteger> getPrototypeCreationStatistic(){
return prototypeCreationStatistic;
}
}
public abstract class PrototypeCreationPublisher implements BeanNameAware , ApplicationEventPublisherAware ,InitializingBean {
private String beanName;
private ApplicationEventPublisher applicationEventPublisher;
#Override
public void setBeanName(String name) {
this.beanName = name;
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.println();
}
#Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
#PostConstruct //or use interface InitializingBean
public void sendEventAfterCreation() throws Exception {
applicationEventPublisher.publishEvent(new PrototypeCreationEvent(this , beanName));
}
}
#Component(value = BeanDefinition.SCOPE_PROTOTYPE)
public class PrototypeA extends PrototypeCreationPublisher{
}
#Component(value = BeanDefinition.SCOPE_PROTOTYPE)
public class PrototypeB extends PrototypeCreationPublisher{
}
example :
PrototypeA prototypeA1 = context.getBean(PrototypeA.class);
PrototypeA prototypeA2 = context.getBean(PrototypeA.class);
PrototypeA prototypeA3 = context.getBean(PrototypeA.class);
PrototypeB prototypeB1 = context.getBean(PrototypeB.class);
PrototypeCreationListener statistic = context.getBean(PrototypeCreationListener.class);
statistic.getPrototypeCreationStatistic().entrySet().forEach(s->{
System.out.println(s.getKey() + " count = "+s.getValue());
});
result :
PrototypeB count = 1
PrototypeA count = 3
I would like to create a factory, but it's not simple with Spring and again I'm lost in space :p
This is what i would like to do.
I have an abstract class which implements multiple interface (Runnable and some personal interfaces)
public abstract class AbstractDocMan implements Runnable, DocMan {
protected AbstractDocUnit docUnit;
// some attributes
// some getter & setter
}
I have some classes which extends from this abstract class, i will call them : W, S & E :p
And some classes for the Abstract attribute (docUnit) called : WD for W, SD for S and ED for E :)
Now considering a parameter, i would like to instantiate the good class in my main controller. I would like a generic code, but working with specific class considering the good process.
Something like that.
#Component("mainVm")
#Scope("prototype")
public class MainVm {
#Autowired
private DocManFactory docManFactory;
// ???
private AbstractDocMan docMan;
...
public void setProcess(String myProcess) {
docMan = docManFactory.getDocMan(myProcess);
}
}
For moment, i have a factory defined strangely. It is working but i don't think it's a good practice :
public class DocManFactory {
#Autowired
private S s;
#Autowired
private W w;
#Autowired
private E e;
#Autowired
private SD sd;
#Autowired
private WD wd;
#Autowired
private ED ed;
public AbstractDocMan getDocMan(String myProcess) {
AbstractDocMan adm = null;
if ("S".equals(myProcess)) {
s.setDocUnit(sd);
adm = s;
} else if ("W".equals(myProcess)) {
w.setDocUnit(wd);
adm = w;
} else if ("E".equals(myProcess)) {
e.setDocUnit(ed);
adm = e;
}
return adm;
}
}
So my questions :
- How to inject dynamically the good docUnit in the factory ? cause here all object are instantiate (s,e,w,sd,ed,wd) zzz
- Is there a way to annotate the attribute in main controller ?
So...How to do a good factory with Spring (v3.1.1).
Thank you.
I think generics and a Map are the solutions here.
Your instinct is correct: this implementation is far too brittle. Start with this:
public DocManFactory {
// You can inject or hard wire these
private static final Map<String, AbstractDocMan> INSTANCES;
public static AbstractDocMan getDocMan(String processName, Process process) {
AbstractDocMan docMan = INSTANCES.get(processName);
process.setDocUnit(docMan);
return docMan;
}
}
Generics can help if the Process class that I assumed varies.
I need to start a variable number of threads which in turn each start a varying number of threads (i.e. i threads where the Ith thread needs to start Ki threads) in a spring application.
assuming each of the "I threads" contains an inner class which is autowired how will I generate those instances?
So I have an A bean which needs to somehow generate I instances of a bean which needs to be spring managed to satisfy its dependencies.
I've written a short sample code of what I think is the base for my solution and I've marked the code I'm not sure how to write by ???:
#Component
public class MasterOrchestrator {
public void do(List<DataObjWrapper> list){
ExecutorService es = Executors.newFixedThreadPool(list.size());
for (DataObjWrapper dataObjWrapper : list){
es.submit(???);
}
}
}
#Component
public class ThreadWorkerI implements Runnable{
private int numThreadsForMessageType;
private int numRunsForMessageType;
private DataObj dataObj;
public ThreadWorkerI(int numThreadsForMessageType, int numRunsForMessageType, DataObj dataObj){
this.numThreadsForMessageType = numThreadsForMessageType;
this.numRunsForMessageType = numRunsForMessageType;
this.dataObj = dataObj;
}
#Autowired
private JmsTemplate jmsTemplate;
public void run(){
ExecutorService es = Executors.newFixedThreadPool(numThreadsForMessageType);
for (int i=0;i<numRunsForMessageType;i++){
es.submit(new ActualWorker(i));
}
}
private class ActualWorker implements Runnable{
private int numRun;
private ActualWorker(int numRun){
this.numRun = numRun;
}
public void run(){
//send message using the jmsTemplate the dataObj and numRun
}
}
}
DatObjWrapper contains amongst other members the numThreadsForMessageType, numRunsForMessageType and dataObj.
You can use #Configurable annotation to let Spring inject dependencies into your workers - even the one's that are not managed explicitly by the Spring container.
Instead of starting your own threads it is better to use thread pool or Spring's task executor abstraction. Then your tasks can be Spring beans or manually instantiated.
How about passing a reference to the MasterOrchestrator or the ThreadWorker into the Runnable's constructor? Then you can put all the configuration into the #Component class.
For example:
private class ActualWorker implements Runnable{
private int numRun;
private ActualWorker(ThreadWorkerI owner, int numRun){
this.numRun = numRun;
}
public void run(){
//send message using owner.jmsTemplate, owner.dataObj and numRun
}
}