Following Toby's Spring 3.1 in Spring Boot :
Chapter 1 Objects and Dependency Relations - 1.6 Singleton Registry and Object Scope
Dev environment - OS : mac - STS : 4.0.1 - MySQL : Server version: 8.0.13 Homebrew - Framework : keeping things as dependency-free as possible, sticking to jar only. Related links - Spring User Group homepage http://www.ksug.org/ - Spring User Group Q&A https://groups.google.com/forum/#!topic/ksug/13vB4tCFqrI - 2017 Spring Camp https://www.youtube.com/playlist?list=PLdHtZnJh1KdZ6NDO9zc9hF4tONDLTSEUV |
Chapter 1. Objects and Dependency Relations
1.6 Singleton Registry and Object Scope
Up through the previous example, we had two different ways of getting the same result, but if you compare the "Previously" run results below, the results come out different. This section's purpose is to understand why and to come up with a fix.
1.6.0 previously previously : Two ways to implement IoC ;D
1. Plain Java coding - build a DaoFactory (object factory) yourself and use it directly.
2. Spring-style Java coding - add @Configuration and use it through the application context.
When you ask for the bean named userDao, DaoFactory's userDao() method gets called, runs, and the result is returned.
* For testing, I created a new class named IoCObjectTest.
package springbook.user.dao;
import java.sql.SQLException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class IoCObjectTest {
public static void main(String[] args) throws ClassNotFoundException, SQLException{
//1. 그냥 자바 IoC 코딩
DaoFactory factory = new DaoFactory();
UserDao dao1 = factory.userDao();
UserDao dao2 = factory.userDao();
System.out.println(dao1);
System.out.println(dao2);
//2. 자바 스프링 IoC 코딩
ApplicationContext context1 = new AnnotationConfigApplicationContext(DaoFactory.class);
UserDao dao3 = context1.getBean("userDao",UserDao.class);
UserDao dao4 = context1.getBean("userDao",UserDao.class);
System.out.println(dao3);
System.out.println(dao4);
}
}The result shows that objects created via the factory have different values from each other, while the ones via the application context come out the same.
Oh, by the way — unlike the screenshot above, you might hit an error !!
Caused by: java.lang.IncompatibleClassChangeError: class org.springframework.core.type.classreading.ClassMetadataReadingVisitor has interface org.springframework.asm.ClassVisitor as super class
The culprit is the asm file among the jars we added earlier — asm.jar — just delete it ~ To delete: select the project, right-click~ click Build Path~ select the file, then click Remove ~
The specific cause is a dependency conflict with spring-asm. From version 3.2 onward, spring-asm is bundled into spring-core by default, which is why this clash happens. Googling sources 2) https://choong0121.tistory.com/entry/orgspringframeworkasmClassVisitor-as-super-class |
This is an issue of object identity vs. equivalence.
In Java, there's the notion of two completely identical objects (identical) and objects said to hold equivalent information (equivalent). The former is called identity comparison and the latter equivalence comparison.
To add a footnote: in Java, each variable holds a value and each variable has its own unique address. If both the address and the value are the same, that's identity; if only the value is the same, that's equivalence.
Ah.. there was a similar example in TDD a little while ago. Leaving a link ~ |
So, interpreting the example above: for objects obtained by directly calling userDao() through DaoFactory, a brand-new (new) object is created on every call, while with the application context, getBean() returns the same object every time (not recreating with new).
So the Spring-style approach using the application context returns the same object no matter how many times you request the bean.
1.6.1 Singleton Registry and Object Scope
1. The reason is this:
Spring's application context doesn't just play the role of an IoC container — it's also a singleton registry that stores and manages singletons. So by default, all bean objects it creates are singletons. However, while the concept is similar to the Singleton design pattern, the implementation is clearly different.
1) Singleton concept: create and use a limited — usually just one — object within the application. It's heavily used in server environments.
2) To skip to the conclusion, simply building a singleton in Java via the design pattern has various issues. So the Spring container plays the role of a singleton container that creates, manages, and supplies singletons. This is exactly the singleton registry. Spring itself provides the ability to create and manage singleton-style objects.
3) Comparing singleton creation styles
> Reserved slot < My own example — implementing a Singleton via design pattern in plain Java
"Still waiting.."
|
2. So why does Spring make beans as singletons? Let's look at that.
1) Spring is a server-side framework
Spring isn't built for standalone programs — it's a technology for server environments using enterprise systems. Enterprise server environments handle many requests and lots of processing. A single request is often served by a layered structure where many objects participate — data access, service, business, presentation logic, and so on.
There's no way you can create a fresh set of those objects every single request —
2) Enter the servlet
That's why the enterprise world has long used the idea of a service object, like the servlet.
Most multithreaded environments work with singletons. One object per servlet class, and many threads handling user requests share and use the same object concurrently.
..Ahhh! That's why each name had to be unique, and why I'd get errors on duplicates..
3) Spring making beans singletons is ultimately the IoC role of controlling how objects are created.
1.6.2 Singletons and Object State
In a multithreaded environment, multiple threads can access and use the object at the same time. So when you use a service-style object, it has to be built as stateless — with no state info kept on the object.
So as a rule, don't build singletons as stateful, mutating-instance-fields types.
..Technical terms keep pouring out.. I ended up interpreting this as "favor private-style global variables." Doesn't feel bad. Reading ahead,
So when a singleton is used in a multithreaded environment, information that changes per call — like our previous UserDao — should be defined as a local variable or passed around via parameters.
Of course, instance variables aren't off-limits.
..Apparently "instance variable" is just another name for a class-level global variable.. better late than never to learn that..
The ConnectionMaker we used earlier is read-only info, so using it is fine. If it's plain read-only, you can also declare it as static final or final and use it freely.
1.6.3 Scope of Spring Beans
OK.. let's not forget.
Spring bean = an object managed by Spring
With that out of the way — Bean Scope is the range within which a bean is created, exists, and applies.
And most beans Spring creates have singleton scope.
= only one object per container; as long as the Spring container isn't forcibly terminated, it persists.
Searching Google, I found other scopes too.
I was going to skip past them... but wow, things I used to bang my head on showed up — Spring MVC applications! Hehe, I feel like I can finally use them knowingly...
That's why I'm re-sharing it here.
Types of Spring bean scopes Objects registered as Beans in Spring are managed as singleton objects by default. But depending on the requirements and the features you're implementing, there are many cases when you need non-singleton beans. Spring provides the "scope" keyword to explicitly distinguish these. If you don't specify a scope, Spring's default is singleton. Spring general applications singleton : default singleton scope. prototype: Spring creates a new instance every time the application requests one (getBean()). thread : creates a new bean instance when a new thread requests it; returns the same bean instance for the same thread. custom : implement org.springframework.beans.factory.config.Scope and register your custom scope in Spring's configuration. Spring MVC applications request : instantiated per HTTP request, destroyed when the request ends (for Spring MVC web applications). session : instantiated per HTTP session, destroyed when the session ends (for Spring MVC web applications). global session : for portlet-based web applications. A bean with global session scope can be shared across all portlets within a portal application using the same Spring MVC. Source: https://javaslave.tistory.com/45 [IT Slave Blog] Also, related to scope, here's a blog link that walks through examples of each scope. [Spring] Types of Spring Bean Scope Whoa.. kind of eerie... the first address is /45 and the next is /54... |
