Java Spring Boot Local Scope Variable make it shared - java

Hi I am using Sprint boot and creating microservices. I have a scenario where an object will be created and it will be used by other methods of the same class and methods of other classes. But scope will be only when this method gets called.
Class SharedObject {
private String name;
//getters setters
}
#Service
Class FirstServiceImpl {
#Autowired
SecondServiceImpl second;
public void process() {
SharedObject obj = new SharedObject();
//...
process2(obj);
}
private void process2(SharedObject obj) {
//...
second.process(obj);
}
}
#Service
Class SecondServiceImpl {
public void process(SharedObject obj) {
//...
}
}
Here SharedObject needs to be created in process method of FirstServiceImpl class and that needs to be accessed in rest of the places. But next call of process method of FirstServiceImpl class, it should create a new object. Considering this, I can pass to all the methods it requires. But any other cleaner way to achieve this ?

You can use ThreadLocal (https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html) for this use case. But use it with care, it can easily cause memory leaks if not done properly.
There are some interesting articles to read on ThreadLocal.
https://dzone.com/articles/an-alternative-approach-to-threadlocal-using-sprin-1 - Better implementation of ThreadLocal
https://plumbr.io/blog/locked-threads/how-to-shoot-yourself-in-foot-with-threadlocals
]https://javarevisited.blogspot.com/2013/01/threadlocal-memory-leak-in-java-web.html#axzz7iil9FiAC

Related

Passing one instance of an object to different classes without using static or singleton

I am trying to figure out a way to pass one instance of the same class to multiple classes so I am able to build an object. The problem is it cannot be static or use singleton because many users will be hitting the application at the same time and I may run into other issues. Are there any design patterns that would work best with this scenario or if there is some way to use global variables in java? I am trying implement this with an existing rest service that was not designed very well.
public class OneInstanceOf
{//I want to build this map object without static
private Map<String, String> mapIwantToBuild = new HaspMap<String, String>();
public void methodIwantToCall(String name, String value)
{mapIwantToBuild.put(name, value)
}
The common pattern for you task is dependency injection. You can use spring framework for that task.
1.Create configuration with your bean:
#Configuration
public class YourConfiguration {
#Bean
public OneInstanceOf oneInstanceOf {
return new OneInstanceOf();
}
}
2.Inject your bean whatever you want (simplest - use autowiring):
#Component
public class Client1 {
#Autowire
private OneInstanceOf oneInstanceOf;
public void someMethod() {
oneInstanceOf.methodIwantToCall();
}
}
Spring will insure single instance of oneInstanceOf will be injected in all clients.
U can create a setter with parameter of instance class variable, in every class in which you want to pass the instance. Then create a method in one of the classes that calls setter of all those classes and pass parameter instance as parameter to that method.
Like below.
class A{
B b = new B;
set(B b){
C.setB(b);
D.setB(b);
E.setB(b);
}
}

Block access to specifc attribute inside own class

I'm using a public java API to build my multi thread application, but I don't know if some methods of this API are thread-safe [indeed I really think they aren't].
I was looking for the most clean and straight way to implement this safety on my code and decided to use lambda expression.
I'm planning to use something like this:
public class Myclass {
private NotThreadSafe obj;
public Myclass() {
this.obj = new NotThreadSafe();
}
private synchronized void useNonThreadSafeObject(FunctionalInterface r) {
r.exec(this.obj);
}
private void method1() {
this.useNonThreadSafeObject((NotThreadSafe p)->{/*do stuff*/};);
}
private void method2() {
this.obj.someMethod();
}
/* any other methods */
}
I want to make sure that no method in Myclass will call directly to 'obj'
so all methods must use obj as method1 do, avoiding directly call as method2
of course java doens't have a modifier to do it, but I was wondering if was an annotation or other way to check it at compiler time...
----[I wasn't clear at first time, trying to explain more]----
You can simply split the class into two:
class Guard {
private final NotThreadSafe obj;
public Guard() {
this.obj = new NotThreadSafe();
}
synchronized void useNonThreadSafeObject(FunctionalInterface r) {
r.exec(this.obj);
}
}
public class Myclass {
private Guard guard=new Guard();
private void method1() {
guard.useNonThreadSafeObject(p -> {/*do stuff with p*/});
}
private void method2() {
guard.useNonThreadSafeObject(p->{/*do other stuff with p*/});
}
/* any other methods */
}
This is the best isolation you can get as no direct access to obj is possible from MyClass. But note that this is not bullet-proof, it’s still possible to create a custom implementation of FunctionalInterface which will keep the received NotThreadSafe instance and store it somewhere in the heap for accessing it at a later time without the Guard. However, that’s a bigger effort and unlikely to happen accidentally…

Appropriate way to pass instance of class to other classes (Java)

I have a main class which has a number of instance related methods that are often needed in other classes and I often find myself passing an instance of the main class in the constructor. I often find this goes several layers deep with classes having instances of the main class that has been copied from instance to instance which I can't imagine is good for memory usage.
Is there a way to do this without having to pass the instance in the constructor or a method or at least a way to reduce the memory that is used by the instances of the main class.
To make it clear I am not looking for static methods, it is designed to be able to have more than one instance of the main class.
Example code:
public class Main {
public Main() {
Class2 class2 = new Class2(this);
}
public void someMethod() {
//Do something
}
}
public class Class2 {
private final Main instance;
public Class2(Main instance) {
this.instance = instance;
Class3 class3 = new Class3(instance);
}
}
public class Class3 {
private final Main instance;
public Class3(Main instance) {
this.instance = instance;
instance.someMethod();
}
}
You can use Dependency Injection Design Pattern.
Dependency-Injection-Design-Pattern
Spring, Google Guice and Java EE CDI frameworks facilitate the
process of dependency injection through use of Java Reflection API and
java annotations. All we need is to annotate the field, constructor or
setter method and configure them in configuration xml files or
classes.
You could also use dependency injection to pass on the dependent attributes or objects to required classes.
One such popular framework is Google Guice.
You could make methods like someMethod() in the Main class static, or if that's not possible, make the Main class itself a singleton.
Example of the former approach:
public class Main {
public Main() {
Class2 class2 = new Class2(this);
}
public static void someMethod() {
//Do something
}
}
Now you don't have to pass an instance of Main around any more, because other classes can just call Main.someMethod() directly.

Can I register a static method as a Guava EventBus subscriber?

I have an application Config object that gathers information from several sources — .properties files, database tables, the OS, etc. — and makes this available to the rest of the application as if they were java.util.Properties, for example:
private static String devToAddress = Config.getConfig().getProperty("testAddress");
These are often stored, as shown above, as a static so it's always available to all instances of a class without having to constantly fetch it.
I also have a way to tell this (web) application to re-load these "properties" so I can reconfigure the application while it's running without doing a restart.
What I want to do is register with my Guava EventBus to subscribe to my "ConfigurationChangeEvent" so the class can update this devToAddress when I use my re-load feature.
In some cases this may be a static class with only static methods that still needs the application Config information, so I can't necessarily count on having an instance to do the work of updating the static variables.
What I tried is this:
package com.sample.mw;
import com.google.common.eventbus.Subscribe;
import com.example.mw.events.ConfigurationChangeEvent;
import com.example.mw.events.EventDispatcher;
import com.example.mw.Config;
public class SampleMailer
{
private static String devToAddress;
// constructor(s)
public SampleMailer()
{
// ...
}
// instance methods
// ...
// static methods
public static String getTheAddress()
{
return devToAddress;
}
#Subscribe
public static void loadConfig(ConfigurationChangeEvent cce)
{
devToAddress = Config.getConfig().getProperty("testAddress");
}
// static/class registration with the event bus
static
{
loadConfig(null); // initial config load without an event
// 'EventDispatcher' is my singleton that encapsulates the EventBus
EventDispatcher.getDispatcher().register(SampleMailer.class); // <-- not sure what to register here
}
}
The questions are (a) Is this possible at all? Can you statically register with the Guava EventBus? (b) What Object do I pass to the EventBus .register(Object object) method?
No, you can't register a static method with an EventBus... not directly. First of all, I'd strongly recommend trying to avoid a need for this to begin with. Static state like you have in SampleMailer is a smell.
That said, there's a pretty simple workaround here using an anonymous inner class:
eventBus.register(new Object() {
#Subscribe
public void loadConfig(ConfigurationChangeEvent cce) {
SampleMailer.loadConfig(cce);
}
});
But again, it should really probably be an instance method on something to begin with.
Edit: Huh, looks like EventBus will register a static method given an instance of that class. Still, I wouldn't recommend taking advantage of that: EventBus is based around registration of object instances as subscribers, and static subscriber methods interact somewhat strangely with that.
Following ColinD's answer, I found that the Guava #Subscribe annotation is perfectly happy registering and calling a static method, but it needs an instance passed for registration.
The trick is you don't want to register the subscribed static method many times, for each instance, you only want to register once so the class loadConfig() method (below) doesn't get called 100 times when a reload occurs.
This slightly rewritten example better demonstrates how I actually use my configuration items; there are no getters and the world outside of this Class never sees the "state" of the config vars.
package com.sample.mw;
import com.google.common.eventbus.Subscribe;
import com.example.mw.events.ConfigurationChangeEvent;
import com.example.mw.events.EventDispatcher;
import com.example.mw.mail.Mailer;
import com.example.mw.Config;
public class SampleMailer
{
private static boolean registered = false;
private static String devToAddress;
private static boolean override;
// constructor(s)
public SampleMailer()
{
if (!registered) // could be protected with synchronized() block
{
// 'EventDispatcher' is my singleton that encapsulates the EventBus
// if you register 'this' instance it will find the annotated static method.
EventDispatcher.getDispatcher().register(this);
registered = true;
}
}
// instance methods
public void performAction(String toAddress)
{
doSomething( override ? devToAddress : toAddress );
}
private void doSomething(String toAddress)
{
Mailer.sendAnEmailToTheAddress(toAddress, getEmailText());
}
#Subscribe
public static void loadConfig(ConfigurationChangeEvent cce)
{
Config config = Config.getConfig();
devToAddress = config.getProperty("testAddress");
override = Boolean.parseBoolean( config.getProperty("overrideMailDestination") );
}
// static/class initial load
static
{
loadConfig(null); // initial config load without an event
}
}
This is closer to the real-world use; while still only example code, it does demonstrate how static handling of guava EventBus calls can be done.

java separate file for global variables

I have a newbie question. If I have some global variables that are shared by two classes or more how can I have them in a separate file so that any class can read and update them. Is this possible without using Interfaces?
Yes, since interfaces variables are all implicitly static, so each of these variables has only one instance in the jvm.
However, a better way to do it [in my opinion] would probably be having them declared in some singleton class and using it.
The best way to do this is to have your shared application state accessible via interface methods, then have an implementing class that holds the variables, and pass this instance of the class to your other classes during construction (which they accept as an instance of the interface).
This is better than using a static class or singleton since it allows you to mock out the functionality of the shared state for testing, improves general code reusability, and allows you to change the implementation and configuration of the shared state without impacting any of the code using it.
E.g.
// Session interface for all application shared state.
public interface ApplicationSession
{
public int getMaxUserLimit();
}
// A backing for the interface (simple in memory version, maybe future versions use a database, who knows).
public class SomeApplicationSession implements ApplicationSession
{
private volatile int maxUserLimit = 0;
public void setMaxUserLimit(int limit) { this.maxUserLimit = limit; }
public int getMaxUserLimit() { return maxUserLimit; }
}
// ClassA uses the supplied session.
public class MyClassA
{
private ApplicationSession session;
public myClassA(ApplicationSession session)
{
this.session = session;
}
}
// usage...
public class MyMain
{
public static void main(String[] args)
{
// Create / get session (ultimately possibly from a factory).
ApplicationSession session = new SomeApplicationSession();
ClassA myClassA = new ClassA(session);
// do stuff..
}
}

Categories