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问题。