SpringBoot开发自己的Starter

SpringBoot starter机制

SpringBoot中的starter是一种非常重要的机制,能够抛弃以前繁杂的配置,将其统一集成进starter,应用者只需要在maven中引入starter依赖,SpringBoot就能自动扫描到要加载的信息并启动相应的默认配置。starter让我们摆脱了各种依赖库的处理,需要配置各种信息的困扰。SpringBoot会自动通过classpath路径下的类发现需要的Bean,并注册进IOC容器。SpringBoot提供了针对日常企业应用研发各种场景的spring-boot-starter依赖模块。所有这些依赖模块都遵循着约定成俗的默认配置,并允许我们调整这些配置,即遵循“约定大于配置”的理念。

自定义starter的好处

在我们公司有很多的项目,经常会出现很多的相同功能,比如系统中记录日志,用户统一登录模块;我们一般都是把代码复制过来复制过去的,非常的麻烦。如果可以将这些可独立于业务代码之外的功配置模块封装成一个starter,使用的时候只通过pom.xml中引用依赖即可,让SpringBoot为我们完成自动装配。

自定义starter的命名规则

SpringBoot提供的starter以spring-boot-starter-xxx的方式命名的。官方建议自定义的starter使用xxx-spring-boot-starter命名规则。以区分SpringBoot生态提供的starter。


SpringBoot开发自己的Starter

来自官方文档



接下来实现一个自定义的starter,这里以 日志为例(通过AOP记录所有接口的执行时间)。

  • 编写一个注解类,用于Controller上的方法,只有在接口上写了该注解才会被aop拦截
@Documented @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface SystemLog { 	 	/** 	 * <p>操作说明</p> 	 * @return 	 */ 	String value() default "" ; 	 }
  • 编写我们的拦截程序
public class SystemAroundOperator implements MethodInterceptor {  	private static final Logger logger = LoggerFactory.getLogger(SystemAroundOperator.class);  	@Override 	public Object invoke(MethodInvocation invocation) throws Throwable { 		// 开始执行时间 		long start = System.currentTimeMillis(); 		Method method = invocation.getMethod() ; 		SystemLog annoLog = null ; 		if (method.isAnnotationPresent(SystemLog.class)) { 			annoLog = method.getAnnotation(SystemLog.class) ; 			String value = annoLog.value() ; 			try { 				Object result = invocation.proceed() ; 				// 方法执行时间 				Long execTime = System.currentTimeMillis() - start ; 				logger.info("{}, 业务执行时间:{} ms", value, execTime) ; 				return result ; 			} catch (Throwable t) { 				Long execTime = System.currentTimeMillis() - start ; 				logger.info("{}, 业务执行时间:{} ms,发生异常信息:{}", value, execTime, t.getMessage()) ; 				throw t ; 			} 		} 		return invocation.proceed(); 	}  }

注意:我们一般都是通过如下方式定义我们的切面程序:


SpringBoot开发自己的Starter

由于这里我们要能动态的配置切入点,所以这里我们只能通过这种方式来。@Pointcut("${...}")是不支持这样写的,所以没有办法。

  • 属性配置类
@ConfigurationProperties(prefix = "logs") public class LogsProperties { 	/** 	 * 	切入点定义<br/> 	 * 	 示例:execution(public * com.pack.controller.*.*(..)) 	 */ 	private String pointcut ; 	/** 	 * 	是否开启日志功能 	 */ 	private boolean enabled = true ; 	 	public String getPointcut() { 		return pointcut; 	} 	public void setPointcut(String pointcut) { 		this.pointcut = pointcut; 	} 	public boolean isEnabled() { 		return enabled; 	} 	public void setEnabled(boolean enabled) { 		this.enabled = enabled; 	} 	 }
  • 自动装配类配置
@Configuration @EnableConfigurationProperties(LogsProperties.class) @ConditionalOnProperty(prefix = "logs", name = "enabled", havingValue = "true") @EnableAspectJAutoProxy public class LogsAutoConfiguration { 	 	private static final Logger logger = LoggerFactory.getLogger(LogsAutoConfiguration.class) ; 	 	@Resource 	private LogsProperties logsProperties ; 	 	@Bean 	public AspectJExpressionPointcutAdvisor logAdvisor() { 		AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor() ; 		logger.info("执行表达式:{}", logsProperties.getPointcut()) ; 		advisor.setExpression(logsProperties.getPointcut()) ; 		advisor.setAdvice(new SystemAroundOperator()) ; 		return advisor ; 	} 	 }

这里最好加上@EnableAspectJAutoProxy注解,有可能在你的环境中没有开启AOP动态代理呢(为的是以防万一)。

@ConditionalOnProperty(prefix = "logs", name = "enabled", havingValue = "true")

该注解,自动配置以logs开头的配置,name为enabled的属性,这里就是:logs.enabled属性。havingValue意思是只有配置的logs.enabled=true的情况下才会自动装配。

  • 最重要的一步编写spring.factories文件

在classpath下新建文件夹:META-INF

然后在这文件夹下新建spring.factories文件,内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.pack.config.LogsAutoConfiguration

到此就结束了一个starter的完整开发流程,下面看看整体项目的一个结构:


SpringBoot开发自己的Starter

我这里的红XX不要紧,eclipse问题。


接下来我们执行mvn clean install将其安装到本地仓库。

执行完后在我本地仓库中如下:


SpringBoot开发自己的Starter

接下来测试:

新建一个springboot工程

pom.xml中引入我们的starter

<dependency> 			<groupId>com.pack</groupId> 			<artifactId>logs-spring-boot-starter</artifactId> 			<version>0.0.1</version> 		</dependency> 

编写测试的controller:

@RestController public class HttpsController { 	 	@GetMapping("/test") 	@SystemLog("开启HTTPS功能测试") 	public Object https() { 		return "success" ; 	} 	 }

application.yml配置:

logs:   pointcut: execution(public * com.pack.controller.*.*(..))   enabled: true

启动服务:


SpringBoot开发自己的Starter

这里已经可以看到我们配置的信息了

访问接口:http://localhost:8080/test ,控制台输出了执行时间:


SpringBoot开发自己的Starter

一切正常。

springboot
分享到:

您可能还会对下面的文章感兴趣: