Springboot自定义starter解决统一项目规范

俗话说:“无规矩不成方圆”,在我们软件开发过程中也是这样的要求,特别是对大型项目必须制定诸多的开发规范,有的是通过文件制度的形式要求,有的是通过工程框架要求,我个人认为要好的贯彻执行只能靠工程框架约束,否则每个工程师对文件制度都有不同的认识,长此以往这些规范制度就形同虚设了,而且通过工程框架约束还能够通过一些检查工具自动校验,最大限度的降低了人为的偏差。
今天就不多说编码的规范了,这个已经是业界公认的标准了,今天要介绍的是对公司大型项目如何通过工程框架来实现统一的规范约束。

实现统一规范的方案

  1. 统一结构的工程脚手架
    这个是通过工程架构约束的基础能力,就如同盖大楼一样,主体结构是大楼的基本体现,要想快速有效的落实基础架构,工程脚手架是必须的第一步。这里推荐的脚手架结构是以项目为目标,功能为模块的两层结构,把每个模块通用的部分放到项目层面,每个模块本身只包含项目特有的结构。


    脚手架项目结构
  2. 以jar包封装一些统一的规范能力
    项目中要用的统一能力可以通过集中封装的方式集成到一些独立分发的jar包中提供给项目的其他工程使用,这样就把一些统一的规范集中管控,从而缩小了泛化的可能性,当然同时也抑制了工程的自由度,这个要根据项目的实际情况做一个平衡。Springboot提供了更好的方式来实现这个目标,就是starter,这个也是本文重点介绍的方式。
  3. 以微服务方式提供黑箱服务
    将项目中通用的能力以微服务方式提供,对其他模块的使用更加的隔离,微服务的优势和方法不在本文详述,如果感兴趣可以自行脑补。

自定义starter

Springboot通过starter方式提供了封装更为精准的独立服务能力,让使用方开箱即用。目前很多开源系统都提供了starter方式,这样大大降低了我们使用这些优秀开源系统的门槛,也极大提高了开发效率,那么我们项目自身是否也可以用这样的方式来实现一些通用功能呢?答案是肯定的,而且过程也非常的简单,让原先以jar包分发的方式更加的优雅和简单。
starter工程和其他的Springboot工程结构没有什么区别,下面就把一些特殊的要求罗列一下。

  1. 命名规范
    1.1 官方命名空间(Springboot旗下项目)
    前缀:spring-boot-starter-
    模式:spring-boot-starter-{模块名}
    举例:spring-boot-starter-web、spring-boot-starter-jdbc
    1.2 自定义命名空间(非Springboot项目)
    后缀:-spring-boot-starter
    模式:{模块}-spring-boot-starter
    举例:mybatis-spring-boot-starter
  2. 必须引入的依赖包
    starter模式和以前的jar包模式的区别是配置装配能力,也就是starter包可以自动从配置文件获取项目本身的配置参数,从而更灵活的适应项目个性,那么就必须依赖这个包。
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>
  1. 工程入口程序
    这个程序是取代普通Springboot工程的Application的,是配置获取、bean装配的入口。
@Slf4j
@Configuration
@EnableConfigurationProperties(BasicProperties.class)
@ConditionalOnClass(BasicService.class)
@ConditionalOnProperty(prefix = "myself.middle", value = "enabled", matchIfMissing = true)

public class BasicServiceAutoConfiguration {
    @Autowired
    private BasicProperties basicProperties;

    @Bean
    @ConditionalOnMissingBean(BasicService.class)
    public BasicService basicService(){
        log.info("中台服务-基础服务装配开始...");
        log.info("运行域:{}",basicProperties.getDomain());
        BasicService basicService=new BasicService();
        log.info("中台服务-基础服务装配完成。");
        return basicService;
    }
}

这里指明获取配置的类,需要实例化的bean等,这里装配的bean在使用端就可以通过@Autowired的方式直接使用了,这些注解的详细说明自行搜索,资料很多。
配置文件application.yml如下:

myself:
  middle:
    domain: bj.myself.middle
  1. 配置spring.factories,指明starter的主入口
    在resources目录下建META-INF目录,创建spinrg.factories文件,文件内容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.myself.platform.middle.BasicServiceAutoConfiguration

AOP方式统一服务日志

原先实现统一日志都是放到每个工程中以AOP方式实现,现在有了starter方式,就可以将公司的日志规范集中到这里来统一管理。

  1. 编写Aspect类
    该类的实现和原先的方式没有任何变化,直接放代码如下:
@Aspect
@Component
@Slf4j
public class WebLogAspect {
    @Pointcut("execution(public * com.myself.platform.middle..web.*.*(..))")
    public void webLog(){}

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 记录下请求内容
        log.info("开始服务:{}", request.getRequestURL().toString());
        log.info("客户端IP :{}" , request.getRemoteAddr());
        log.info("参数值 :{}",Arrays.toString(joinPoint.getArgs()));
    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求,返回内容
        log.info("返回值 : {}" , ret);
    }
}
  1. starter装载类添加AOP Bean方法
    AOP如果直接放置到Springboot工程中就可以直接生效,但是通过starter方式提供还得在装载类中Bean化,这点要特别注意,否则不会生效。
@Slf4j
@Configuration
@EnableConfigurationProperties(BasicProperties.class)
@ConditionalOnClass(BasicService.class)
@ConditionalOnProperty(prefix = "myself.middle", value = "enabled", matchIfMissing = true)

public class BasicServiceAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(WebLogAspect.class)
    public WebLogAspect webLogAspect(){
        log.info("中台服务-统一web AOP装配开始...");
        log.info("运行域:{}",basicProperties.getDomain());
        WebLogAspect webLogAspect=new WebLogAspect();
        log.info("中台服务-统一web AOP装配完成。");
        return webLogAspect;
    }
}

发布

经过以上步骤这个包含了AOP及统一功能的starter就开发完成了,执行mvn install就可以部署到本地maven仓库给其他项目使用了,如果要在全公司使用就通过mvn deploy部署到公司私有仓库。

实际执行效果

2019-12-12 17:29:13.736  INFO [user-base,,,] 1 --- [           main] c.s.p.m.BasicServiceAutoConfiguration    : 中台服务-统一web AOP装配开始...
2019-12-12 17:29:13.736  INFO [user-base,,,] 1 --- [           main] c.s.p.m.BasicServiceAutoConfiguration    : 运行域:http://bj.myself.com
2019-12-12 17:29:13.736  INFO [user-base,,,] 1 --- [           main] c.s.p.m.BasicServiceAutoConfiguration    : 中台服务-统一web AOP装配完成。

看到AOP已经Bean化了。

2019-12-13 09:58:15.007  INFO [user-base,1a66e1fde3654b29,dbaacc6e1b0dd547,true] 1 --- [nio-1010-exec-3] c.s.p.middle.service.WebLogAspect        : 开始服务:http://172.16.15.229:1010/readUserinfo
2019-12-13 09:58:15.008  INFO [user-base,1a66e1fde3654b29,dbaacc6e1b0dd547,true] 1 --- [nio-1010-exec-3] c.s.p.middle.service.WebLogAspect        : 客户端IP :172.16.15.229
2019-12-13 09:58:15.008  INFO [user-base,1a66e1fde3654b29,dbaacc6e1b0dd547,true] 1 --- [nio-1010-exec-3] c.s.p.middle.service.WebLogAspect        : 请求参数 :org.apache.catalina.util.ParameterMap@22597edd
2019-12-13 09:58:15.008  INFO [user-base,1a66e1fde3654b29,dbaacc6e1b0dd547,true] 1 --- [nio-1010-exec-3] c.s.p.middle.service.WebLogAspect        : 参数值 :[61d4b219-e4e5-4c29-9688-b6759e3e6427]
2019-12-13 09:58:15.072  INFO [user-base,1a66e1fde3654b29,dbaacc6e1b0dd547,true] 1 --- [nio-1010-exec-3] c.s.p.middle.service.WebLogAspect        : 返回值 : ResponseData(code=0, message=成功, data={"avatarUrl":"fgjfgjghj","userName":"57547457","userId":"61d4b219-e4e5-4c29-9688-b6759e3e6427","email":"fghjfgjgh"})

可以看到AOP的统一日志已经输出。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容