在实际业务开发过程当中,有很多公共的功能。针对这些功能,可以自己开发公共的starter模块
命名
对于自己开发的starter模块,一般使用xxx-spring-boot-starter,而spring自己生态圈的starter,一般都是spring-boot-starter-xxx格式命名
maven依赖(pom.xml)
<parent>
<groupId>org.springframework.boot
</groupId>
<artifactId>spring-boot-starter-parent
</artifactId>
<version>2.3.4.RELEASE
</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8
</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot
</groupId>
<artifactId>spring-boot-configuration-processor
</artifactId>
<optional>true
</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot
</groupId>
<artifactId>spring-boot-starter
</artifactId>
</dependency>
</dependencies>
属性类
package com
.leewan
.vue
.starter
.properties
;
import org
.springframework
.boot
.context
.properties
.ConfigurationProperties
;
@ConfigurationProperties(prefix
= "leewan.vue")
public class LeewanVueProperties {
private String rootPath
;
public String
getRootPath() {
return rootPath
;
}
public void setRootPath(String rootPath
) {
this.rootPath
= rootPath
;
}
}
通过@ConfigurationProperties注解,注入属性
配置类(最核心)
package com
.leewan
.vue
.starter
.config
;
import com
.leewan
.vue
.starter
.condition
.ConditionalHasProperties
;
import com
.leewan
.vue
.starter
.controller
.LeewanPageController
;
import com
.leewan
.vue
.starter
.pageContext
.ClassPathPageContext
;
import com
.leewan
.vue
.starter
.pageContext
.FilePageContext
;
import com
.leewan
.vue
.starter
.pageContext
.PageContext
;
import com
.leewan
.vue
.starter
.properties
.LeewanVueProperties
;
import org
.springframework
.beans
.BeansException
;
import org
.springframework
.beans
.factory
.annotation
.Autowired
;
import org
.springframework
.boot
.context
.properties
.EnableConfigurationProperties
;
import org
.springframework
.context
.ApplicationContext
;
import org
.springframework
.context
.ApplicationContextAware
;
import org
.springframework
.context
.annotation
.Bean
;
import org
.springframework
.context
.annotation
.Configuration
;
import org
.springframework
.util
.ResourceUtils
;
import org
.springframework
.web
.servlet
.mvc
.method
.annotation
.RequestMappingHandlerMapping
;
import java
.lang
.reflect
.Method
;
import java
.net
.URL
;
@Configuration
@EnableConfigurationProperties(LeewanVueProperties
.class)
@ConditionalHasProperties(propertyName
= "leewan.vue.root-path")
public class LeewanVueConfiguration {
@Autowired
private LeewanVueProperties properties
;
@Bean
public PageContext
pageContext() {
String rootPath
= properties
.getRootPath();
if(rootPath
.startsWith(ResourceUtils
.CLASSPATH_URL_PREFIX
)) {
String path
= rootPath
.substring(ResourceUtils
.CLASSPATH_URL_PREFIX
.length());
URL url
= Thread
.currentThread().getContextClassLoader().getResource(path
);
if(ResourceUtils
.isJarURL(url
)) {
return new ClassPathPageContext(path
);
}else {
return new FilePageContext(rootPath
);
}
}else {
return new FilePageContext(rootPath
);
}
}
@Bean("leewanPageController")
public LeewanPageController
pageController(){
return new LeewanPageController();
}
@Bean
public ApplicationContextAware
aware(){
return new ApplicationContextAware() {
@Override
public void setApplicationContext(ApplicationContext application
) throws BeansException
{
RequestMappingHandlerMapping handlerMapping
= application
.getBean(RequestMappingHandlerMapping
.class);
try {
Method method
=handlerMapping
.getClass().getSuperclass().getSuperclass().
getDeclaredMethod("detectHandlerMethods",Object
.class);
method
.setAccessible(true);
method
.invoke(handlerMapping
, "leewanPageController");
} catch (Exception e
) {
e
.printStackTrace();
}
}
};
}
}
@EnableConfigurationProperties(LeewanVueProperties
.class)
表示开启LeewanVueProperties配置对象,否则无法注入LeewanVueProperties对象
后续使用IDE(如idea,eclipse)编辑yml文件时,会根据LeewanVueProperties进行自动提示
条件注解
有些starter虽然引入,但实际运行过程中 需要满足一些特定条件才会运行。所以还需要条件注解来进行判断。springboot自带了很多条件注解,如@ConditionalOnProperty、@ConditionalOnBean等。
但是对于一些比较复杂的业务场景,使用spring自带的条件注解无法满足需求时,我们还可以自定义注解。 自定义注解一般需要两个类,一是注解,一是具体的条件匹配实现类
注解类
package com
.leewan
.vue
.starter
.condition
;
import org
.springframework
.context
.annotation
.Conditional
;
@Conditional(HasPropertiesCondition
.class)
public @
interface ConditionalHasProperties {
String
propertyName() default "";
}
条件匹配实现类
需要实现org.springframework.context.annotation.Condition类, 通过AnnotatedTypeMetadata可以获取注解类里的一些配置 通过conditionContext可以获取上下文一些配置参数
package com
.leewan
.vue
.starter
.condition
;
import org
.springframework
.context
.annotation
.Condition
;
import org
.springframework
.context
.annotation
.ConditionContext
;
import org
.springframework
.core
.type
.AnnotatedTypeMetadata
;
import org
.springframework
.util
.StringUtils
;
import java
.util
.Map
;
public class HasPropertiesCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext
, AnnotatedTypeMetadata annotatedTypeMetadata
) {
Map
<String, Object> annotationAttributes
= annotatedTypeMetadata
.getAnnotationAttributes(ConditionalHasProperties
.class.getName());
String propertyName
= (String
) annotationAttributes
.get("propertyName");
String property
= conditionContext
.getEnvironment().getProperty(propertyName
);
if(StringUtils
.hasText(property
)){
return true;
}
return false;
}
}
配置文件
最后需要告诉spring 你的这个starter的自动配置类是哪个。通过配置文件进行配置 1、resources目录下 新建META-INF目录 2、新建文件spring.factories 3、在spring.factories中
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.leewan.vue.starter.config.LeewanVueConfiguration
一切搞定