You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

《Clean Architecture》架构下,非Spring环境如何创建包级访问修饰符服务?

Preserving Clean Architecture Encapsulation Without Spring (Or With Spring Java Config)

Great question! Let's break this down step by step—since you're aiming to keep that tight encapsulation pattern Simon Brown outlines in Clean Architecture (hiding implementation classes behind interfaces, with package-level access on implementations), we'll cover both Spring Java Config solutions and a fully Spring-free approach.

First: Fixing the Spring Java Config Issue

The problem with your initial AppConfig is that OrderServiceImpl has package-level access, so if your config class lives outside the com.my.service.impl package, it can't directly instantiate the class. Here are two clean ways to resolve this:

1. Move the Configuration Class to the Implementation Package

The simplest, most idiomatic fix is to place your @Configuration class in the same package as your implementation. This lets you legally access the package-level OrderServiceImpl:

// File: com/my/service/impl/AppConfig.java
@Configuration
public class AppConfig {
    @Bean
    OrderService orderService(){
        return new OrderServiceImpl(); // No access issues now—same package!
    }
}

This preserves the encapsulation: external code only ever references the OrderService interface, and the implementation stays hidden.

2. Use Reflection (Last Resort)

If you can't move the config class (for project structure reasons), you can use reflection to bypass the access modifier. Note: this breaks the spirit of encapsulation, so only use this if you have no other option:

@Configuration
public class AppConfig {
    @Bean
    OrderService orderService() throws Exception {
        // Get the package-level constructor
        Constructor<OrderServiceImpl> constructor = OrderServiceImpl.class.getDeclaredConstructor();
        // Disable access checks temporarily
        constructor.setAccessible(true);
        return constructor.newInstance();
    }
}

Fully Spring-Free Implementation

To replicate this pattern without any Spring dependencies, the key is to keep instance creation logic within the same package as your implementation class, so it can access the package-level OrderServiceImpl. Here are two solid approaches:

1. Simple Manual DI Container

Create a container class inside the impl package that handles instantiation, and exposes only the interface to the outside:

// File: com/my/service/impl/ServiceContainer.java
public class ServiceContainer {
    private final OrderService orderService;

    public ServiceContainer() {
        this.orderService = new OrderServiceImpl();
    }

    // Expose only the interface
    public OrderService getOrderService() {
        return orderService;
    }
}

Then use it in your application code:

public class App {
    public static void main(String[] args) {
        ServiceContainer container = new ServiceContainer();
        OrderService orderService = container.getOrderService();
        // Use orderService as needed—no reference to OrderServiceImpl anywhere!
    }
}

2. Factory Pattern (Cleaner for Scalability)

Define a factory interface in your public service package, then implement it as a package-level class in impl. Add a static helper method to the interface to get the factory:

// File: com/my/service/OrderService.java
public interface OrderService {
    List<Order> getOrders();

    // Static factory accessor—no external dependencies
    static OrderService createInstance() {
        return new DefaultOrderServiceFactory().createOrderService();
    }

    // Internal factory interface
    interface OrderServiceFactory {
        OrderService createOrderService();
    }
}

// File: com/my/service/impl/DefaultOrderServiceFactory.java
// Package-level access—only visible to same package
class DefaultOrderServiceFactory implements OrderService.OrderServiceFactory {
    @Override
    public OrderService createOrderService() {
        return new OrderServiceImpl();
    }
}

Now external code can get an instance without ever touching the implementation:

OrderService orderService = OrderService.createInstance();

All these approaches maintain the core idea from Simon Brown's chapter: hiding implementation details behind interfaces, with package-level access modifiers enforcing that no external code can depend on concrete classes.

内容的提问来源于stack exchange,提问作者Pavel Petrashov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 18:33:10