在 Java 中实施分层体系结构

给定一个由三层组成的Java编写的软件系统,A ->B -> C,即A层使用B层,B层使用C层。

我想确保一个层的类只能访问同一层的类或其直接依赖关系,即B应该能够访问C而不是A。此外,A 应该能够访问 B,但不能访问 C。

有没有一种简单的方法来执行这样的限制?理想情况下,我希望 eclipse 在尝试访问错误层的类时立即抱怨。

该软件目前使用maven。因此,我试图将A,B和C放入不同的maven模块中,并正确声明依赖项。这可以很好地防止 B 访问 A,但不会阻止 A 访问 C。

接下来,我试图将C从依赖关系中排除到B。现在,这也阻止了从 A 到 C 的访问。但是,现在我不再能够使用复制依赖项来收集运行时所需的所有传递依赖项。

有没有一种好方法可以让我干净地分离层,同时也允许我收集所有需要的运行时依赖项?


答案 1

在 maven 中,您可以使用 maven-macker-plugin,如以下示例所示:

<build>
    <plugins>
        <plugin>
            <groupId>de.andrena.tools.macker</groupId>
            <artifactId>macker-maven-plugin</artifactId>
            <version>1.0.2</version>
            <executions>
                <execution>
                    <phase>compile</phase>
                    <goals>
                        <goal>macker</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

这是一个示例 macker-rules.xml 示例文件:(将其放在与 pom 相同的级别.xml)

<?xml version="1.0"?>
<macker>

    <ruleset name="Layering rules">
        <var name="base" value="org.example" />

        <pattern name="appl" class="${base}.**" />
        <pattern name="common" class="${base}.common.**" />
        <pattern name="persistence" class="${base}.persistence.**" />
        <pattern name="business" class="${base}.business.**" />
        <pattern name="web" class="${base}.web.**" />

        <!-- =============================================================== -->
        <!-- Common -->
        <!-- =============================================================== -->
        <access-rule>
            <message>zugriff auf common; von überall gestattet</message>
            <deny>
                <to pattern="common" />
                <allow>
                    <from>
                        <include pattern="appl" />
                    </from>
                </allow>
            </deny>
        </access-rule>

        <!-- =============================================================== -->
        <!-- Persistence -->
        <!-- =============================================================== -->
        <access-rule>
            <message>zugriff auf persistence; von web und business gestattet</message>
            <deny>
                <to pattern="persistence" />
                <allow>
                    <from>
                        <include pattern="persistence" />
                        <include pattern="web" />
                        <include pattern="business" />
                    </from>
                </allow>
            </deny>
        </access-rule>

        <!-- =============================================================== -->
        <!-- Business -->
        <!-- =============================================================== -->
        <access-rule>
            <message>zugriff auf business; nur von web gestattet</message>
            <deny>
                <to pattern="business" />
                <allow>
                    <from>
                        <include pattern="business" />
                        <include pattern="web" />
                    </from>
                </allow>
            </deny>
        </access-rule>

        <!-- =============================================================== -->
        <!-- Web -->
        <!-- =============================================================== -->
        <access-rule>
            <message>zugriff auf web; von nirgends gestattet</message>
            <deny>
                <to pattern="web" />
                <allow>
                    <from>
                        <include pattern="web" />
                    </from>
                </allow>
            </deny>
        </access-rule>

        <!-- =============================================================== -->
        <!-- Libraries gebunden an ein spezifisches Modul -->
        <!-- =============================================================== -->
        <access-rule>
            <message>nur in web erlaubt</message>
            <deny>
                <to>
                    <include class="javax.faces.**" />
                    <include class="javax.servlet.**" />
                    <include class="javax.ws.*" />
                    <include class="javax.enterprise.*" />
                </to>
                <allow>
                    <from pattern="web" />
                </allow>
            </deny>
        </access-rule>

        <access-rule>
            <message>nur in business und persistence erlaubt</message>
            <deny>
                <to>
                    <include class="javax.ejb.**" />
                    <include class="java.sql.**" />
                    <include class="javax.sql.**" />
                    <include class="javax.persistence.**" />
                </to>
                <allow>
                    <from>
                        <include pattern="business" />
                        <include pattern="persistence" />
                    </from>
                </allow>
            </deny>
        </access-rule>

    </ruleset>

</macker>

在一个简单的多模块maven项目中,只需将macker规则.xml放在一个中心位置,并指向存储它的目录。然后,您需要在父 pom 中配置插件.xml

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>de.andrena.tools.macker</groupId>
                <artifactId>macker-maven-plugin</artifactId>
                <version>1.0.2</version>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>macker</goal>
                        </goals>
                        <configuration>
                            <rulesDirectory>../</rulesDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

答案 2

如果我是你,我会做以下步骤:


推荐