Design Pattrns in Spring Framework - tenji/ks GitHub Wiki

Spring 中的设计模式

Spring 框架中广泛应用了各种设计模式,比如:

  • Singleton Pattern (beans defined in spring config files are singletons by default)
  • Factory Pattern
  • Dependency Injection (DI)
  • Builder Pattern
  • Proxy Pattern (used heavily in AOP)
  • Chain of Responsibility Pattern
  • Observer Pattern
  • Strategy Pattern
  • Template Method Pattern

AOP (Aspect-Oriented Programming) 的底层设计模式是 Proxy Pattern 还是 Decorator Pattern?

是 Proxy Pattern 代理模式。AOP 不管是静态代理还是动态代理,都需要生成代理类,而且用户并不感知这个代理类。

Singleton Pattern

Spring Boot 广泛利用 Singleton 模式来管理和控制 Bean(由 Spring 容器管理的组件)的创建。默认情况下,除非另有规定,Spring 将对象作为容器内的单例进行管理。

当你在 Spring 中定义一个 Bean(例如,使用 @Component@Service@Repository@Controller 等注释)时,Spring IoC 容器会管理这些 Bean 的生命周期。默认情况下,Spring 在其容器中将这些 bean 作为单例进行管理,这意味着 Spring 只创建该 bean 的一个实例,并在注入或需要该 bean 的任何地方重用它。

使用示例

@Service  
public class DemoService {  
    // Your service logic here  
}

在此示例中,@Service 注释将 DemoService 标记为 Spring 管理的 bean。每当您从 Spring 应用程序上下文请求 DemoService 实例时,Spring 容器默认每次都会返回相同的实例,遵循单例模式。

但需要注意的是,虽然 Spring 默认以单例方式管理 bean,但开发人员可以配置 bean 的作用域。他们可以根据具体需求使用其他作用域,如原型(prototype,为每个请求创建一个新实例)、会话作用域(session scope)、请求作用域(request scope)等。

例如,使用 @Scope 注释允许开发人员指定不同的 bean 范围:

@Service
@Scope("prototype")
public class DemoPrototype {
    // Your service logic here
}

在这种情况下,每次从 Spring 应用程序上下文请求时,DemoPrototype bean 都会作为新实例创建,这与默认的 Singleton 行为不同。

原理

...

更多关于单例模式,Singleton Design Pattern

Factory Pattern

使用示例

在 Spring Boot 中,工厂模式应用于各种场景,以创建对象并管理其实例化。以下是一个例子:

FactoryBean 接口:Spring Boot 中的 FactoryBean 接口允许你定义用于创建 bean 的自定义工厂逻辑。此接口使您可以控制特定类型 bean 的创建过程。

import org.springframework.beans.factory.FactoryBean;  
  
public class MyFactoryBean implements FactoryBean<MyBean> {  
    @Override  
    public MyBean getObject() throws Exception {  
        // Custom logic to create and return MyBean instance  
        return new MyBean();  
    }  
  
    @Override  
    public Class<?> getObjectType() {  
        return MyBean.class;  
    }  
  
    @Override  
    public boolean isSingleton() {  
        return true; // Or false, depending on your bean's scope  
    }  
}

通过实现 FactoryBean,您可以在 getObject() 方法中定义创建 MyBean 实例的逻辑。这样,Spring Boot 就可以管理 MyBean 实例的创建和生命周期。

原理

...

BeanFactory 和 FactoryBean 的区别?

The root interface for accessing a Spring bean container.

这句话指明了 BeanFactory 在 Spring 家族中的地位,它是操作 Spring 容器、获取 Spring Bean 的根接口。从字面意思可以看出它是一个 Bean 工厂,其内部采用了工厂模式,通过它们我们可进行创建 Bean、获取 Bean 等操作。

FactoryBean 不是一个普通的 Bean,它实际上是一个用于创建特定 bean 的工厂,主要用于构建一些实例化过程较为复杂或有配置依赖的对象(即非普通 POJO),并将其交给 Spring 容器管理,这可以提高 Spring 框架扩展能力。FactoryBean 的示例可以查看:SqlSessionFactoryBean

更多关于工厂模式,Factory Design Pattern

Builder Pattern

在 Spring Boot 中,Builder 模式通常用于创建复杂对象,通过提供一种优雅的方式来使用多个可选参数或配置来构造它们。尽管 Builder 模式本身并未在 Spring Boot 中明确实现为设计模式,但开发人员经常使用它来构建复杂对象或配置组件。

使用示例

Spring Boot 中的构建器可以使用多种方法实现,包括使用 Lombok 的 @Builder 注释,或手动创建自定义构建器类。以下是示例:

import lombok.Builder;  
import lombok.Data;  
  
@Data  
@Builder  
public class User {  
    private String username;  
    private String email;  
    private int age;  
    // Other fields  
}

使用 Lombok 的 @Builder 注解,会自动为 User 类生成一个构建器类,从而可以流畅地构造 User 对象:

User user = User.builder()  
    .username("john_doe")  
    .email("[email protected]")  
    .age(30)  
    .build();

原理

使用 Lombok 的 @Builder 注解相当于以下的代码实现:

public class User {  
    private String username;  
    private String email;  
    private int age;  
  
    private User(Builder builder) {  
        this.username = builder.username;  
        this.email = builder.email;  
        this.age = builder.age;  
        // Set other fields  
    }  
  
    // Getters for User fields  
  
    public static class Builder {  
        private String username;  
        private String email;  
        private int age;  
  
        public Builder username(String username) {  
            this.username = username;  
            return this;  
        }  
  
        public Builder email(String email) {  
            this.email = email;  
            return this;  
        }  
  
        public Builder age(int age) {  
            this.age = age;  
            return this;  
        }  
  
        public User build() {  
            return new User(this);  
        }  
    }  
  
    // Other methods  
}

自定义 Builder 的用法:

User user = new User.Builder()  
    .username("john_doe")  
    .email("[email protected]")  
    .age(30)  
    .build();

Builder 模式有助于创建具有流畅且可读的界面的复杂对象,允许创建具有特定配置的对象,同时保持 Spring Boot 应用程序内的灵活性和可读性。

Proxy Pattern

在 Spring Boot 中,代理模式用于面向方面编程 (AOP) 框架内,以便将横切关注点应用于组件,而无需修改其核心逻辑。AOP 允许开发人员将关注点(例如日志记录、安全性、缓存)与主要业务逻辑分开,从而促进模块化和可重用性。

使用示例

通过 Spring Boot 的 AOP 实现代理模式的步骤:

  1. 创建一个切面(Aspect):

    切面包含了定义要采取什么操作以及在何处应用这些操作的建议。

import org.aspectj.lang.annotation.Aspect;  
import org.aspectj.lang.annotation.Before;  
  
@Aspect  
@Component  
public class LoggingAspect {  
      
    @Before("execution(* com.example.service.*.*(..))")  
    public void beforeServiceMethods() {  
        // Logic to be executed before service methods  
        System.out.println("Logging before service methods...");  
    }  
}
  1. 定义切入点(Pointcuts):

    切入点指定了应该应用 Advice(cross-cutting concern)的位置。在上面的例子中,切入点表达式 (execution(* com.example.service.*.*(..))) 针对 com.example.service 包中的所有方法。

  2. 应用建议(Advice):

    建议(Advice)定义了在方法调用之前、之后或周围应执行的行为。在这种情况下,@Before advice 在调用目标方法之前执行日志记录逻辑。

  3. 启用切面自动代理(Auto-Proxying):

    确保在 Spring Boot 应用程序中启用了 AOP。使用 @EnableAspectJAutoProxy 等注释时,它通常默认启用。

import org.aspectj.lang.annotation.Aspect;  
import org.aspectj.lang.annotation.Before;  
  
@Aspect  
@Component  
public class LoggingAspect {  
      
    @Before("execution(* com.example.service.*.*(..))")  
    public void beforeServiceMethods() {  
        // Logic to be executed before service methods  
        System.out.println("Logging before service methods...");  
    }  
}
  1. 将切面(Aspect)应用于目标组件(Components):

    使用 @Service@Repository@Controller 等注释来注释目标组件或方法,以便让 Spring 知道该方面应该应用于哪些 bean。

原理

...

更多关于代理模式,Proxy Design Pattern

∞、参考链接

⚠️ **GitHub.com Fallback** ⚠️