Spring의 9가지 클래식 디자인 패턴

1 단순 공장(23가지 디자인 패턴 중 하나가 아님)

1 1 구현 방법:

BeanFactory. Spring의 BeanFactory는 단순 팩토리 패턴의 구현으로 Bean 객체는 고유한 식별자를 전달하여 얻어지지만 매개변수를 전달한 후 생성되는지 아니면 매개변수를 전달하기 전에 생성되는지는 특정 상황에 따라 다릅니다.

1.2 물질:

팩토리 클래스는 전달된 매개변수에 따라 생성해야 하는 제품 클래스를 동적으로 결정합니다.

1.3 구현 원칙:

빈 컨테이너의 시작 단계:

  • bean의 xml 구성 파일을 읽고 bean 요소를 각각 BeanDefinition 객체로 변환합니다.
  • 그런 다음 이 빈은 BeanDefinitionRegistry를 통해 beanFactory에 등록되고 ConcurrentHashMap 중 하나에 저장됩니다.
  • BeanFactory에 BeanDefinition을 등록한 후 Spring은 여기에 확장된 컷을 제공하여
    BeanFactoryPostProcessor 인터페이스를 구현하여 여기에 정의된 코드를 삽입할 수 있도록 합니다.
  • 대표적인 예는 PropertyPlaceholderConfigurer로, 데이터베이스의 dataSource를 구성할 때 일반적으로 사용하는 placeholder 값이 주입된다.

컨테이너에 있는 빈의 인스턴스화 단계:
인스턴스화 단계는 주로 리플렉션 또는 CGLIB를 통해 빈을 인스턴스화하는 것입니다. 이 단계에서 Spring은 많은 확장 지점에 노출됩니다.

  • 이러한 Aware 인터페이스를 구현하는 Bean에 대해 BeanFactoryAware와 같은 다양한 Aware 인터페이스는 Bean을 인스턴스화할 때 Spring이 해당 BeanFactory 인스턴스를 주입하는 데 도움이 됩니다.
  • BeanPostProcessor 인터페이스는 BeanPostProcessor 인터페이스의 bean을 구현하며 bean을 인스턴스화할 때 Spring은 인터페이스에서 메소드를 호출하도록 도와줍니다.
  • InitializingBean 인터페이스를 구현하는 Bean인 InitializingBean 인터페이스 Spring은 Bean을 인스턴스화할 때 인터페이스에서 메서드를 호출하는 데 도움이 됩니다.
  • DisposableBean 인터페이스는 BeanPostProcessor 인터페이스를 구현한 빈으로, 빈이 죽으면 스프링이 인터페이스에서 메서드를 호출하도록 도와준다.

1.4 디자인 의의:

느슨한 결합. 원래 하드코딩된 종속성은 Spring beanFactory 팩토리를 통해 주입될 수 있습니다. 느슨한 결합 효과를 달성하기 위한 종속성 문제.

콩 추가 가공. Spring 인터페이스의 노출을 통해 우리는 bean을 인스턴스화하는 단계에서 몇 가지 추가 처리를 수행할 수 있으며 이러한 추가 처리는 bean이 해당 인터페이스를 구현하도록 하기만 하면 spring은 bean 수명 주기에서 구현한 인터페이스를 호출합니다. 콩을 폐기하십시오. (매우 중요)

2가지 팩토리 메소드

2.1 구현 방법:

FactoryBean 인터페이스.

2.2 구현 원칙:

FactoryBean 인터페이스를 구현하는 빈은 팩토리라고 불리는 빈의 일종이다. 특징은 bean을 얻기 위해 getBean() 호출을 사용할 때 spring이 자동으로 bean의 getObject() 메서드를 호출하므로 반환되는 것은 factory bean이 아니라 bean.getOjbect() 메서드의 반환값이다. .

2.3 예

대표적인 예가 spring과 mybatis의 조합이다.
코드 예:
여기에 이미지 설명 삽입

설명:
FactoryBean 인터페이스를 구현하므로 반환되는 것은 SqlSessionFactoryBean의 인스턴스가 아니라 해당 SqlSessionFactoryBean.getObject()의 반환 값이므로 위의 bean을 살펴보겠습니다.

3 싱글톤 모드

3.1 구현 프로세스

  • 스프링 종속성 주입 빈 인스턴스는 기본적으로 싱글톤입니다.
  • Spring의 의존성 주입(lazy-init 메소드 포함)은 AbstractBeanFactory의 getBean에서 발생합니다.
  • getBean의 doGetBean 메소드는 bean을 작성하기 위해 getSingleton을 호출합니다.
    getSingleton() 메서드 분석
public Object getSingleton(String beanName){
    
    
    //参数true设置标识允许早期依赖
    return getSingleton(beanName,true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    
    
    //检查缓存中是否存在实例
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    
    
        //如果为空,则锁定全局变量并进行处理。
        synchronized (this.singletonObjects) {
    
    
            //如果此bean正在加载,则不处理
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
    
    
                //当某些方法需要提前初始化的时候则会调用addSingleFactory 方法将对应的ObjectFactory初始化策略存储在singletonFactories
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
    
    
                    //调用预先设定的getObject方法
                    singletonObject = singletonFactory.getObject();
                    //记录在缓存中,earlysingletonObjects和singletonFactories互斥
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
  • getSingleton() 프로세스 다이어그램
    ps: 스프링 종속성 주입 시 이중 판단 및 잠금 기능이 있는 싱글톤 모드가 사용됩니다.
    여기에 이미지 설명 삽입

3.2 요약

싱글톤 패턴 정의: 클래스의 인스턴스가 하나만 있음을 보장하고 액세스할 수 있는 전역 액세스 지점을 제공합니다.
Spring의 싱글톤 구현: Spring의 싱글톤 패턴은 문장의 후반부를 완성합니다. 즉, 전역 액세스 지점 BeanFactory를 제공합니다. 그러나 Spring은 임의의 Java 객체를 관리하기 때문에 생성자 수준에서 싱글톤 제어가 없습니다.

4 어댑터 모드

4.1 구현 방법:

SpringMVC의 어댑터 핸들러Adatper.

4.2 구현 원칙:

HandlerAdatper는 핸들러 규칙에 따라 다른 핸들러를 실행합니다.

4.3 구현 프로세스:

DispatcherServlet은 HandlerMapping에 의해 반환된 핸들러에 따라 핸들러를 처리하기 위해 HandlerAdatper에 대한 요청을 시작합니다.

HandlerAdapter는 규칙에 따라 해당 Handler를 찾아 실행하고, 실행 후 Handler는 HandlerAdapter에 ModelAndView를 반환하고 마지막으로 HandlerAdapter는 DispatchServelet에 ModelAndView를 반환합니다.

4.4 실현의 중요성:

HandlerAdatper를 사용하면 새로운 Handler와 해당 HandlerAdapter를 추가하기만 하면 Handler를 쉽게 확장할 수 있습니다.

따라서 Spring은 각 유형의 Controller에 해당 어댑터 구현 클래스가 있으므로 어댑터가 컨트롤러 대신 해당 메서드를 실행할 수 있도록 적응 인터페이스를 정의합니다. 이와 같이 Controller를 확장할 때 하나의 어댑터 클래스만 추가하면 SpringMVC의 확장이 완료된다.

5 데코레이터 패턴

5.1 구현 방법:

Spring에서 사용되는 래퍼 패턴은 클래스 이름에 두 가지 표현이 있습니다. 하나는 클래스 이름에 Wrapper가 포함되어 있고 다른 하나는 클래스 이름에 Decorator가 포함되어 있다는 것입니다.

5.2 물질:

개체에 일부 추가 책임을 동적으로 추가합니다.
데코레이터 패턴은 기능 추가 측면에서 서브클래싱보다 더 유연합니다.

6 프록시 모드

6.1 구현 방법:

AOP의 최하위 계층은 동적 프록시 모드의 실현입니다.

  • 동적 프록시: 메모리 내장, 프록시 클래스를 수동으로 작성할 필요 없음
  • 정적 프록시: 프록시 클래스를 수동으로 작성해야 하며 프록시 클래스는 프록시 개체를 참조합니다.

6.2 구현 원칙:

Aspect는 런타임 시 애플리케이션에 통합됩니다. 일반적으로 AOP 컨테이너는 대상 객체에 대한 프록시 객체를 동적으로 생성합니다. Spring AOP는 이러한 방식으로 aspect를 엮는다.

짜기: 대상 개체에 측면을 적용하고 새 프록시 개체를 만드는 프로세스입니다.

7 관찰자 패턴

7.1 구현 방법:

Spring의 이벤트 기반 모델은 관찰자 모드를 사용하며 Spring에서 관찰자 모드의 일반적인 사용은 수신기의 구현입니다.

7.2 특정 구현:

이벤트 메커니즘의 구현에는 이벤트 소스, 이벤트 및 이벤트 리스너의 세 부분이 필요합니다.

7.2.1 ApplicationEvent 추상 클래스(이벤트)

  • jdk의 EventObject에서 상속받은 모든 이벤트는 ApplicationEvent를 상속받아 생성자 파라미터 source를 통해 이벤트 소스를 가져와야 합니다.
  • 이 클래스의 구현 클래스 ApplicationContextEvent는 ApplicaitonContext의 컨테이너 이벤트를 나타냅니다.
  • 암호:
public abstract class ApplicationEvent extends EventObject {
    
    
    private static final long serialVersionUID = 7099057708183571937L;
    private final long timestamp;
    public ApplicationEvent(Object source) {
    
    
    super(source);
    this.timestamp = System.currentTimeMillis();
    }
    public final long getTimestamp() {
    
    
        return this.timestamp;
    }
}

7.2.2 ApplicationListener 인터페이스(이벤트 리스너)

  • jdk의 EventListener에서 상속된 모든 리스너는 이 인터페이스를 구현해야 합니다.
  • 이 인터페이스에는 ApplicationEvent 또는 그 하위 클래스 객체를 매개변수로 받는 onApplicationEvent() 메서드가 하나만 있으며 메서드 본문에서 Event 클래스에 대한 다양한 판단을 통해 해당 처리를 수행할 수 있습니다.
  • 모든 리스너는 이벤트가 발생하면 메시지를 받습니다.
  • 암호:
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    
    
     void onApplicationEvent(E event);
}

7.2.3 ApplicationContext 인터페이스(이벤트 소스)

  • ApplicationContext는 스프링의 글로벌 컨테이너로 "애플리케이션 컨텍스트"로 번역됩니다.
  • ApplicationEventPublisher 인터페이스를 구현했습니다.
  • 책임: 빈 구성 문서 읽기, 빈 로드 관리 및 빈 간의 종속성 유지를 담당합니다.빈의 전체 수명 주기를 담당한다고 할 수 있습니다.더 일반적으로 IOC 컨테이너라고 부르는 것입니다.
  • 암호:
public interface ApplicationEventPublisher {
    
    
        void publishEvent(ApplicationEvent event);
}

public void publishEvent(ApplicationEvent event) {
    
    
    Assert.notNull(event, "Event must not be null");
    if (logger.isTraceEnabled()) {
    
    
         logger.trace("Publishing event in " + getDisplayName() + ": " + event);
    }
    getApplicationEventMulticaster().multicastEvent(event);
    if (this.parent != null) {
    
    
    this.parent.publishEvent(event);
    }
}

7.2.4 ApplicationEventMulticaster 추상 클래스(이벤트 소스의 publishEvent 메소드는 getApplicationEventMulticaster 메소드를 호출해야 함)

  • 이는 이벤트 브로드캐스터에 속하며 그 기능은 Applicationcontext가 게시한 이벤트를 모든 리스너에게 브로드캐스트하는 것입니다.
  • 암호:
public abstract class AbstractApplicationContext extends DefaultResourceLoader
    implements ConfigurableApplicationContext, DisposableBean {
    
    
    private ApplicationEventMulticaster applicationEventMulticaster;
    protected void registerListeners() {
    
    
    // Register statically specified listeners first.
    for (ApplicationListener<?> listener : getApplicationListeners()) {
    
    
    getApplicationEventMulticaster().addApplicationListener(listener);
    }
    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String lisName : listenerBeanNames) {
    
    
    getApplicationEventMulticaster().addApplicationListenerBean(lisName);
    }
  }
}

8 전략 모드

8.1 구현 방법:

Spring 프레임워크의 자원은 Resource 인터페이스에 액세스합니다. 이 인터페이스는 보다 강력한 리소스 액세스 기능을 제공하며 Spring 프레임워크 자체는 Resource 인터페이스를 광범위하게 사용하여 기본 리소스에 액세스합니다.

8.2 리소스 인터페이스 소개

소스 인터페이스는 특정 리소스 액세스 전략의 추상화이며 모든 리소스 액세스 클래스에 의해 구현되는 인터페이스이기도 합니다.
Resource 인터페이스는 주로 다음 메서드를 제공합니다.

  • getInputStream(): 리소스를 찾아 열고 리소스에 해당하는 입력 스트림을 반환합니다. 각 호출은 새로운 입력 스트림을 반환합니다. 호출자는 입력 스트림을 닫아야 합니다.
  • exists(): Resource가 가리키는 리소스가 존재하는지 여부를 반환합니다.
  • isOpen(): 리소스 파일이 열려 있는지 여부를 반환합니다. 리소스 파일을 여러 번 읽을 수 없는 경우 리소스 누수를 방지하기 위해 매번 읽을 때마다 명시적으로 닫아야 합니다.
  • getDescription(): 리소스 처리 오류 발생 시 정보를 출력하기 위해 일반적으로 사용되는 리소스의 설명 정보를 반환하며, 일반적으로 정규화된 파일 이름 또는 실제 URL입니다.
  • getFile: 리소스에 해당하는 File 객체를 반환합니다.
  • getURL: 리소스에 해당하는 URL 개체를 반환합니다.

마지막 두 가지 방법은 일반적으로 사용하지 않으며, Resource는 단순 접근이 불가능한 경우에만 전통적인 리소스 접근 기능을 제공합니다.

리소스 인터페이스 자체는 기본 리소스에 액세스하기 위한 구현 논리를 제공하지 않습니다.다른 기본 리소스에 대해 Spring은 다른 리소스 구현 클래스를 제공하며 다른 구현 클래스는 다른 리소스 액세스 논리를 담당합니다.

Spring은 Resource 인터페이스에 대해 다음과 같은 구현 클래스를 제공합니다.

  • UrlResource: 네트워크 리소스에 액세스하기 위한 구현 클래스입니다.
  • ClassPathResource: 클래스 로딩 경로에서 리소스에 액세스하기 위한 구현 클래스입니다.
  • FileSystemResource: 파일 시스템의 리소스에 액세스하기 위한 구현 클래스입니다.
  • ServletContextResource: ServletContext 경로에 상대적인 리소스에 액세스하기 위한 구현 클래스입니다.
  • InputStreamResource: 입력 스트림 리소스에 액세스하기 위한 구현 클래스입니다.
  • ByteArrayResource: 바이트 배열 리소스에 액세스하기 위한 구현 클래스입니다.

이러한 Resource 구현 클래스는 서로 다른 기본 리소스에 해당하는 리소스 액세스 논리를 제공하고 클라이언트 프로그램에서 리소스 액세스를 용이하게 하는 편리한 패키징을 제공합니다.

9 템플릿 방법 패턴

9.1 클래식 템플릿 메서드 정의:

부모 클래스는 스켈레톤(어떤 메서드가 호출되고 어떤 순서로 호출되는지)을 정의하고 일부 특정 메서드는 하위 클래스에 의해 구현됩니다.

가장 큰 이점은 코드 재사용, 코드 중복 감소입니다. 하위 클래스에 의해 구현되는 특정 메서드를 제외하고 다른 메서드와 메서드 호출 순서는 부모 클래스에 미리 작성되어 있습니다.

따라서 부모 클래스 템플릿 메서드에는 두 가지 유형의 메서드가 있습니다.

공통 방법: 모든 하위 클래스에서 사용되는 코드

다른 방법: 하위 클래스에 의해 재정의되는 방법은 두 가지 유형으로 나뉩니다.

  • 추상 메서드: 부모 클래스는 추상 메서드이며 하위 클래스는 이를 재정의해야 합니다.
  • 후크 방식: 부모 클래스의 빈 메서드이며 하위 클래스는 기본을 상속받으며 역시 비어 있습니다.

참고: 후크라고 하는 이유는 이 후크가 실제로는 부모 클래스의 메서드(빈 메서드)이기 때문에 하위 클래스는 이 후크(메소드)를 통해 부모 클래스를 제어할 수 있습니다!

9.2 Spring 템플릿 메소드 패턴의 본질:

템플릿 메서드 모드와 콜백 모드의 조합이며 상속이 필요하지 않은 템플릿 메서드의 또 다른 구현입니다. 거의 모든 Spring의 추가 기능 확장이 이 모드를 사용합니다.

9.3 구체적인 구현:

JDBC의 추상화와 Hibernate의 통합은 둘 다 개념 또는 처리 방법을 채택합니다. 즉, 템플릿 메서드 패턴이 해당 콜백 인터페이스와 결합됩니다.

템플릿 메서드 패턴은 통합되고 중앙화된 방식으로 리소스의 획득 및 해제를 처리하는 데 사용됩니다. JdbcTempalte를 예로 들어 보겠습니다.

public abstract class JdbcTemplate {
    
    
     public final Object execute(String sql){
    
    
        Connection con=null;
        Statement stmt=null;
        try{
    
    
            con=getConnection();
            stmt=con.createStatement();
            Object retValue=executeWithStatement(stmt,sql);
            return retValue;
        }catchSQLException e){
    
    
             ...
        }finally{
    
    
            closeStatement(stmt);
            releaseConnection(con);
        }
    }
    protected abstract Object executeWithStatement(Statement   stmt, String sql);
}

9.4 콜백을 도입한 이유:

JdbcTemplate은 추상 클래스이므로 독립적으로 사용할 수 없으며 데이터에 접근할 때마다 해당 하위 클래스 구현을 제공해야 하는데 이는 확실히 불편하므로 콜백을 도입합니다.

콜백 코드

public interface StatementCallback{
    
    
    Object doWithStatement(Statement stmt);
}

콜백 메서드를 사용하여 JdbcTemplate 메서드를 다시 작성합니다.

public class JdbcTemplate {
    
    
    public final Object execute(StatementCallback callback){
    
    
        Connection con=null;
        Statement stmt=null;
        try{
    
    
            con=getConnection();
            stmt=con.createStatement();
            Object retValue=callback.doWithStatement(stmt);
            return retValue;
        }catchSQLException e){
    
    
            ...
        }finally{
    
    
            closeStatement(stmt);
            releaseConnection(con);
        }
    }

    ...//其它方法定义
}

Jdbc는 다음과 같이 사용됩니다.

JdbcTemplate jdbcTemplate=...;
    final String sql=...;
    StatementCallback callback=new StatementCallback(){
    
    
    public Object=doWithStatement(Statement stmt){
    
    
        return ...;
    }
}
jdbcTemplate.execute(callback);

9.5 JdbcTemplate이 상속을 사용하지 않는 이유는 무엇입니까?

이 클래스에는 메서드가 너무 많지만 여전히 JdbcTemplate의 기존 안정적인 공용 데이터베이스 연결을 사용하고 싶기 때문에 어떻게 해야 합니까?

변경된 사항을 추출하여 JdbcTemplate 메소드에 매개변수로 전달할 수 있습니다. 그러나 변경되는 것은 코드 조각이며 이 코드는 JdbcTemplate의 변수를 사용합니다. 무엇을 해야 합니까?

그런 다음 콜백 개체를 사용합니다. 이 콜백 객체에는 JdbcTemplate에서 변수를 조작하기 위한 메소드를 정의하고, 이 메소드를 구현할 때 여기에 중점적으로 변경하도록 하겠습니다. 그런 다음 이 콜백 개체를 JdbcTemplate에 전달하여 호출을 완료합니다.

Supongo que te gusta

Origin blog.csdn.net/qq_37284798/article/details/129987705
Recomendado
Clasificación