Spring在它的问题域内,通过准确的命名区分定义了不同的领域概念,我们在开发时可以多多借鉴参考
从上面的命名中也可以看见Spring运用了大量的设计模式和设计原则,这里着重提及一二。
拦截器应用广泛,扩展性强。先看下Spring的HandlerInceptor定义:
public interface HandlerInterceptor {
// handler执行前操作
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
// handler执行后操作
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
// handler执行完成后操作
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}应用拦截器一般如下(实际调用逻辑参考HandlerExecutionChain类):
public class Business {
private Interceptor[] interceptors;
public void handleBusiness(BusinessContext context) {
interceptors.forEach(interceotpr -> interceotpr.preHandle(context));
Result result = action();
interceptors.forEach(interceotpr -> interceotpr.postHandle(context, result));
}
}这里可以看到,通过拦截器我们可以把核心业务逻辑与扩展业务逻辑拆分开来,对于Spring MVC而言,处理request的handler是它的核心业务逻辑,扩展业务逻辑像鉴权、日志、request header校验、限流等等都可以放在Interceptor中。
其他一些例子:
Spring对不同的业务概念定义了不同的接口,一个接口下可能会对应多个不同的实现类,比如读写分离的接口设计ApplicationContext和ConfigurableApplicationContext:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
String getApplicationName();
... // 省略
}
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
void refresh() throws BeansException, IllegalStateException;
... // 省略
}Java开发者最频繁接触到的应该就是Spring框架了,平时开发中就可以多进入源码中翻翻看看,有助于培养良好的代码风格。
注意接口的使用有个常见的误区:无脑先定义一个接口后,再写一个对应的实现类,尽管实际上并没有多态的需求。这种代码形式常见于Spring MVC分层架构里,比如定义接口XxxService,然后一对一配对实现XxxServiceImpl。大量一对一的接口和实现类反而带来很多无效的工作量,没什么意义。相反,应该采取的方法是:1. 有深入的业务知识并且仔细思考后自上而下地定义好业务接口 2. 持续重构,按业务发展的需要自下而上地创建良好的业务接口。
依赖注入 - Dependency Injection, 控制反转 - inverse of control,是Spring框架扩展性的基石。Spring框架启动过程主要的两步:
以数据存储服务迁移为例认识下IOC框架提供的扩展性,比如从数据存储Storage_A迁移到数据存储Storage_B,处理流程一般如下:
@Service
public class StorageService {
public List<Record> read() {
// 数据存储A读取
}
public void insert(Record t) {
// 数据存储A写入
}
}public interface StorageService {
List<Record> read();
void insert(Record t);
}
@Service
public class StorageAService implements StorageService {
public List<Record> read() {
// 数据存储A读取
}
public void insert(Record t) {
// 数据存储A写入
}
}public interface StorageService {
List<Record> read();
void insert(Record t);
}
@Service
public class StorageAService implements StorageService {
public List<Record> read() {
// 数据存储A读取
}
public void insert(Record t) {
// 数据存储A写入
}
}
@Service
public class StorageBService implements StorageService {
public List<Record> read() {
// 数据存储B读取
}
public void insert(Record t) {
// 数据存储B写入
}
}
@Primary
@Service
public class StorageProxy implements StorageService {
private StorageAService storageAService;
private StorageBService storageBService;
public List<Record> read() {
// 双读控制
}
public void insert(Record t) {
// 双写控制
}
}public interface StorageService {
List<Record> read();
void insert(Record t);
}
@Service
public class StorageBService implements StorageService {
public List<Record> read() {
// 数据存储B读取
}
public void insert(Record t) {
// 数据存储B写入
}
}如上所示,通过Spring的依赖注入和代理模式的使用,实现了存储服务的迁移逻辑,但修改逻辑干净简洁。
无侵入实现横切的扩展逻辑,同样适用于日志、鉴权、异常处理等场景。
比如,Spring @Transactional注解的实现就是依赖于AOP,如下例所示:
@Repository
public class FirstRepository {
@Transactional
public void update() {
System.out.println("Update ...");
}
}
public interface SecondRepository {
void update();
}
@Repository
public class SecondRepositoryImpl implements SecondRepository {
@Transactional
public void update() {
System.out.println("Update");
}
}
@Service
public class BusinessService {
private FirstRepository firstRepository;
private SecondRepository secondRepository;
@Autowired
public void setFirstRepository(FirstRepository firstRepository) {
this.firstRepository = firstRepository;
}
@Autowired
public void setSecondRepository(SecondRepository secondRepository) {
this.secondRepository = secondRepository;
}
}Spring在启动时注入的Bean:

如上图所示,Spring通过运行时注入动态代理类的方式实现AOP,代理类的创建有两种方式:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。