I am implementing an service class which uses the services of the third party providers.
User will interact with the Service class to get the service of the service provider.
My requirement:
I want to load the service class only once( or it persist for long time in memory say 2 Hr.).
My question:
How can I check that this service class is loaded only once?
If it is loaded each time an request is made so is there any way to them persist in the memory?
Here is the code of my Service class
package com.example;
import com.example.spi.Multiplication;
import java.util.Iterator;
import java.util.ServiceLoader;
public class MultiplicationService implements Multiplication{
private static MultiplicationService service;
private ServiceLoader loader;
public static int no=0;
private MultiplicationService() {
loader = ServiceLoader.load(Multiplication.class);
}
public static synchronized MultiplicationService getInstance() {
if (service == null) {
service = new MultiplicationService();
}
return service;
}
public int getMultiplication(int a,int b){
int result = 0;
try {
Iterator multiply = loader.iterator();
while (result == 0 && multiply.hasNext())
{
Multiplication d = multiply.next();
result = d.getMultiplication(a,b);
System.out.println("Result is : "+ result);
}
} catch (Exception serviceError) {
result = 0;
serviceError.printStackTrace();
}
return result;
}
}
Thanks
You can implement the singleton pattern. One option is using an enum:
public enum Service {
INSTANCE;
private ThirdPartyService service = new ThirdPartyService();
public ThirdPartyService getService() {
return service;
}
}
But don't overuse that pattern, because it makes it hard to unit-test your code.
Go for Spring.
Make a bean entry and keep it singleton [which is by default]
It will create an object of that class once when context is initialized then it won't touch the class and your purpose will get solved.
You could also check out OSGi, which has a service model and will take care of all class loading for you. You can also combine it with Spring to get the benefits from both worlds.
Related
I have an interface I and 2+ of its implementations/services (ex. I1, I2)
public interface I {
void handle();
Network getNetwork();
}
and I have another one service (ex. IHolder) that is injecting the list of all services that implementing I and is putting it to its inner private map field where key is some unique Enum (interface has public method that returns one) and value the implementation itself.
public class IHolder {
private final Map<Network, I> iByNetwork = new HashMap<>();
public IHolder(List<I> is) {
for (I i : is) {
register(i.getNetwork(), i);
}
}
private void register(Network network, I i) {
this.iByNetwork.put(network, i);
}
public I getI(Network network) {
return iByNetwork.get(network);
}
}
Now I want to inject IHolder to my test class to use his map filled with those services
So basically annotate the IHolder class with #Service, but you won't be able to use it's private field (map), at least not in a simple way...
edit
Try to add these annotations to your test classes:
#RunWith(SpringRunner.class)
#SpringBootTest
I tried to generate and unique long id. I generate this in a service this is the service:
package x.y.z;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.ejb.Startup;
import javax.ejb.Stateless;
import x.y.NiceObject;
#Stateless
#Startup
public class Transacciones {
private long idTransaccion = 0l;
static Map<Long, NiceObject> mapaTransacciones = new ConcurrentHashMap<>();
public Transacciones() {
}
public long getIdTransaccion() {
++idTransaccion;
return idTransaccion;
}
public void setIdTransaccion(long idTransaccion) {
idTransaccion = idTransaccion;
}
public Map<Long, NiceObject> getMapaTransacciones() {
return mapaTransacciones;
}
public void setMapaTransacciones(Map<Long, NiceObject> mapaTransacciones) {
this.mapaTransacciones = mapaTransacciones;
}
}
And I have a managed bean from where I call this service and try to consume this id Generated. This is the method of the bean:
#EJB
private Transacciones transaccionService;
public String capture() {
ExecutorService service = Executors.newFixedThreadPool(2);
try {
long idTransaccion =
transaccionService.getIdTransaccion();
method1(idTransaccion);
service.submit(() -> {
method2(idTransaccion);
});
} finally {
if (service != null)
service.shutdown();
}
return null;
}
The problem is that in some place in the time, it fails; because I hope to get generate Id like this:
1,2,3,4,5,6.......
but I get:
1,2,1,3,4,2,...
In this line:
long idTransaccion = transaccionService.getIdTransaccion();
What would be the problem. Remenber I have a Managed Bean of SessionScope from where I invoque this method in a EJB.
For any help Thanks in advance!
There is a pool of stateless bean. And each call is delegated to a different instance actually you call a method of proxy and it delegates your call to an instance of the pool. There is no guarantee that even two consecutive calls on a bean(injected in your bean) use the same bean. So when regenerates 1, it means that it used another bean. You could use the singleton instead of stateless.
As #prasad_3 said you must not have state in a stateless bean.
Define idTransaccion as static variable.
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've a web service like this in a Jersey Java app:
#Singleton
#Path("/root")
public class MyWebService() {
private int count;
public MyWebService() {
count=0;
}
#Path("/perf/request")
#GET
#Produces(MediaType.APPLICATION_JSON)
public String getCount() {
String out = "";
count++;
out = "Count is: " + out;
return out;
}
}
Due to the Jersey lifecycle, the class is re-instantiated every time a service is called (in spite of the "#Singleton" annotation) and then every time the count is equal to zero.
Is there a way to make this class/field static so the "count" field will not be reset?
That should totally work! According to the documentation:
In this scope there is only one instance per jax-rs application.
Singleton resource can be either annotated with #Singleton and its
class can be registered using the instance of Application. You can
also create singletons by registering singleton instances into
Application.
Did you register the class with the application?
public class MyApplication extends ResourceConfig {
/*Register JAX-RS application components.*/
public MyApplication () {
register(MyWebService.class);
}
}
Also you may be importing the wrong annotation type.
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.