우리 모두 알고 있듯이 Spring 컨테이너에는 기본적으로 Bean이 싱글 톤으로 있고 Spring 프레임 워크를 기반으로하는 웹 애플리케이션이있는 경우이 경우 Spring을 통해 Bean을 생성하는 대신 글로벌 데이터를 보유하기 위해 Singleton 디자인 패턴을 구현해야합니다. .
내가 실제로 묻고 자했던 것을 설명 할 수 없다면 참아주세요.
답변:
Spring의 singleton bean과 singleton 패턴은 상당히 다릅니다. Singleton 패턴은 특정 클래스의 인스턴스가 클래스 로더 당 하나만 생성 될 것이라고 말합니다.
Spring 싱글 톤의 범위는 "빈당 컨테이너 당"으로 설명됩니다. Spring IoC 컨테이너 당 단일 객체 인스턴스에 대한 Bean 정의 범위입니다. Spring의 기본 범위는 Singleton입니다.
기본 범위는 싱글 톤이지만 <bean ../>
요소 의 범위 속성을 지정하여 Bean의 범위를 변경할 수 있습니다 .
<bean id=".." class=".." scope="prototype" />
Spring의 Singleton 범위는 Spring 컨텍스트의 단일 인스턴스를 의미합니다.
Spring 컨테이너는 Bean을 얻기위한 후속 호출에 대해 동일한 인스턴스를 반복해서 반환합니다.
그리고 Spring은 bean의 클래스가 singleton으로 코딩되어 있는지 여부를 신경 쓰지 않습니다. 사실 클래스가 생성자를 private로 코딩 한 singleton으로 코딩 된 경우 Spring은 BeanUtils.instantiateClass ( 여기에서는 javadoc )를 사용하여 생성자를 액세스 가능하고 호출하도록 설정합니다. 그것.
또는 다음과 같이 빈 정의에서 factory-method 속성을 사용할 수 있습니다.
<bean id="exampleBean" class="example.Singleton" factory-method="getInstance"/>
가장 간단한 예를 들어 보겠습니다. 애플리케이션이 있고 기본 클래스 로더 만 사용합니다. 어떤 이유로 든 애플리케이션에 둘 이상의 인스턴스가 없어야한다고 결정하는 클래스가 있습니다. (여러 사람이 애플리케이션의 일부를 작업하는 시나리오를 생각해보십시오.)
Spring 프레임 워크를 사용하지 않는 경우 Singleton 패턴은 애플리케이션에 클래스의 인스턴스가 두 개 이상 존재하지 않도록합니다. 생성자가 private이기 때문에 'new'를 수행하여 클래스의 인스턴스를 인스턴스화 할 수 없기 때문입니다. 클래스의 인스턴스를 얻는 유일한 방법은 항상 동일한 인스턴스를 반환하는 클래스의 정적 메서드 (일반적으로 'getInstance'라고 함)를 호출하는 것입니다.
애플리케이션에서 Spring 프레임 워크를 사용하고 있다고 말하면 클래스의 인스턴스를 얻는 일반적인 방법 (클래스의 인스턴스를 반환하는 새 메서드 또는 정적 메서드) 외에도 Spring에 요청하여 얻을 수 있음을 의미합니다. 해당 클래스와 Spring의 인스턴스는 해당 클래스의 인스턴스를 요청할 때마다 Singleton 패턴을 사용하여 클래스를 작성하지 않았더라도 항상 동일한 인스턴스를 반환하도록 보장합니다. 즉, 클래스에 공용 생성자가 있어도 항상 해당 클래스의 인스턴스를 Spring에 요청하면 Spring은 애플리케이션 수명 동안 해당 생성자를 한 번만 호출합니다.
일반적으로 Spring을 사용하는 경우 Spring을 사용하여 인스턴스를 만들어야하며 클래스에 대한 공용 생성자를 가질 수 있습니다. 그러나 생성자가 비공개가 아니라면 Spring을 우회하여 누군가가 클래스의 새 인스턴스를 직접 생성하는 것을 실제로 막을 수는 없습니다.
진정으로 클래스의 단일 인스턴스를 원하면 애플리케이션에서 Spring을 사용하고 Spring에서 클래스를 싱글 톤으로 정의하더라도 Singleton 패턴을 사용하여 클래스를 구현하는 유일한 방법입니다. 이는 사람들이 Spring을 사용하여 인스턴스를 얻거나 Spring을 우회하는지 여부에 관계없이 단일 인스턴스가 있음을 보장합니다.
나는 " 콩당 용기 당"을 이해하기 어렵다는 것을 알았다 . 나는 " 컨테이너에있는 bean id 당 하나의 bean "이라고 말할 것이다. 그것을 이해하는 예를 들어 보자. 빈 클래스 Sample이 있습니다. 이 클래스의 빈 정의에서 다음과 같이 두 개의 빈을 정의했습니다.
<bean id="id1" class="com.example.Sample" scope="singleton">
<property name="name" value="James Bond 001"/>
</bean>
<bean id="id7" class="com.example.Sample" scope="singleton">
<property name="name" value="James Bond 007"/>
</bean>
그래서 내가 id "id1"을 가진 bean을 얻으려고 할 때, spring container는 하나의 bean을 생성하고 그것을 캐싱하고 id1로 참조 된 동일한 bean을 반환 할 것입니다. id7로 가져 오려고하면 Sample 클래스에서 다른 빈이 생성되고 id7로 참조 할 때마다 동일한 빈이 캐시되고 반환됩니다.
Singleton 패턴에서는 불가능합니다. Singlton 패턴에서는 클래스 로더 당 하나의 객체가 항상 생성됩니다. 그러나 Spring에서 범위를 Singleton으로 만드는 것은 컨테이너가 해당 클래스에서 많은 인스턴스를 만드는 것을 제한하지 않습니다. 동일한 ID에 대한 새 객체 생성을 다시 제한하고 동일한 ID에 대한 객체 요청시 이전에 생성 된 객체를 반환합니다. . 참고
Spring의 Singleton 범위는이 Bean이 Spring에 의해 한 번만 인스턴스화됨을 의미합니다. 프로토 타입 범위 (매번 새 인스턴스), 요청 범위 (요청 당 한 번), 세션 범위 (HTTP 세션 당 한 번)와 달리.
싱글 톤 범위는 기술적으로 싱글 톤 디자인 패턴과 관련이 없습니다. 싱글 톤 범위에 들어가기 위해 bean을 싱글 톤으로 구현할 필요가 없습니다.
Spring의 Singleton Bean과 Singleton 디자인 패턴을 기반으로하는 클래스는 상당히 다릅니다.
싱글 톤 패턴은 Spring 싱글 톤 빈의 범위가 '빈당 컨테이너 당'으로 설명되는 클래스 로더 당 하나의 특정 클래스 인스턴스 만 생성되도록합니다. Spring의 Singleton 범위는이 Bean이 Spring에 의해 한 번만 인스턴스화됨을 의미합니다. Spring 컨테이너는 Bean을 얻기위한 후속 호출에 대해 동일한 인스턴스를 반복해서 반환합니다.
둘 사이에는 매우 근본적인 차이가 있습니다. Singleton 디자인 패턴의 경우 classLoader 당 하나의 클래스 인스턴스 만 생성되지만 Spring singleton에서는 IoC 컨테이너 당 주어진 id에 대한 하나의 공유 빈 인스턴스가 생성되는 경우와는 다릅니다.
예를 들어, "SpringTest"라는 이름의 클래스가 있고 내 XML 파일이 다음과 같은 경우 :-
<bean id="test1" class="com.SpringTest" scope="singleton">
--some properties here
</bean>
<bean id="test2" class="com.SpringTest" scope="singleton">
--some properties here
</bean>
따라서 이제 메인 클래스에서 위의 두 참조를 확인하면 Spring 문서에 따라 false를 반환합니다.
빈이 싱글 톤 인 경우 빈의 하나의 공유 인스턴스 만 관리되며, 해당 빈 정의와 일치하는 ID를 가진 빈에 대한 모든 요청은 Spring 컨테이너에 의해 하나의 특정 빈 인스턴스가 반환되도록합니다.
따라서 우리의 경우와 마찬가지로 클래스는 동일하지만 우리가 제공 한 ID가 다르므로 두 개의 다른 인스턴스가 생성됩니다.
최소한 지금까지 모든 답변은 디자인 패턴과 Spring 싱글 톤의 차이점을 설명하는 데 집중하고 실제 질문을 다루지 않습니다. 싱글 톤 디자인 패턴을 사용해야합니까 아니면 Spring 싱글 톤 빈을 사용해야합니까? 무엇이 더 낫습니까?
대답하기 전에 두 가지를 모두 수행 할 수 있다고 말씀 드리겠습니다. Bean을 Singleton 디자인 패턴으로 구현하고 Spring을 사용하여 Spring Singleton Bean으로 클라이언트 클래스에 주입 할 수 있습니다.
이제 질문에 대한 답은 간단합니다. 싱글 톤 디자인 패턴을 사용하지 마십시오!
공용 생성자를 사용하여 클래스로 구현 된 Spring의 싱글 톤 Bean을 사용하십시오.
왜? 싱글 톤 디자인 패턴은 안티 패턴으로 간주되기 때문입니다. 대부분 테스트가 복잡하기 때문입니다. (스프링을 사용하여 주입하지 않으면 싱글 톤을 사용하는 모든 클래스가 이제 밀접하게 연결되어 있으며,이를 대체하거나 확장 할 수 없습니다. 하나는 이것에 대한 더 많은 정보를 얻기 위해 "Singleton anti-pattern"을 구글 할 수 있습니다. Singleton anti-pattern
Spring singleton을 사용하는 것은 (Singleton 디자인 패턴이 아니라 public 생성자로 구현 된 singleton bean을 사용하여) Spring singleton bean을 쉽게 테스트 할 수 있고이를 사용하는 클래스가 긴밀하게 결합되지 않도록하는 방법입니다. 대신 Spring은 싱글 톤 (인터페이스로)을 필요한 모든 빈에 주입하고 싱글 톤 빈은이를 사용하는 클라이언트 클래스에 영향을주지 않고 언제든지 다른 구현으로 대체 될 수 있습니다.
예 : "콩당 컨테이너 당".
<bean id="myBean" class="com.spring4hibernate4.TestBean">
<constructor-arg name="i" value="1"></constructor-arg>
<property name="name" value="1-name"></property>
</bean>
<bean id="testBean" class="com.spring4hibernate4.TestBean">
<constructor-arg name="i" value="10"></constructor-arg>
<property name="name" value="10-name"></property>
</bean>
</beans>
public class Test {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("ws.xml");
TestBean teatBean = (TestBean) ac.getBean("testBean");
TestBean myBean1 = (TestBean) ac.getBean("myBean");
System.out.println("a : " + teatBean.test + " : " + teatBean.getName());
teatBean.setName("a TEST BEAN 1");
System.out.println("uPdate : " + teatBean.test + " : " + teatBean.getName());
System.out.println("a1 : " + myBean1.test + " : " + myBean1.getName());
myBean1.setName(" a1 TEST BEAN 10");
System.out.println("a1 update : " + teatBean.test + " : " + myBean1.getName());
}
}
public class TestBean {
public int test = 0;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name = "default";
public TestBean(int i) {
test += i;
}
}
JAVA SINGLETON :
public class Singleton {
private static Singleton singleton = new Singleton();
private int i = 0;
private Singleton() {
}
public static Singleton returnSingleton() {
return singleton;
}
public void increment() {
i++;
}
public int getInt() {
return i;
}
}
public static void main(String[] args) {
System.out.println("Test");
Singleton sin1 = Singleton.returnSingleton();
sin1.increment();
System.out.println(sin1.getInt());
Singleton sin2 = Singleton.returnSingleton();
System.out.println("Test");
sin1.increment();
System.out.println(sin1.getInt());
}
Spring singleton bean은 '빈당 컨테이너 당'으로 설명됩니다. Spring의 Singleton 범위는 동일한 메모리 위치에있는 동일한 객체가 동일한 Bean ID로 반환됨을 의미합니다. 동일한 클래스의 다른 ID를 가진 여러 개의 빈을 생성하면 컨테이너는 다른 개체를 다른 ID로 반환합니다. 이는 키가 빈 ID이고 값이 하나의 스프링 컨테이너에있는 빈 객체 인 키 값 매핑과 같습니다. Singleton 패턴은 특정 클래스의 인스턴스가 클래스 로더 당 하나만 생성되도록합니다.