Back to feed
Renewal·서른의 생활코딩

Following Toby's Spring 3.1 in Spring Boot: Ch.1 - 1.6 Singleton Registry and Object Scope

NS
normalstory
cover image

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 previouslyTwo 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 

1) https://kooremo.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B2%84%EC%A0%84-%EB%B3%80%EA%B2%BD%EC%8B%9C-%EC%97%90%EB%9F%AC-%EC%82%AC%ED%95%AD311321

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 ~  

TDD Practice in Spring Boot - Ch.3. Equality for All  


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

Comparison of 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...




The end ~ 


This English version was translated by Claude.

친절한 찰쓰씨
Written by
친절한 찰쓰씨

Pleasant Charles — UI/UX researcher at AIT. Keeping notes on design, planning, and slow days here since 2010.

More on the author's page

Keep reading

Renewal

Steadily, for the long haul, without burning out

Mar 31, 2026·9 min
Renewal

Tech-life balance

Feb 7, 2026·3 min
Renewal

Humanality, by Park Jeong-ryeol

Feb 7, 2026·11 min