Design Pattrns in Spring Framework - tenji/ks GitHub Wiki
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 不管是静态代理还是动态代理,都需要生成代理类,而且用户并不感知这个代理类。
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
在 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
在 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 应用程序内的灵活性和可读性。
在 Spring Boot 中,代理模式用于面向方面编程 (AOP) 框架内,以便将横切关注点应用于组件,而无需修改其核心逻辑。AOP 允许开发人员将关注点(例如日志记录、安全性、缓存)与主要业务逻辑分开,从而促进模块化和可重用性。
通过 Spring Boot 的 AOP 实现代理模式的步骤:
-
创建一个切面(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...");
}
}
-
定义切入点(Pointcuts):
切入点指定了应该应用 Advice(cross-cutting concern)的位置。在上面的例子中,切入点表达式
(execution(* com.example.service.*.*(..)))
针对com.example.service
包中的所有方法。 -
应用建议(Advice):
建议(Advice)定义了在方法调用之前、之后或周围应执行的行为。在这种情况下,
@Before
advice 在调用目标方法之前执行日志记录逻辑。 -
启用切面自动代理(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...");
}
}
-
将切面(Aspect)应用于目标组件(Components):
使用
@Service
、@Repository
或@Controller
等注释来注释目标组件或方法,以便让 Spring 知道该方面应该应用于哪些 bean。
...
更多关于代理模式,Proxy Design Pattern