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。
来自官方文档
接下来实现一个自定义的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(); 	}  }注意:我们一般都是通过如下方式定义我们的切面程序:
由于这里我们要能动态的配置切入点,所以这里我们只能通过这种方式来。@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的完整开发流程,下面看看整体项目的一个结构:
我这里的红XX不要紧,eclipse问题。
