你会写Spring Boot Starter吗

前面写了一篇AOP自定义注解实现接口请求日志记录,可以记录接口请求日志。但是代码与项目耦合度太高,其他项目也需要的话,不利于移植!此时我们就可以把它写成一个starter,需要时在pom文件中添加依赖就可以了。

创建maven项目

在使用spring-boot-starter,会发现,有的项目名称是 XX-spring-boot-starter,有的是
spring-boot-starter-XX,这个项目的名称有什么讲究呢?
从springboot官方文档摘录如下:

Do not start your module names with spring-boot, even if you use a different Maven groupId. We may offer official support for the thing you auto-configure in the future.As a rule of thumb, you should name a combined module after the starter.

从这段话可以看出spring-boot-starter命名的潜规则:

spring-boot-starter-XX是springboot官方的starter
XX-spring-boot-starter是第三方扩展的starter

创建名为aspectlog-spring-boot-starter的项目,pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.jiangchh</groupId>
    <artifactId>aspectlog-spring-boot-starter</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>1.8</java.version>
        <mybatis-plus.version>2.1.8</mybatis-plus.version>
        <mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- MyBatis plus增强和springboot的集成-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatisplus-spring-boot-starter</artifactId>
            <version>${mybatisplus-spring-boot-starter.version}</version>
        </dependency>
    </dependencies>
</project>

关于spring-boot-configuration-processor的说明,引自springBoot官方文档:

Spring Boot uses an annotation processor to collect the conditions on auto-configurations in a metadata file ( META-INF/spring-autoconfigure-metadata.properties ). If that file is present, it is used to eagerly filter auto-configurations that do not match, which will improve startup time. It is recommended to add the following dependency in a module that contains auto-configurations:org.springframework.bootspring-boot-autoconfigure-processortrue

简单说就是:写starter时,在pom中配置spring-boot-autoconfigure-processor,在编译时会自动收集配置类的条件,写到一个META-INF/spring-autoconfigure-metadata.properties中。

自动配置逻辑

各种condition

类型注解说明
Class Conditions类条件注解@ConditionalOnClass当前classpath下有指定类才加载
@ConditionalOnMissingClass当前classpath下无指定类才加载
Bean ConditionsBean条件注解@ConditionalOnBean当期容器内有指定bean才加载
@ConditionalOnMissingBean当期容器内无指定bean才加载
Property Conditions环境变量条件注解(含配置文件)@ConditionalOnPropertyprefix 前缀name 名称havingValue 用于匹配配置项值matchIfMissing 没找指定配置项时的默认值
ResourceConditions 资源条件注解@ConditionalOnResource有指定资源才加载
Web Application Conditionsweb条件注解@ConditionalOnWebApplication是web才加载
@ConditionalOnNotWebApplication不是web才加载
SpEL Expression Conditions@ConditionalOnExpression符合SpEL 表达式才加载
  1. 定义AspectLog注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AspectLog {
    /**
     * 接口描述
     */
    String desc() default "";
}
  1. 定义配置文件对应类

@ConfigurationProperties("aspectlog")
public class AspectLogProperties {

    private boolean enable;
    public boolean isEnable() {
        return enable;
    }
    public void setEnable(boolean enable) {
        this.enable = enable;
    }
}
  1. 定义自动配置类
@Aspect
@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
@Configuration
@ConditionalOnProperty(prefix = "aspect-log", name = "enable",matchIfMissing = true)
@EnableConfigurationProperties(AspectLogProperties.class)
public class AspectLogAutoConfiguration implements PriorityOrdered {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private SysOperateLogDao sysOperateLogDao;

    /*Logger logger = LoggerFactory.getLogger(LogAdvice.class);*/

    /**
     * 切入点
     */
    @Pointcut("@annotation(com.digihealth.icu.aspectLog.AspectLog)")
    public void logAop(){}

    /**
     * 环绕通知
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("logAop()")
    public Object arround(ProceedingJoinPoint joinPoint) throws Throwable {
        //请求开始时间戳
        long begin = System.currentTimeMillis();
        Date startTime = new Date();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        AspectLog aspectLog = method.getAnnotation(AspectLog.class);

        Object result = joinPoint.proceed();
        //请求结束时间戳
        long end = System.currentTimeMillis();
        //结束时间
        Date endTime = new Date();

        SysOperateLog sysOperateLog = new SysOperateLog();
        sysOperateLog.setId(GenerateSequenceUtil.generateSequenceNo())
                .setUrl(request.getRequestURL().toString())
                .setTpye(request.getMethod())
                .setMethod(signature.getDeclaringTypeName()+"."+signature.getName())
                .setIp(request.getRemoteAddr())
                //.setInParam(JSON.toJSONString(joinPoint.getArgs()))
                //.setOutParam(JSON.toJSONString(result))
                .setStartTime(startTime)
                .setTimeConsum(Long.toString(end-begin))
                .setEndTime(endTime)
                .setDescription(aspectLog.desc());
        sysOperateLogDao.insert(sysOperateLog);
        return result;
    }
    @Override
    public int getOrder() {
        //保证事务等切面先执行
        return Integer.MAX_VALUE;
    }
}

配置类简要说明:
@ConditionalOnProperty(prefix = “aspect-log”, name = “enable”,matchIfMissing = true)
prefix:配置属性名称的前缀
name:数组,配置属性完整名称或部分名称,可与prefix组合使用,组成完整的配置属性名称,与value不可同时使用
matchIfMissing:缺少该配置属性时是否可以加载。如果为true,没有该配置属性时也会正常加载;反之则不会生效

  1. META-INF/spring.factories
    META-INF/spring.factories是spring的工厂机制,在这个文件中定义的类,都会被自动加载。多个配置使用逗号分割,换行用\
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.digihealth.icu.aspectLog.AspectLogAutoConfiguration

在这里插入图片描述

  1. 打包测试
    在IDEA中,进行mvn intall
    打包完成后,在其他项目中的pom中引入进行测试
    源码地址
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值