All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.dddplus.ArchitectureEnforcer Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
/*
 * Copyright DDDplus Authors.
 *
 * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
 */
package io.github.dddplus;

import com.tngtech.archunit.core.domain.JavaModifier;
import com.tngtech.archunit.lang.ArchRule;
import io.github.dddplus.annotation.*;
import io.github.dddplus.ext.IDomainExtension;
import io.github.dddplus.ext.IIdentityResolver;
import io.github.dddplus.model.IDomainModel;
import io.github.dddplus.model.IDomainModelCreator;
import io.github.dddplus.model.IDomainService;
import io.github.dddplus.runtime.BaseDomainAbility;
import io.github.dddplus.specification.ISpecification;
import io.github.dddplus.step.IDomainStep;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

import java.lang.annotation.Target;
import java.util.LinkedList;
import java.util.List;

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.*;
import static com.tngtech.archunit.library.Architectures.layeredArchitecture;
import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS;
import static com.tngtech.archunit.library.GeneralCodingRules.NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING;
import static com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices;

/**
 * 架构守护神规则库,based upon ArchUnit.
 * 

*

DDDplus框架的架构守护神,为架构演进保驾护航,拒绝架构腐化.

*

同时,也为本框架提供了静态检查机制(配合单元测试使用),杜绝线上出现不合规范的使用.

*

https://www.archunit.org/motivation

*

*

 *  _      xxxx      _
 * /_;-.__ / _\  _.-;_\
 * `-._`'`_/'`.-'
 *     `\   /`
 *      |  /
 *     /-.(
 *     \_._\
 *      \ \`;
 *       > |/
 *      / //
 *      |//
 *      \(\
 *       ``
 * 
*/ public class ArchitectureEnforcer { private ArchitectureEnforcer() { } /** * 业务中台架构的所有规则. */ public static final List requiredRules = new LinkedList<>(); public static final ArchRule serviceRule() { return classes() .that().haveNameMatching(".*Service") .should().implement(IDomainService.class) .andShould().beAnnotatedWith(DomainService.class) .as("Service必须是domain service,不能用于其他场景"); } public static final ArchRule partnerDependencyRule() { return noClasses() .that().resideInAPackage("..bp..") .should().dependOnClassesThat().resideInAPackage("..domain..") .as("前台垂直业务包不能依赖domain包,必须依赖spec包"); } public static final ArchRule abilityRule() { return classes() .that().haveNameMatching(".*Ability") .should().beAssignableTo(BaseDomainAbility.class) .andShould().beAnnotatedWith(DomainAbility.class) .as("ability必须继承BaseDomainAbility,并且加@DomainAbility"); } public static final ArchRule specificationRule() { return classes() .that().implement(ISpecification.class) .should().beAnnotatedWith(Specification.class) .as("ISpecification rule"); } public static final ArchRule partnerRule() { return classes() .that().haveNameMatching(".*Partner") .should().beAnnotatedWith(Partner.class) .as("Partner使用规范"); } public static final ArchRule noActivityClassAllowed() { return noClasses() .should().haveNameMatching(".*Activity") .as("Activity必须定义成Step"); } public static final ArchRule activityRule() { return classes() .that().haveSimpleNameEndingWith("Step") .and().haveModifier(JavaModifier.ABSTRACT) .should().implement(IDomainStep.class) .as("Activity使用规范"); } public static final ArchRule domainStepRule() { return classes() .that().implement(IDomainStep.class) .and().doNotHaveModifier(JavaModifier.ABSTRACT) // 排除Activity .should().haveSimpleNameEndingWith("Step") .andShould().beAnnotatedWith(Step.class) .as("领域步骤的使用规范"); } public static final ArchRule patternRule() { return classes() .that().haveNameMatching(".*Pattern") .and().doNotHaveModifier(JavaModifier.ABSTRACT) .should().beAssignableTo(IIdentityResolver.class) .andShould().beAnnotatedWith(Pattern.class) .as("Pattern的使用规范"); } public static final ArchRule extensionRule() { return classes() .that().areAssignableTo(IDomainExtension.class) .and().areNotInterfaces() .and().haveNameNotMatching(".Default*") // 默认的扩展点实现可以不使用 @Extension .should().haveNameMatching(".*Ext") .andShould().beAnnotatedWith(Extension.class) .as("扩展点实现的规范"); } public static final ArchRule loggers_should_be_private_static_final() { return fields() .that().haveRawType(Logger.class) .should().bePrivate() .andShould().beStatic() .andShould().beFinal() .because("by convention"); } public static final ArchRule domainModelRule() { return classes() .that().implement(IDomainModel.class) .should().haveOnlyPrivateConstructors() .as("DomainModel不能直接new"); } public static final ArchRule creatorRule() { return classes() .that().haveNameMatching(".*Creator") .should().implement(IDomainModelCreator.class) .as("Creator rule"); } /** * 所有接口名称必须以'I'开头,除了Dao/Manager以及对外的Api. */ public static final ArchRule optionalInterfaceNameStartsWithI() { return classes() .that().areInterfaces() .and().areNotAnnotatedWith(Target.class) // 把注解本身排除掉 .and().haveNameNotMatching(".*Dao") .and().haveNameNotMatching(".*Manager") .and().haveNameNotMatching(".*Api") .and().haveNameNotMatching(".*Group") // 排除JSR303 group interface .should().haveSimpleNameStartingWith("I") .as("接口名称必须以I开头"); } public static final ArchRule controllers_should_only_use_their_own_slice() { return slices() .matching("..controller.(*)..").namingSlices("Controller $1") .as("Controllers") .should().notDependOnEachOther(); } public static final ArchRule repositoryRule() { return classes() .that().haveNameMatching(".*Repository") .and().areNotInterfaces() .should().beAnnotatedWith(Repository.class) .as("Repository必须用@Repository注解"); } public static final ArchRule aclRule() { return classes() .that().haveNameMatching(".*Acl") .and().areNotInterfaces() .should().resideInAPackage("..acl..") .andShould().beAnnotatedWith(Component.class) .as("ACL类的使用规范"); } public static final ArchRule optionalDddLayerRule() { return layeredArchitecture() .optionalLayer("Application").definedBy("..app..") .optionalLayer("Domain").definedBy("..domain..") .optionalLayer("Infrastructure").definedBy("..infra") .whereLayer("Application").mayNotBeAccessedByAnyLayer() .whereLayer("Domain").mayOnlyBeAccessedByLayers("Application", "Infrastructure") .whereLayer("Infrastructure").mayOnlyBeAccessedByLayers("Application") .as("DDD分层架构规范"); } static { // 不允许使用System.out/System.in/System.err,printStackTrace requiredRules.add(NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS); // 不允许使用java.util.logging requiredRules.add(NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING); requiredRules.add(loggers_should_be_private_static_final()); // DDD框架的使用规范 requiredRules.add(repositoryRule()); requiredRules.add(creatorRule()); requiredRules.add(partnerDependencyRule()); requiredRules.add(domainModelRule()); requiredRules.add(specificationRule()); requiredRules.add(serviceRule()); requiredRules.add(noActivityClassAllowed()); requiredRules.add(activityRule()); requiredRules.add(aclRule()); requiredRules.add(patternRule()); requiredRules.add(abilityRule()); requiredRules.add(partnerRule()); requiredRules.add(domainStepRule()); requiredRules.add(extensionRule()); requiredRules.add(controllers_should_only_use_their_own_slice()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy