原因和目标:
一般一个正常的企业级的java项目不仅仅是包含java基础的包,而是会有一些额外的东西来构成整个项目的完整,例如公司自己工具包,CI/CD集成的相关配置,测试相关的配置,部署相关的配置等.往往创建一个符合公司规范的项目需要花费很多的时间.同时还有一个难题就是选择合适引用包的版本.也就是java工程的包管理。<br /> 为了解决上述的问题,现修改spring initializr的工程,想做到目标。
- 能够集成到idea集成开发工具里,自由选择spring 提供的相关依赖。并且能把自己的定义的包和依赖放入可选择的列表。
- 能够随时更新相关的模板文件的结构和内容,并且通过选择分支来勾选适用于不同场景的模板文件
准备工作以及方法论:
为了完成上述的功能,需要提前做好的准备工作以及方法论.
- 认真查看spring initializr 的源码,去掉其中我们不需要模块和功能,精简化代码,保留核心功能
- 构思如何在spring initalizr 构建项目包的过程中结合我们自己的东西。
- 保证我们的东西和spring initalizr 项目的本身的东西不发生冲突,使得项目能正常工作
- 保证项目的灵活度和可配置性,思考是否能运用到java工程以外的项目
Spring initalizr 源码解读
spring initalizr 项目构成
其中的核心主要是两个模块
1.initializr-metadate:用于定义项目各个方面的元数据结构
2.initializr-generator:核心项目生成库
initializr-generator源码
首先我们来看initalizr-generator的源码
查看pom.xml该模块的主要依赖
从上面可以看出项目结构很简单
ProjectGenerator类
是为项目生成的主入口点。一个 ProjectGenerator
需要ProjectDescription
定义一个特定的项目生成和实现的ProjectAssetGenerator
,负责根据可用人选产生的资产。
所以我们先看ProjectGenerator的源码
ProjectGenerator的源码
public class ProjectGenerator {
private final Consumer<ProjectGenerationContext> contextConsumer;
private final Supplier<? extends ProjectGenerationContext> contextFactory;
public ProjectGenerator(Consumer<ProjectGenerationContext> contextConsumer,
Supplier<? extends ProjectGenerationContext> contextFactory) {
this.contextConsumer = contextConsumer;
this.contextFactory = contextFactory;
}
public ProjectGenerator(Consumer<ProjectGenerationContext> contextConsumer) {
this(contextConsumer, defaultContextFactory());
}
private static Supplier<ProjectGenerationContext> defaultContextFactory() {
return () -> {
ProjectGenerationContext context = new ProjectGenerationContext();
context.setAllowBeanDefinitionOverriding(false);
return context;
};
}
public <T> T generate(ProjectDescription description, ProjectAssetGenerator<T> projectAssetGenerator)
throws ProjectGenerationException {
try (ProjectGenerationContext context = this.contextFactory.get()) {
context.registerBean(ProjectDescription.class, resolve(description, context));
context.register(CoreConfiguration.class);
this.contextConsumer.accept(context);
context.refresh();
try {
return projectAssetGenerator.generate(context);
}
catch (IOException ex) {
throw new ProjectGenerationException("Failed to generate project", ex);
}
}
}
private Supplier<ProjectDescription> resolve(ProjectDescription description, ProjectGenerationContext context) {
return () -> {
if (description instanceof MutableProjectDescription) {
MutableProjectDescription mutableDescription = (MutableProjectDescription) description;
ProjectDescriptionDiffFactory diffFactory = context.getBeanProvider(ProjectDescriptionDiffFactory.class)
.getIfAvailable(DefaultProjectDescriptionDiffFactory::new);
// Create the diff here so that it takes a copy of the description
// immediately
ProjectDescriptionDiff diff = diffFactory.create(mutableDescription);
context.registerBean(ProjectDescriptionDiff.class, () -> diff);
context.getBeanProvider(ProjectDescriptionCustomizer.class).orderedStream()
.forEach((customizer) -> customizer.customize(mutableDescription));
}
return description;
};
}
@Configuration
@Import(ProjectGenerationImportSelector.class)
static class CoreConfiguration {
}
static class ProjectGenerationImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
List<String> factories = SpringFactoriesLoader.loadFactoryNames(ProjectGenerationConfiguration.class,
getClass().getClassLoader());
return factories.toArray(new String[0]);
}
}
}
可以看到其中的generate方法向Project Generate的上下文中注册了ProjectDescription,并且返回了ProjectAssetGenerator的实例。
接下来看看ProjectDesciption类,可以看到里面基本上是一个java项目相关的描述,它是一个接口。
ProjectDesciption的源码
public interface ProjectDescription {
default ProjectDescription createCopy() {
throw new UnsupportedOperationException();
}
Map<String, Dependency> getRequestedDependencies();
Version getPlatformVersion();
BuildSystem getBuildSystem();
Packaging getPackaging();
Language getLanguage();
String getGroupId();
String getArtifactId();
String getVersion();
String getName();
String getDescription();
String getApplicationName();
String getPackageName();
String getBaseDirectory();
}
它的实现类是MuableProjectDesciption 是一个典型的POJO类
可以看到在向ProjectGenerator上下文注册工程描述的时候,会调用resolve解析方法,这个方法作用是对比project
description 是否有改变,如果有改变,确定改变是正确的就注册改变后的项目描述
public <T> T generate(ProjectDescription description, ProjectAssetGenerator<T> projectAssetGenerator)
throws ProjectGenerationException {
try (ProjectGenerationContext context = this.contextFactory.get()) {
context.registerBean(ProjectDescription.class, resolve(description, context));
context.register(CoreConfiguration.class);
this.contextConsumer.accept(context);
context.refresh();
try {
return projectAssetGenerator.generate(context);
}
catch (IOException ex) {
throw new ProjectGenerationException("Failed to generate project", ex);
}
}
}
累了,缓一会儿