技术栈

  • Java
  • Go

程序员之禅

关于设计/架构

开源之路(藤原会)

Canal

Apache SkyWalking

Spring Cloud Tencent

APIJSON

Apache pulsar

公益表单管理系统

云教室在线支教

程序设计小case

实现一个基于maven的依赖检查工具

<dependencies>
    <dependency>
        <groupId>org.apache.maven</groupId>
        <artifactId>maven-model</artifactId>
        <version>3.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.maven</groupId>
        <artifactId>maven-plugin-api</artifactId>
        <version>3.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.maven</groupId>
        <artifactId>maven-core</artifactId>
        <version>3.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.maven</groupId>
        <artifactId>maven-model</artifactId>
        <version>3.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>3.2.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.maven.shared</groupId>
        <artifactId>maven-dependency-tree</artifactId>
        <version>3.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.maven.plugin-tools</groupId>
        <artifactId>maven-plugin-annotations</artifactId>
        <version>3.5.2</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-plugin-plugin</artifactId>
            <version>3.6.0</version>
        </plugin>
    </plugins>
</build>


@Mojo(name = "collect", requiresDependencyCollection = ResolutionScope.TEST, threadSafe = true)
public class CollectDependencyPlugin extends AbstractMojo {

    @Parameter(defaultValue = "${project}", readonly = true, required = true)
    private MavenProject project;
    @Parameter(defaultValue = "${session}", readonly = true, required = true)
    private MavenSession session;
    @Component(hint = "default")
    private DependencyCollectorBuilder dependencyCollectorBuilder;
    @Component(hint = "default")
    private DependencyGraphBuilder dependencyGraphBuilder;

    @Parameter(property = "verbose", defaultValue = "false")
    private boolean verbose;
    @Parameter(property = "skip", defaultValue = "false")
    private boolean skip;
    @Parameter(property = "outputType", defaultValue = "text")
    private String outputType;
    @Parameter(property = "tokens", defaultValue = "standard")
    private String tokens;

    @Parameter(property = "scope")
    private String scope;
    @Parameter(property = "includes")
    private String includes;
    @Parameter(property = "excludes")
    private String excludes;

    private DependencyNode rootNode;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        if (isSkip()) {
            getLog().info("Skipping plugin execution");
            return;
        }
        try {
            String dependencyTreeString;
            //String dependencyTreeStringOrigin;
            ArtifactFilter artifactFilter = createResolvingArtifactFilter();
            ProjectBuildingRequest buildingRequest =
                    new DefaultProjectBuildingRequest(session.getProjectBuildingRequest());
            buildingRequest.setProject(project);

            if (verbose) {
                rootNode = dependencyCollectorBuilder.collectDependencyGraph(buildingRequest, artifactFilter);
                dependencyTreeString = serializeDependencyTree(rootNode);
            } else {
                rootNode = dependencyGraphBuilder.buildDependencyGraph(buildingRequest, artifactFilter);
                dependencyTreeString = serializeDependencyTree(rootNode);
            }
            String[] dependenciesStr = dependencyTreeString.split("\r\n");
            if (dependenciesStr == null || dependenciesStr.length == 0) {
                throw new MojoFailureException("当前项目不存在第三方依赖");
            }
            List<Artifact> artifactList = parseToArtifact(dependenciesStr);
            getLog().info(project.getGroupId());
            getLog().info(project.getArtifactId());
            getLog().info(project.getVersion());
            getLog().info(project.getPackaging());
            getLog().info(artifactList.toString());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private String serializeDependencyTree(DependencyNode theRootNode) {
        StringWriter writer = new StringWriter();
        DependencyNodeVisitor visitor = getSerializingDependencyNodeVisitor(writer);
        visitor = new BuildingDependencyNodeVisitor(visitor);
        DependencyNodeFilter filter = createDependencyNodeFilter();
        if (filter != null) {
            CollectingDependencyNodeVisitor collectingVisitor = new CollectingDependencyNodeVisitor();
            DependencyNodeVisitor firstPassVisitor = new FilteringDependencyNodeVisitor(collectingVisitor, filter);
            theRootNode.accept(firstPassVisitor);
            DependencyNodeFilter secondPassFilter =
                    new AncestorOrSelfDependencyNodeFilter(collectingVisitor.getNodes());
            visitor = new FilteringDependencyNodeVisitor(visitor, secondPassFilter);
        }
        theRootNode.accept(visitor);
        return writer.toString();
    }

    public DependencyNodeVisitor getSerializingDependencyNodeVisitor(Writer writer) {
        if ("graphml".equals(outputType)) {
            return new GraphmlDependencyNodeVisitor(writer);
        } else if ("tgf".equals(outputType)) {
            return new TGFDependencyNodeVisitor(writer);
        } else if ("dot".equals(outputType)) {
            return new DOTDependencyNodeVisitor(writer);
        } else {
            return new SerializingDependencyNodeVisitor(writer, toGraphTokens(tokens));
        }
    }

    private DependencyNodeFilter createDependencyNodeFilter() {
        List<DependencyNodeFilter> filters = new ArrayList<>();
        if (includes != null) {
            List<String> patterns = Arrays.asList(includes.split(","));
            getLog().debug("+ Filtering dependency tree by artifact include patterns: " + patterns);
            ArtifactFilter artifactFilter = new StrictPatternIncludesArtifactFilter(patterns);
            filters.add(new ArtifactDependencyNodeFilter(artifactFilter));
        }

        if (excludes != null) {
            List<String> patterns = Arrays.asList(excludes.split(","));
            getLog().debug("+ Filtering dependency tree by artifact exclude patterns: " + patterns);
            ArtifactFilter artifactFilter = new StrictPatternExcludesArtifactFilter(patterns);
            filters.add(new ArtifactDependencyNodeFilter(artifactFilter));
        }
        return filters.isEmpty() ? null : new AndDependencyNodeFilter(filters);
    }

    private ArtifactFilter createResolvingArtifactFilter() {
        ArtifactFilter filter;
        if (scope != null) {
            getLog().debug("+ Resolving dependency tree for scope '" + scope + "'");
            filter = new ScopeArtifactFilter(scope);
        } else {
            filter = null;
        }
        return filter;
    }

    private SerializingDependencyNodeVisitor.GraphTokens toGraphTokens(String theTokens) {
        return new SerializingDependencyNodeVisitor.GraphTokens("", "","", "");
    }

    private List<Artifact> parseToArtifact(String[] dependencyGavStrs) {
        List<Artifact> artifactList = new ArrayList<>(dependencyGavStrs.length);
        for (String dependencyGavStr : dependencyGavStrs) {
            String[] gavInfo = dependencyGavStr.split(":");
            if (gavInfo == null) {
                continue;
            }
            if (gavInfo.length < 4) {
                getLog().error("不合法的依赖:" + dependencyGavStr);
            }
            //String groupId, String artifactId, String classifier, String extension, String version
            Artifact artifact = new DefaultArtifact(gavInfo[0], gavInfo[1], "", gavInfo[2], gavInfo[3]);
            artifactList.add(artifact);
        }
        return artifactList;
    }

    public boolean isSkip() {
        return skip;
    }
}

动态控制日志输出级别

@Plugin(
        name = "Log4j2DynamicLoggingFilter",
        category = "Core",
        elementType = "filter",
        printObject = true
)
public class Log4j2DynamicLoggingFilter extends AbstractFilter {

    private DynamicLoggingHelper helper;
    public Log4j2DynamicLoggingFilter() {
        helper = DynamicLoggingHelper.getInstance();
    }

    @Override
    public Result filter(LogEvent event) {
        return filter(event.getLoggerName(),event.getLevel());
    }

    @Override
    public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
        return filter(logger.getName(), level);
    }
    @Override
    public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
        return filter(logger.getName(), level);
    }
    @Override
    public Result filter(Logger logger, Level level, Marker marker, String msg, Object... params) {
        return filter(logger.getName(), level);
    }
    @Override
    public Result filter(Logger logger, Level level, Marker marker, String msg, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8) {
        return filter(logger.getName(), level);
    }
    @Override
    public Result filter(Logger logger, Level level, Marker marker, String msg, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7) {
        return filter(logger.getName(), level);
    }
    @Override
    public Result filter(Logger logger, Level level, Marker marker, String msg, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6) {
        return filter(logger.getName(), level);
    }
    @Override
    public Result filter(Logger logger, Level level, Marker marker, String msg, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5) {
        return filter(logger.getName(), level);
    }
    @Override
    public Result filter(Logger logger, Level level, Marker marker, String msg, Object p0, Object p1, Object p2, Object p3, Object p4) {
        return filter(logger.getName(), level);
    }
    @Override
    public Result filter(Logger logger, Level level, Marker marker, String msg, Object p0, Object p1, Object p2, Object p3) {
        return filter(logger.getName(), level);
    }
    @Override
    public Result filter(Logger logger, Level level, Marker marker, String msg, Object p0, Object p1, Object p2) {
        return filter(logger.getName(), level);
    }
    @Override
    public Result filter(Logger logger, Level level, Marker marker, String msg, Object p0, Object p1) {
        return filter(logger.getName(), level);
    }
    @Override
    public Result filter(Logger logger, Level level, Marker marker, String msg, Object p0) {
        return filter(logger.getName(), level);
    }
    @Override
    public Result filter(Logger logger, Level level, Marker marker, String msg, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8, Object p9) {
        return filter(logger.getName(), level);
    }

    /**
     *  核心拦截逻辑
     * */
    private Result filter(String loggerName, Level level) {
        ...
    }
}


@Slf4j
@Configuration
@ConditionalOnClass(value = {LoggerContext.class, EmbeddedServletContainerInitializedEvent.class})
@ConditionalOnMissingBean(LogbackDynamicAutoConfiguration.class)
public class Log4j2DynamicAutoConfiguration implements ApplicationListener<EmbeddedServletContainerInitializedEvent> {
    private DynamicLoggingHelper helper ;
    public Log4j2DynamicAutoConfiguration() {
        this.helper = DynamicLoggingHelper.getInstance();
    }
    @Override
    public void onApplicationEvent(EmbeddedServletContainerInitializedEvent contextRefreshedEvent) {
        if (!this.helper.isDynamicLoggingLevelFilterOff()) {
            LoggerContext context = (LoggerContext) LogManager.getContext(false);
            org.apache.logging.log4j.core.config.Configuration configuration = context.getConfiguration();
            configuration.addFilter(new Log4j2DynamicLoggingFilter());
            context.updateLoggers(configuration);
        }
    }
}


public class LogbackDynamicLoggingFilter extends TurboFilter {

    private DynamicLoggingHelper helper ;
    public LogbackDynamicLoggingFilter() {
        helper = DynamicLoggingHelper.getInstance();
    }

    @Override
    public FilterReply decide(Marker marker, Logger logger, Level level, String s, Object[] objects, Throwable throwable) {
        ...
    }
}

@Slf4j
@Configuration
@ConditionalOnClass(value = {LoggerContext.class, EmbeddedServletContainerInitializedEvent.class})
public class LogbackDynamicAutoConfiguration implements ApplicationListener<EmbeddedServletContainerInitializedEvent> {
    private DynamicLoggingHelper helper ;
    public LogbackDynamicAutoConfiguration() {
        this.helper = DynamicLoggingHelper.getInstance();
    }
    @Override
    public void onApplicationEvent(EmbeddedServletContainerInitializedEvent contextRefreshedEvent) {
        if (!helper.isDynamicLoggingLevelFilterOff()) {
            LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
            loggerContext.addTurboFilter(new LogbackDynamicLoggingFilter());
        }
    }
}

Redis双写


echo
23 声望0 粉丝

生命中最难的阶段,不是没人懂你,而是你不懂自己。


下一篇 »
Golang入门

引用和评论

0 条评论