当前位置: 首页 > news >正文

三层架构与分层解耦:深入理解IOC与DI设计模式

目录

一、软件架构演进与三层架构概述

1.1 从单体架构到分层架构

1.2 经典三层架构详解

1.3 三层架构的优势

二、分层解耦的核心思想

2.1 耦合与解耦的基本概念

2.2 分层解耦的实现手段

2.3 分层解耦的实践原则

三、控制反转(IOC)深度解析

3.1 IOC概念与演进历史

3.1.1 传统控制流程

3.1.2 IOC控制流程

3.2 IOC的实现方式

3.2.1 模板方法模式

3.2.2 回调函数

3.2.3 依赖注入

3.3 IOC容器的核心功能

3.4 IOC的优缺点分析

四、依赖注入(DI)全面剖析

4.1 DI基本概念与实现方式

4.1.1 构造函数注入

4.1.2 Setter方法注入

4.1.3 接口注入

4.2 现代DI框架的高级特性

4.2.1 自动装配(Autowiring)

4.2.2 限定符(Qualifiers)

4.2.3 条件化装配

4.2.4 延迟初始化

4.3 DI的最佳实践

五、Spring框架中的IOC与DI实现

5.1 Spring IOC容器体系

5.1.1 BeanFactory与ApplicationContext

5.1.2 容器初始化过程

5.2 Spring DI的注解驱动开发

5.2.1 核心注解

5.2.2 典型配置示例

5.3 Spring高级DI特性

5.3.1 生命周期管理

5.3.2 作用域扩展

5.3.3 延迟依赖解析

六、实战:构建三层架构的Spring应用

6.1 项目结构与依赖配置

6.2 各层实现详解

6.2.1 数据访问层(Repository)

6.2.2 业务逻辑层(Service)

6.2.3 表示层(Controller)

6.3 配置与集成

6.3.1 主配置类

6.3.2 Web配置

6.4 测试策略

6.4.1 单元测试

6.4.2 集成测试

七、IOC与DI的高级主题与最佳实践

7.1 解决复杂依赖场景

7.1.1 循环依赖处理

7.1.2 条件化装配策略

7.2 性能优化技巧

7.3 设计模式与DI的结合

7.3.1 装饰器模式

7.3.2 策略模式

7.4 现代Java中的DI趋势

八、常见问题与解决方案

8.1 IOC/DI实施中的典型问题

问题1:Bean创建异常

问题2:依赖注入冲突

问题3:作用域不匹配

8.2 调试技巧与工具

8.3 性能调优指南

九、总结与展望

9.1 关键要点回顾

9.2 未来发展趋势

9.3 学习资源推荐


一、软件架构演进与三层架构概述

1.1 从单体架构到分层架构

在软件开发初期,应用程序通常采用单体架构(Monolithic Architecture),所有功能模块紧密耦合在一起。随着业务复杂度增加,这种架构暴露出诸多问题:

  • 代码维护困难

  • 功能扩展性差

  • 团队协作效率低

  • 技术栈升级困难

分层架构(Layered Architecture)应运而生,通过将系统划分为多个职责分明的层次,解决了上述问题。其中,三层架构是最经典且广泛采用的分层模式。

1.2 经典三层架构详解

三层架构将应用程序划分为三个主要层次:

  1. 表示层(Presentation Layer)

    • 负责用户界面和交互

    • 处理用户输入和展示输出

    • 典型实现:Web MVC框架、客户端应用

  2. 业务逻辑层(Business Logic Layer)

    • 核心业务规则和流程实现

    • 数据处理和业务验证

    • 典型实现:服务组件、领域模型

  3. 数据访问层(Data Access Layer)

    • 与数据存储系统交互

    • 提供数据的CRUD操作

    • 典型实现:DAO模式、ORM框架

1.3 三层架构的优势

  1. 解耦性:各层职责明确,降低耦合度

  2. 可维护性:修改某层不影响其他层

  3. 可扩展性:可独立扩展某层功能

  4. 可测试性:便于单元测试和集成测试

  5. 团队协作:不同团队可并行开发不同层次

二、分层解耦的核心思想

2.1 耦合与解耦的基本概念

耦合(Coupling)指软件模块间的依赖程度,高耦合系统存在以下问题:

  • 牵一发而动全身

  • 难以复用单个模块

  • 测试困难

解耦(Decoupling)是通过设计手段降低模块间依赖程度的技术,目标是实现:

  • 模块独立演化

  • 接口契约编程

  • 依赖关系清晰

2.2 分层解耦的实现手段

  1. 面向接口编程

    // 紧耦合实现
    public class OrderService {private OrderRepository repository = new MySQLOrderRepository();
    }// 解耦实现
    public class OrderService {private OrderRepository repository;public OrderService(OrderRepository repository) {this.repository = repository;}
    }
  2. 依赖注入

    • 构造函数注入

    • Setter方法注入

    • 接口注入

  3. 工厂模式

    public class RepositoryFactory {public static OrderRepository createOrderRepository() {return new MySQLOrderRepository();}
    }
  4. 服务定位器模式

    public class ServiceLocator {private static Map<String, Object> services = new HashMap<>();public static void register(String name, Object service) {services.put(name, service);}public static Object getService(String name) {return services.get(name);}
    }

2.3 分层解耦的实践原则

  1. 依赖倒置原则(DIP)

    • 高层模块不应依赖低层模块,二者都应依赖抽象

    • 抽象不应依赖细节,细节应依赖抽象

  2. 单一职责原则(SRP)

    • 每个类/模块只负责一个功能领域

  3. 接口隔离原则(ISP)

    • 客户端不应被迫依赖它不使用的接口

  4. 迪米特法则(LoD)

    • 一个对象应当对其他对象有尽可能少的了解

三、控制反转(IOC)深度解析

3.1 IOC概念与演进历史

控制反转(Inversion of Control)是一种软件设计原则,最早由Michael Mattson在1996年提出,后由Martin Fowler推广。其核心思想是:

"传统程序流程由开发者控制,而IOC将流程控制权交给框架/容器"

3.1.1 传统控制流程
public class TraditionalApp {public static void main(String[] args) {// 开发者控制所有对象创建和调用顺序Service service = new ServiceImpl();service.execute();}
}
3.1.2 IOC控制流程
public class IOCApp {public static void main(String[] args) {// 框架容器控制对象生命周期ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");Service service = context.getBean(Service.class);service.execute();}
}

3.2 IOC的实现方式

3.2.1 模板方法模式
public abstract class TemplateMethod {// 框架控制流程public void execute() {step1();step2();customStep();step3();}protected abstract void customStep();
}public class MyImplementation extends TemplateMethod {@Overrideprotected void customStep() {// 子类实现特定步骤}
}
3.2.2 回调函数
public class EventDispatcher {private Map<String, List<EventListener>> listeners = new HashMap<>();public void register(String eventType, EventListener listener) {listeners.computeIfAbsent(eventType, k -> new ArrayList<>()).add(listener);}public void dispatch(String eventType) {listeners.getOrDefault(eventType, Collections.emptyList()).forEach(EventListener::onEvent);}
}public interface EventListener {void onEvent();
}
3.2.3 依赖注入

最常见的IOC实现方式,详见第四章。

3.3 IOC容器的核心功能

现代IOC容器(如Spring、Guice)提供以下核心能力:

  1. 组件管理

    • 生命周期管理

    • 作用域控制(单例、原型等)

  2. 依赖解析

    • 自动装配

    • 循环依赖处理

  3. 配置管理

    • 多种配置源支持

    • 环境抽象

  4. AOP支持

    • 代理创建

    • 切面织入

  5. 扩展点

    • Bean后处理器

    • 工厂钩子

3.4 IOC的优缺点分析

优点:

  • 降低组件耦合度

  • 提高代码可测试性

  • 统一生命周期管理

  • 便于集中配置

  • 促进面向接口编程

缺点:

  • 学习曲线较陡

  • 调试复杂度增加

  • 启动时间可能变长

  • 过度使用会导致"配置地狱"

四、依赖注入(DI)全面剖析

4.1 DI基本概念与实现方式

依赖注入(Dependency Injection)是IOC的一种具体实现技术,由组件外部注入依赖项,而非组件自行创建。

4.1.1 构造函数注入
public class OrderService {private final OrderRepository repository;// 通过构造函数注入依赖public OrderService(OrderRepository repository) {this.repository = repository;}
}

优点:

  • 依赖不可变(final)

  • 完全初始化的对象

  • 易于测试

4.1.2 Setter方法注入
public class OrderService {private OrderRepository repository;// 通过setter方法注入依赖public void setRepository(OrderRepository repository) {this.repository = repository;}
}

优点:

  • 可选依赖

  • 可重新配置

  • 符合JavaBean标准

4.1.3 接口注入
public interface RepositoryAware {void setRepository(OrderRepository repository);
}public class OrderService implements RepositoryAware {private OrderRepository repository;@Overridepublic void setRepository(OrderRepository repository) {this.repository = repository;}
}

特点:

  • 显式接口契约

  • 较少使用

4.2 现代DI框架的高级特性

4.2.1 自动装配(Autowiring)
@Component
public class OrderService {@Autowiredprivate OrderRepository repository;
}

类型:

  • 按类型(byType)

  • 按名称(byName)

  • 构造函数自动装配

4.2.2 限定符(Qualifiers)
@Repository("jdbcRepo")
public class JdbcOrderRepository implements OrderRepository {}@Repository("jpaRepo")
public class JpaOrderRepository implements OrderRepository {}@Service
public class OrderService {@Autowired@Qualifier("jpaRepo")private OrderRepository repository;
}
4.2.3 条件化装配
@Configuration
public class AppConfig {@Bean@ConditionalOnProperty(name = "db.type", havingValue = "mysql")public OrderRepository mysqlRepo() {return new MySQLOrderRepository();}
}
4.2.4 延迟初始化
@Lazy
@Service
public class HeavyService {// 延迟到第一次使用时初始化
}

4.3 DI的最佳实践

  1. 优先使用构造函数注入

    • 特别是强制依赖

    • 保持不可变性

  2. 合理使用接口

    • 针对抽象编程

    • 便于模拟测试

  3. 避免循环依赖

    • 设计时注意依赖方向

    • 必要时引入第三方类

  4. 控制注入范围

    • 避免过度注入

    • 合理划分组件边界

  5. 结合模块化设计

    @Configuration
    public class RepositoryConfig {@Beanpublic OrderRepository orderRepository() {return new JpaOrderRepository();}
    }

五、Spring框架中的IOC与DI实现

5.1 Spring IOC容器体系

5.1.1 BeanFactory与ApplicationContext
// 基础容器
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));// 高级容器(推荐)
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

功能对比:

特性BeanFactoryApplicationContext
Bean实例化/装配
自动Bean后处理器注册×
便捷的MessageSource访问×
应用事件发布×
5.1.2 容器初始化过程
  1. 配置元数据读取

    • XML配置

    • 注解扫描

    • Java配置类

  2. Bean定义解析

    • BeanDefinition注册

  3. BeanFactory后处理

    • BeanDefinitionRegistryPostProcessor

    • BeanFactoryPostProcessor

  4. Bean实例化

    • 依赖查找

    • 依赖注入

  5. 初始化回调

    • InitializingBean

    • @PostConstruct

5.2 Spring DI的注解驱动开发

5.2.1 核心注解
  1. 声明Bean

    • @Component

    • @Service

    • @Repository

    • @Controller

    • @Configuration

  2. 依赖注入

    • @Autowired

    • @Inject (JSR-330)

    • @Resource (JSR-250)

  3. 配置相关

    • @Bean

    • @PropertySource

    • @Value

5.2.2 典型配置示例
@Configuration
@ComponentScan("com.example")
@PropertySource("classpath:app.properties")
public class AppConfig {@Bean@Profile("dev")public DataSource devDataSource() {return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();}@Bean@Profile("prod")public DataSource prodDataSource(@Value("${db.url}") String url,@Value("${db.user}") String user) {return new BasicDataSource(url, user);}
}

5.3 Spring高级DI特性

5.3.1 生命周期管理
public class LifecycleBean implements InitializingBean, DisposableBean {@PostConstructpublic void customInit() {// 注解方式初始化}@Overridepublic void afterPropertiesSet() {// 接口方式初始化}@PreDestroypublic void customDestroy() {// 注解方式销毁}@Overridepublic void destroy() {// 接口方式销毁}
}
5.3.2 作用域扩展
@Scope("thread")
public class ThreadScopedBean {// 线程作用域的Bean
}// 自定义作用域实现
public class ThreadScope implements Scope {private final ThreadLocal<Map<String, Object>> threadLocal = ThreadLocal.withInitial(HashMap::new);@Overridepublic Object get(String name, ObjectFactory<?> objectFactory) {Map<String, Object> scope = threadLocal.get();return scope.computeIfAbsent(name, k -> objectFactory.getObject());}// 其他方法实现...
}
5.3.3 延迟依赖解析
@Service
public class OrderService {@Autowiredprivate Provider<OrderRepository> repositoryProvider;public void process() {OrderRepository repository = repositoryProvider.get();// 每次调用get()获取新实例(根据作用域)}
}

六、实战:构建三层架构的Spring应用

6.1 项目结构与依赖配置

Maven依赖:

<dependencies><!-- Spring Core --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.8</version></dependency><!-- Database --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.8</version></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><version>1.4.200</version></dependency><!-- Web --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.8</version></dependency>
</dependencies>

项目结构:

src/
├── main/
│   ├── java/
│   │   └── com/
│   │       └── example/
│   │           ├── config/
│   │           ├── controller/
│   │           ├── service/
│   │           ├── repository/
│   │           ├── model/
│   │           └── Application.java
│   └── resources/
│       ├── application.properties
│       └── db/
└── test/└── java/└── com/example/

6.2 各层实现详解

6.2.1 数据访问层(Repository)
public interface UserRepository {User findById(Long id);List<User> findAll();void save(User user);
}@Repository
public class JdbcUserRepository implements UserRepository {private final JdbcTemplate jdbcTemplate;@Autowiredpublic JdbcUserRepository(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Overridepublic User findById(Long id) {return jdbcTemplate.queryForObject("SELECT * FROM users WHERE id = ?",new Object[]{id},(rs, rowNum) -> new User(rs.getLong("id"),rs.getString("username")));}// 其他方法实现...
}
6.2.2 业务逻辑层(Service)
public interface UserService {User getUserById(Long id);List<User> getAllUsers();void registerUser(User user);
}@Service
@Transactional
public class UserServiceImpl implements UserService {private final UserRepository userRepository;@Autowiredpublic UserServiceImpl(UserRepository userRepository) {this.userRepository = userRepository;}@Overridepublic User getUserById(Long id) {return userRepository.findById(id);}// 其他方法实现...@Transactional(readOnly = true)@Overridepublic List<User> getAllUsers() {return userRepository.findAll();}
}
6.2.3 表示层(Controller)
@RestController
@RequestMapping("/api/users")
public class UserController {private final UserService userService;@Autowiredpublic UserController(UserService userService) {this.userService = userService;}@GetMapping("/{id}")public ResponseEntity<User> getUser(@PathVariable Long id) {return ResponseEntity.ok(userService.getUserById(id));}@PostMappingpublic ResponseEntity<Void> createUser(@RequestBody User user) {userService.registerUser(user);return ResponseEntity.created(URI.create("/users/" + user.getId())).build();}
}

6.3 配置与集成

6.3.1 主配置类
@Configuration
@ComponentScan("com.example")
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class AppConfig {@Beanpublic DataSource dataSource(@Value("${db.url}") String url,@Value("${db.username}") String username,@Value("${db.password}") String password) {return new DriverManagerDataSource(url, username, password);}@Beanpublic JdbcTemplate jdbcTemplate(DataSource dataSource) {return new JdbcTemplate(dataSource);}@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}
6.3.2 Web配置
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {converters.add(new MappingJackson2HttpMessageConverter());}@Beanpublic ViewResolver viewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/WEB-INF/views/");resolver.setSuffix(".jsp");return resolver;}
}

6.4 测试策略

6.4.1 单元测试
@ExtendWith(MockitoExtension.class)
class UserServiceTest {@Mockprivate UserRepository userRepository;@InjectMocksprivate UserServiceImpl userService;@Testvoid getUserById_shouldReturnUser() {User expected = new User(1L, "test");when(userRepository.findById(1L)).thenReturn(expected);User actual = userService.getUserById(1L);assertEquals(expected, actual);verify(userRepository).findById(1L);}
}
6.4.2 集成测试
@SpringJUnitConfig(classes = TestConfig.class)
@Transactional
class UserServiceIntegrationTest {@Autowiredprivate UserService userService;@Autowiredprivate JdbcTemplate jdbcTemplate;@Testvoid registerUser_shouldPersistUser() {User user = new User(null, "integration");userService.registerUser(user);assertNotNull(user.getId());Integer count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users WHERE id = ?", Integer.class, user.getId());assertEquals(1, count.intValue());}
}

七、IOC与DI的高级主题与最佳实践

7.1 解决复杂依赖场景

7.1.1 循环依赖处理

Spring的三级缓存解决方案:

  1. 一级缓存:存放完全初始化好的Bean

  2. 二级缓存:存放早期暴露的原始Bean(未填充属性)

  3. 三级缓存:存放Bean工厂,用于生成原始Bean

最佳实践:

  • 尽量避免循环依赖

  • 使用setter注入替代构造器注入(Spring可解决)

  • 引入第三方类打破循环

7.1.2 条件化装配策略
@Configuration
public class DataSourceConfig {@Bean@ConditionalOnClass(name = "org.h2.Driver")public DataSource h2DataSource() {return new EmbeddedDatabaseBuilder().setType(H2).build();}@Bean@ConditionalOnProperty("mysql.enabled")public DataSource mysqlDataSource(@Value("${mysql.url}") String url) {return new MysqlDataSource(url);}
}

7.2 性能优化技巧

  1. 懒加载策略

    @Lazy
    @Service
    public class HeavyInitService {// 延迟初始化
    }
  2. 合理使用作用域

    • 无状态服务使用单例(默认)

    • 有状态组件使用原型或自定义作用域

  3. 避免过度注入

    • 检查注入点数量(建议不超过5-7个)

    • 考虑拆分过大的类

  4. 启动时优化

    @SpringBootApplication
    public class MyApp {public static void main(String[] args) {new SpringApplicationBuilder(MyApp.class).lazyInitialization(true).run(args);}
    }

7.3 设计模式与DI的结合

7.3.1 装饰器模式
public interface DataService {String fetchData();
}@Primary
@Service
public class CacheDataService implements DataService {private final DataService delegate;@Autowiredpublic CacheDataService(@Qualifier("mainDataService") DataService delegate) {this.delegate = delegate;}@Overridepublic String fetchData() {// 添加缓存逻辑return delegate.fetchData();}
}
7.3.2 策略模式
public interface PaymentStrategy {void pay(BigDecimal amount);
}@Service
@Qualifier("creditCard")
public class CreditCardPayment implements PaymentStrategy {@Overridepublic void pay(BigDecimal amount) {// 信用卡支付实现}
}@Service
public class PaymentService {private final Map<String, PaymentStrategy> strategies;@Autowiredpublic PaymentService(List<PaymentStrategy> strategyList) {this.strategies = strategyList.stream().collect(Collectors.toMap(s -> s.getClass().getAnnotation(Qualifier.class).value(),Function.identity()));}public void processPayment(String type, BigDecimal amount) {strategies.get(type).pay(amount);}
}

7.4 现代Java中的DI趋势

  1. Jakarta CDI (JSR 365)

    • 标准化的DI规范

    • 与Spring注解兼容

    • 在Jakarta EE/微服务中广泛使用

  2. Micronaut

    • 编译时DI处理

    • 极低启动时间

    • 适合Serverless场景

  3. Quarkus

    • 面向云原生

    • 结合CDI和Spring DI

    • GraalVM原生支持

  4. Dagger 2

    • 纯编译时DI

    • 高性能

    • Android开发首选

八、常见问题与解决方案

8.1 IOC/DI实施中的典型问题

问题1:Bean创建异常

症状:

Error creating bean with name 'userService': 
Injection of autowired dependencies failed

解决方案:

  1. 检查依赖Bean是否已定义

  2. 确认包扫描路径包含所有组件

  3. 检查循环依赖

问题2:依赖注入冲突

症状:

No qualifying bean of type 'com.example.Repository' available: 
expected single matching bean but found 2: jdbcRepo, jpaRepo

解决方案:

  1. 使用@Primary标记首选Bean

  2. 使用@Qualifier明确指定

  3. 重构接口设计,避免同一类型多实现

问题3:作用域不匹配

症状:

Scope 'request' is not active for the current thread

解决方案:

  1. 检查Bean的作用域是否与使用场景匹配

  2. 对于Web请求作用域,确保有活跃的请求上下文

  3. 考虑使用代理模式:

​
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)​

8.2 调试技巧与工具

  1. Spring Bean依赖图

    @Autowired
    private ConfigurableListableBeanFactory beanFactory;public void printBeanDependencies() {for (String name : beanFactory.getBeanDefinitionNames()) {BeanDefinition definition = beanFactory.getBeanDefinition(name);if (definition instanceof AbstractBeanDefinition) {String[] dependsOn = ((AbstractBeanDefinition) definition).getDependsOn();if (dependsOn != null) {System.out.println(name + " depends on: " + Arrays.toString(dependsOn));}}}
    }
  2. 使用Spring Boot Actuator

    management:endpoints:web:exposure:include: beans

    访问/actuator/beans查看所有Bean信息

  3. IDE工具支持

    • IntelliJ IDEA的Diagram功能

    • Eclipse的Spring Tools插件

8.3 性能调优指南

  1. 启动时间优化

    • 减少@ComponentScan范围

    • 使用延迟初始化

    • 避免启动时阻塞操作

  2. 内存占用优化

    • 合理使用原型作用域

    • 及时销毁不再需要的Bean

    • 避免过度使用AOP

  3. 依赖查找优化

    // 避免的写法(每次调用都查找)
    public void process() {MyService service = applicationContext.getBean(MyService.class);service.execute();
    }// 推荐的写法(一次性注入)
    @Autowired
    private MyService service;

九、总结与展望

9.1 关键要点回顾

  1. 三层架构是构建可维护企业应用的基础

    • 表示层:用户交互

    • 业务层:核心逻辑

    • 数据层:持久化操作

  2. 分层解耦通过以下方式实现:

    • 面向接口编程

    • 依赖注入

    • 控制反转

  3. IOC容器的核心价值:

    • 管理组件生命周期

    • 解耦依赖关系

    • 提供统一配置

  4. DI最佳实践

    • 优先使用构造函数注入

    • 合理划分组件作用域

    • 避免过度复杂的依赖关系

9.2 未来发展趋势

  1. 云原生DI

    • 轻量级容器

    • 编译时处理

    • 原生镜像支持

  2. 反应式编程整合

    • 响应式依赖注入

    • 非阻塞组件管理

  3. 函数式风格

    • Java函数式Bean注册

    • Kotlin DSL配置

  4. 多运行时支持

    • 跨环境配置

    • 混合云部署

9.3 学习资源推荐

  1. 经典书籍

    • 《Expert One-on-One J2EE Development without EJB》Rod Johnson

    • 《Dependency Injection》Dhanji R. Prasanna

    • 《Spring in Action》Craig Walls

  2. 在线资源

    • Spring官方文档

    • Martin Fowler的IOC文章

    • Java EE CDI规范

  3. 实践项目

    • 从零实现简易IOC容器

    • 重构传统应用为分层架构

    • 性能对比测试不同DI框架

通过本指南的系统学习,您应该已经掌握了三层架构与分层解耦的核心思想,深入理解了IOC和DI的设计原理与实现方式,并具备了在实际项目中应用这些技术的能力。架构之路永无止境,希望这些知识能成为您构建高质量软件系统的坚实基础。

相关文章:

三层架构与分层解耦:深入理解IOC与DI设计模式

目录 一、软件架构演进与三层架构概述 1.1 从单体架构到分层架构 1.2 经典三层架构详解 1.3 三层架构的优势 二、分层解耦的核心思想 2.1 耦合与解耦的基本概念 2.2 分层解耦的实现手段 2.3 分层解耦的实践原则 三、控制反转&#xff08;IOC&#xff09;深度解析 3.1…...

[react]Next.js之自适应布局和高清屏幕适配解决方案

序言 阅读前首先了解即将要用到的两个包的作用 1.postcss-pxtorem 自动将 CSS 中的 px 单位转换为 rem 单位按照设计稿尺寸直接写 px 值&#xff0c;由插件自动计算 rem 值 2.amfe-flexible 动态设置根元素的 font-size&#xff08;即 1rem 的值&#xff09;根据设备屏幕宽度和…...

TensorFlow深度学习实战——基于语言模型的动态词嵌入技术

TensorFlow深度学习实战——基于语言模型的动态词嵌入技术 0. 前言1. 基于语言模型的词嵌入1.1 ELMo 与 ULMFiT1.2 GPT1.3 BERT 2. 使用 BERT 作为特征提取器相关链接 0. 前言 基于语言模型的词嵌入技术&#xff0c;通过利用上下文信息来生成动态的词向量&#xff0c;大大提升…...

欧拉服务器操作系统部署deekseep(Ollama+DeekSeep+open WebUI)

​​一、解压并安装 Ollama​​ # 1. 解压文件&#xff08;默认会得到一个二进制文件&#xff09; tar -xzvf ollama-linux-amd64.tgz# 2. 将二进制文件安装到系统路径 sudo mv ollama /usr/local/bin/ sudo chmod x /usr/local/bin/ollama# 3. 验证安装 ollama --version链接…...

cocosCreator安卓隐私弹窗(链接版)

每次新上游戏都要重新弄这个隐私弹窗,记录一下下次直接抄。 一、创建Activity 1 用androidStudio 打开项目并切换到Android视角。 2 右键项目new一个空的Activity 3 修改Activity的名字并完成如下图 二、增加依赖文件 1 增加全局颜色定义文件:项目根目录 / res/values/ …...

统计销量前十的订单

传入参数&#xff1a; 传入begin和end两个时间 返回参数 返回nameList和numberList两个String类型的列表 controller层 GetMapping("/top10")public Result<SalesTop10ReportVO> top10(DateTimeFormat(pattern "yyyy-MM-dd") LocalDate begin,Dat…...

【Python爬虫】简单案例介绍2

本文继续接着我的上一篇博客【Python爬虫】简单案例介绍1-CSDN博客 目录 跨页 3.2 环境准备 跨页 当对单个页面的结构有了清晰的认识并成功提取数据后&#xff0c;接下来就需要考虑页面之间的跨页问题。此时我们便迎来了下一个关键任务&#xff1a;如何实现跨页爬取&#xf…...

适合单片机裸机环境的运行的软件定时器框架

如下这篇文档介绍了一个适用于裸机环境的软件定时器模块&#xff0c;其核心功能和实现如下&#xff1a; 模块功能&#xff1a;该模块通过硬件定时器中断实现时基累加&#xff0c;适合用于裸机程序的调度处理。它使用硬件定时中断&#xff08;如1ms一次&#xff09;来增加hw_ti…...

【ComfyUI】蓝耘元生代 | ComfyUI深度解析:高性能AI绘画工作流实践

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈人工智能与大模型应用 ⌋ ⌋ ⌋ 人工智能&#xff08;AI&#xff09;通过算法模拟人类智能&#xff0c;利用机器学习、深度学习等技术驱动医疗、金融等领域的智能化。大模型是千亿参数的深度神经网络&#xff08;如ChatGPT&…...

js的es6模块中 暴露的使用方法简介

在 JavaScript 的 ES6 模块系统中&#xff0c;一个模块文件只能有一个 export default。export default 用于导出一个默认值&#xff0c;这个默认值在导入时可以使用任意名称。 示例&#xff1a; 导出默认值&#xff1a; // myModule.jsexport default function greet() {con…...

基于Android的旅游自助APP(源码+lw+部署文档+讲解),源码可白嫖!

摘要 旅游自助APP设计的目的是为用户提供对景点信息和路线攻略、周边美食等方面的平台。 与PC端应用程序相比&#xff0c;旅游自助的设计主要面向于旅行者&#xff0c;旨在为用户提供一个旅游自助。用户可以通过APP及时景点信息&#xff0c;并对景点进行购票或收藏等。相反&am…...

SQL(7):合并字段,使用UNION,首先应使用SELECT进行检索,再使用UMION进行拼接

核心功能&#xff1a;合并查询结果 想象一下&#xff0c;你有两个不同的名单&#xff0c;你想把它们合并成一个大名单。UNION 和 UNION ALL 都是 SQL 里用来干这个“合并名单”的活儿的。它们可以把两个&#xff08;或更多&#xff09;SELECT 查询语句的结果合并到一起&#x…...

Spring MVC 全栈指南:RESTful 架构、核心注解与 JSON 实战解析

目录 RESTful API 设计规范Spring MVC 核心注解解析静态资源处理策略JSON 数据交互全解高频问题与最佳实践 一、RESTful API 设计规范 1.1 核心原则 原则说明示例 URI资源为中心URI 使用名词&#xff08;复数形式&#xff09;/users ✔️ /getUser ❌HTTP 方法语义化GET&…...

【第43节】实验分析windows异常分发原理

目录 前言 一、异常处理大致流程图 二、实验一&#xff1a;分析 KiTrap03 三、实验二&#xff1a;分析CommonDispatchException 四、代码探究&#xff1a;分析 KiDispatchException 函数 五、代码探究&#xff1a;伪代码分析用户层KiUserExceptionDispatcher 前言 在Wind…...

自动化测试概念篇

文章目录 目录1. 自动化1.1 自动化概念1.1.1 回归测试 1.2 自动化分类1.3 自动化测试金字塔 2. web自动化测试2.1 驱动2.1.1 安装驱动管理2.1.2 selenium库 3. Selenium3.1 一个简单的web自动化示例3.2 selenium驱动浏览器的工作原理 目录 自动化web自动化测试Selenium 1. 自…...

「数据可视化 D3系列」之开篇:开启数据可视化之旅

一、系列介绍 欢迎来到《快速学习D3.js》系列&#xff01;在这个系列中&#xff0c;我们将一起从零开始掌握D3.js&#xff08;Data-Driven Documents&#xff09;&#xff0c;一个强大的JavaScript库&#xff0c;用于创建动态、交互式的数据可视化。 无论你是前端开发者、数据…...

编译构建 WSO2 产品时的一些注意事项

编译构建 WSO2 产品时的一些注意事项 1、JDK 版本2、maven 版本3、npm 和 node 版本4、编译命令示例 1、JDK 版本 对于 WSO2 ESB、WSO2 EI 老产品&#xff0c;可以直接使用 JDK 1.8对于 WSO2 APIM、WSO2 IS、WSO2 MI 等产品的新版本&#xff0c;需要 JDK 11 以上 特别注意&…...

字符串与相应函数(下)

字符串处理函数分类 求字符串长度&#xff1a;strlen长度不受限制的字符串函数&#xff1a;strcpy,strcat,strcmp长度受限制的字符串函数:strncpy,strncat,strncmp字符串查找&#xff1a;strstr字符串切割&#xff1a;strtok错误信息报告&#xff1a;strerror字符操作&#xf…...

驾驭 Linux 云: JavaWeb 项目安全部署

目录 1. 引言 2. Linux 基础指令 2.1 ls 展示目录/文件 2.2 pwd 查看所在路径 2.3 mkdir 创建文件夹 2.4 cd 切换路径 2.5 touch 创建文件 2.6 rm 删除文件 2.6 rm -r/rf 删除文件夹 2.7 rz/sz 上传/下载文件 2.7.1 rz 上传文件 2.7.2 sz 下载文件 2.8 mv 移动文件…...

【MySQL数据库】InnoDB存储引擎:逻辑存储结构、内存架构、磁盘架构

逻辑存储结构 一个数据库是由一张张表组成的&#xff0c;而表中是由一个个段构成的&#xff0c;一个段是由区构成的&#xff0c;区空间是由页构成的&#xff0c;页是行构成的。 ①表空间&#xff1a;.ibd文件&#xff0c;一个mysql实例可以对应多个表空间&#xff0c;用于存储…...

HJ16 购物单

https://www.nowcoder.com/exam/oj/ta?tpId37 HJ16 购物单 描述 王强决定把年终奖用于购物&#xff0c;他把想买的物品分为两类&#xff1a;主件与附件。 主件可以没有附件&#xff0c;至多有 2个附件。附件不再有从属于自己的附件。如果要买归类为附件的物品&#xff0c;必…...

SLAM文献之DM-VIO: Delayed Marginalization Visual-Inertial Odometry

1. 算法概述 DM-VIO (Delayed Marginalization Visual-Inertial Odometry) 是一种基于延迟边缘化的视觉-惯性里程计算法&#xff0c;它结合了视觉和惯性测量单元(IMU)的数据进行位姿估计。该算法是VINS-Mono的改进版本&#xff0c;主要创新点在于采用了一种延迟边缘化策略&…...

【信息安全】黑芝麻A1000芯片安全启动方案

基于黑芝麻A1000芯片的安全启动方案实现指南: 一、安全启动流程架构设计 // 启动阶段状态机定义(基于A1000芯片手册) typedef enum {ROM_BOOT = 0x01, // BootROM验证 SPL_VERIFY = 0x02, // 二级加载器验证 ATF_SIGN_CHECK = 0x03, // ARM Trusted Firmware验证 OS_LOADE…...

初识Redis · list和hash类型

目录 前言&#xff1a; 哈希类型 基本命令 编码方式 应用场景 列表 基本命令 编码方式 应用场景 前言&#xff1a; 前文我们已经介绍了string的基本使用&#xff0c;以及对应的基本命令&#xff0c;最后也是简单的理解了一下string的应用场景&#xff0c;比如计数统计…...

golang-非orm数据库的操作与对比 database/sql、sqlx 和 sqlc

简单介绍 database/sql database/sql 是一个标准库软件包&#xff0c;负责与数据库&#xff08;主要是 SQL 关系数据库&#xff09;的连接和交互。 它为类 SQL 交互提供泛型接口、类型和方法。database/sql 在创建时将简单易用纳入考量&#xff0c;配置为支持与类 SQL 数据库…...

‌DeepSeek模型在非图形智能体的应用中是否需要GPU

答&#xff1a;不一定 概念 1、是否需要GPU与应用是否图形处理应用无关 2、文本内容智能体大多也需要GPU来提供更好的性能 3、‌DeepSeek模型在非图形智能体的应用中是否需要GPU取决于具体的模型版本和部署环境 不需要GPU的模型版本 ‌DeepSeek-R1-1.5B‌&#xff1a; 这…...

RadioMaster POCKET遥控器进入ExpressLRS界面一直显示Loading的问题解决方法

RadioMaster POCKET遥控器进入ExpressLRS界面一直显示Loading的问题解决方法 问题描述解决方法 问题描述 有一天我发现我的 RadioMaster POCKET 遥控器进入 ExpressLRS 设置界面时&#xff0c;界面却一直停留在 “Loading” 状态&#xff0c;完全无法进入设置界面。 我并没有…...

idea的快捷键使用以及相关设置

文章目录 快捷键常用设置 快捷键 快捷键作用ctrlshift/注释选中内容Ctrl /注释一行/** Enter文档注释ALT SHIFT ↑, ALT SHIFT ↓上下移动当前代码Ctrl ALT L格式化代码Ctrl X删除所在行并复制该行Ctrl D复制当前行数据到下一行main/psvm快速生成入口程序soutSystem.o…...

【DDR 内存学习专栏 1.4 -- DDR 的 Bank Group】

文章目录 BankgroupBankgroup 与 Bank 的关系 DDR4 中的 BankgroupDDR4-3200 8Gb芯片为例组织结构访问场景 实际应用示例 Bankgroup Bankgroup是DDR4及后续标准(DDR5)中引入的一个更高层次的组织结构。它将多个Bank组合在一起形成一个Bankgroup&#xff0c;目的是为了进一步提…...

新晋前端框架技术:小程序容器与SuperApp构建

2025年&#xff0c;前端开发领域持续迭代&#xff0c;主流框架如Vue、React等纷纷推出新版本&#xff0c;在性能、开发效率及适用场景上实现突破&#xff0c;进一步巩固其技术地位。 1. Vue 3的全面普及与创新 Vue 3通过多项核心特性优化了开发体验&#xff1a; Teleport组件…...

强化学习:基于价值的方法做的是回归,基于策略的方法做的是分类,可以这么理解吗?

在强化学习领域,基于价值的方法(Value-based Methods)和基于策略的方法(Policy-based Methods)是两种核心范式。本文将从目标函数、优化机制以及与机器学习任务的类比角度,探讨这两种方法是否可以被分别理解为回归和分类任务,并深入分析其内在逻辑。 一、基于价值的方法…...

蓝耘元生代AIDC OS:一站式MaaS平台,助力AI应用快速落地

文章目录 引言1. 什么是MaaS平台&#xff1f;MaaS平台的典型特点 2. 蓝耘元生代AIDC OS 热门模型3. 快速入门&#xff1a;如何调用API&#xff1f;步骤1&#xff1a;注册并获取API Key步骤2&#xff1a;调用API&#xff08;Python示例&#xff09; 4. 与Chatbox搭配使用&#x…...

3.2.2.3 Spring Boot配置拦截器

在Spring Boot应用中配置拦截器&#xff08;Interceptor&#xff09;可以对请求进行预处理和后处理&#xff0c;实现如权限检查、日志记录等功能。通过实现HandlerInterceptor接口并注册到Spring容器&#xff0c;拦截器可以自动应用到匹配的请求路径。案例中&#xff0c;创建了…...

Python----机器学习(基于PyTorch的蘑菇逻辑回归)

Logistic Regression&#xff08;逻辑回归&#xff09;是一种用于处理二分类问题的统计学习方法。它基于线性回归 模型&#xff0c;通过Sigmoid函数将输出映射到[0, 1]范围内&#xff0c;表示概率。逻辑回归常被用于预测某个实 例属于正类别的概率。 一、数据集介绍 本例使用了…...

Python----机器学习(基于PyTorch的乳腺癌逻辑回归)

Logistic Regression&#xff08;逻辑回归&#xff09;是一种用于处理二分类问题的统计学习方法。它基于线性回归 模型&#xff0c;通过Sigmoid函数将输出映射到[0, 1]范围内&#xff0c;表示概率。逻辑回归常被用于预测某个实 例属于正类别的概率。 一、数据集介绍 在本例中&…...

如何配置AWS EKS自动扩展组:实现高效弹性伸缩

本文详细讲解如何在AWS EKS中配置节点组&#xff08;Node Group&#xff09;和Pod的自动扩展&#xff0c;优化资源利用率并保障应用高可用。 一、准备工作 工具安装 安装并配置AWS CLI 安装eksctl&#xff08;EKS管理工具&#xff09; 安装kubectl&#xff08;Kubernetes命令…...

【C++ Qt】认识Qt、Qt 项目搭建流程(图文并茂、通俗易懂)

每日激励&#xff1a;“不设限和自我肯定的心态&#xff1a;I can do all things。 — Stephen Curry” 绪论​&#xff1a; 本章将开启Qt的学习&#xff0c;Qt是一个较为古老但仍然在GUI图形化界面设计中有着举足轻重的地位&#xff0c;因为它适合嵌入式和多种平台而被广泛使用…...

用Python打造去中心化知识产权保护系统:科技驱动创作者权益新方案

用Python打造去中心化知识产权保护系统:科技驱动创作者权益新方案 近年来,区块链技术和去中心化系统的兴起为知识产权保护提供了新的可能性。在传统模式下,知识产权保护通常依赖于集中化管理机构,这种方式不仅成本高,还可能因不透明导致权益争议。于是,我们萌生了一个设…...

CVE重要漏洞复现-Fastjson1.2.24-RCE漏洞

本文仅供网络学习&#xff0c;不得用于非法目的&#xff0c;否则后果自负 1、漏洞简介 fastjson是阿里巴巴的开源JSON解析库&#xff0c;它可以解析JSON格式的字符串&#xff0c;也可以从JSON字符串反序列化到JavaBean。即fastjson的主要功能就是将Java Bean序列化成JSON字符…...

Windows 图形显示驱动开发-WDDM 1.2功能—显示设备硬件软件认证要求

一、容器技术id技术的硬件级实现要求 1.1 EDID规范深度适配 1.物理层要求&#xff1a; 必须使用EDID 2.0及以上版本数据结构 容器ID需写入VSDB区块的0x50-0x6F区域&#xff0c;采用Little-Endian格式存储 允许的最大传输延迟&#xff1a;I2C总线时钟频率≤100KHz时&#xf…...

Coze流搭建--写入飞书多维表格

目标 使用coze搭建一个业务流&#xff0c;将业务流生产出的数据写入飞书保存 测试业务流 使用图片生成插件&#xff0c;配置prompt生产图片&#xff0c;将生产的结果写入飞书文档 coze流 运行后最终效果 搭建流程 第一步&#xff1a;飞书创建多维表格 注册飞书创建多维表…...

4.14:计组第三章

一、数据的强制类型转换与存储 1、边界对齐与大端小端方式 2、真-强制类型转换 二、存储器的基本知识(不包含磁盘存储器) 1、主存储器 (1)...

Vue3+Vite前端项目部署后部分图片资源无法获取、动态路径图片资源报404错误的原因及解决方案

目录 Vue3vite前端项目部署后部分图片资源无法获取、动态路径图片资源报404错误的原因及解决方案 一、情景介绍 1、问题出现的场景 2、无法加载的图片写法 二、反向代理原理简介 三、造成该现象的原因 四、解决方案 1、放弃动态渲染 2、在页面挂载的时候引入图片资源 …...

Nacos操作指南

第一章&#xff1a;Nacos 概述 1.1 什么是 Nacos&#xff1f; 定义与定位 Nacos&#xff08;Naming and Configuration Service&#xff09;是阿里巴巴于2018年开源的动态服务发现、配置管理和服务管理平台&#xff0c;现已成为微服务生态中的重要基础设施。其核心价值在于帮…...

2025年常见渗透测试面试题-红队面试宝典下(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 一、Java反序列化过程及利用链示例 二、大型网络渗透经验 三、Cobalt Strike的两种Dump Hash区别 四…...

扩增子分析|基于R语言microeco包进行微生物群落网络分析(network网络、Zi-Pi关键物种和subnet子网络图)

一、引言 microeco包是福建农林大学姚敏杰教授团队开发的扩增子测序集成分析。该包综合了扩增子测序下游分析的多种功能包括群落组成、多样性、网络分析、零模型等等。通过简单的几行代码可实现复杂的分析。因此&#xff0c;microeco包发表以来被学界广泛关注&#xff0c;截止2…...

flutter-Text等组件出现双层黄色下划线的问题

文章目录 1. 现象2. 原因3. 解决方法 1. 现象 这天我正在写Flutter项目的页面功能&#xff0c;突然发现我的 Text 文字出现了奇怪的样式&#xff0c;具体如下&#xff1a; 文字下面出现了双层黄色下划线文字的空格变得很大&#xff0c;文字的间距也变得很大 我百思不得其解&a…...

优化运营、降低成本、提高服务质量的智慧物流开源了

智慧物流视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本可通过边缘计算技术…...

leetcode第二题

功能函数 typedef struct ListNode {int val;struct ListNode *next; } ListNode;struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {ListNode *dummy (ListNode *)malloc(sizeof(ListNode));ListNode *cur dummy;int carry 0; //carry是进位值…...

QT实现带快捷键的自定义 QComboBox 控件

在现代GUI应用程序中&#xff0c;用户界面的设计不仅要美观&#xff0c;还要提供高效的交互方式。本文将介绍一个自定义的QCComboBox类&#xff0c;它是一个基于Qt的组合框&#xff08;QComboBox&#xff09;&#xff0c;支持为每个下拉项添加快捷键。通过这些快捷键&#xff0…...