如何自定义springboot starter,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
自定义 springboot starter
搞一个demo看看,demo实现了两个功能:
使用Aspectj方式的aop,来实现对某类函数参数监控;
定义一个自己的配置类,读取我们在yml或properties里面配置的参数,同时提供一个service,用来获取我们读取的结果。
这里是示例工程starter.
看了自动配置原理之后,应该知道META-INF/spring.facotires这个家伙是配置的重点了吧,我们很多个的东西都是在这个里头。因此,我们自己的stater当然也少不了这个配置文件,先贴个工程结构。
spring-boot-myaop-starter ├─ pom.xml ├─ spring-boot-myaop-starter.iml └─ src/main ├─ java └─ resources └─ META-INF └─ spring.factories
先按照正常工程把一些配置都配好,先来写一个AspectJ的。
package com.wt.myaop.aspect; @Aspect @Component public class MyAspect { @Pointcut("@annotation(myAnno)") public void myAspectPointCut(MyAopAnnotation myAnno) { } @Before("myAspectPointCut(myAnno)") public void performanceTrance2(JoinPoint joinPoint, MyAopAnnotation myAnno) throws Throwable { System.out.println("--------------myaop-starter args monitor start-----------------"); Object[] args = joinPoint.getArgs(); Class<?>[] types = myAnno.argTypes(); for (int i = 0; i < Math.min(args.length, types.length); i++) { System.out.println("type:" + types[i] + "<--->arg:" + args[i]); } System.out.println("--------------myaop-starter args monitor end-----------------"); } }
我们这里使用的是@Before,在这个方法里面获取到所有参数,然后将所有参数的类型和值都打印出来,方法前后输出日志,比较简单。
然后来看pointCut,这是一个基于注解的,这样其他项目引入这个starter的时候就可以直接以注解来使用,对其他项目不具有侵入性。所以,我们还需要定义一个注解。
package com.wt.myaop.anno; @Target(ElementType.METHOD) @Documented @Retention(RetentionPolicy.RUNTIME) public @interface MyAopAnnotation { Class<?>[] argTypes() default {}; }
注解里面有属性,用来定义方法参数的类型顺序,当然也可以不需要,放这里只是为了方便。
属性的读取我们需要用到一个springboot的注解@ConfigurationProperties.来看看这个配置类,为了缩短代码长度,都没有贴getter/setter方法哦。
package com.wt.myaop.config; @ConfigurationProperties(prefix = MyConfig.MY_PREFIX) public class MyConfig { public static final String MY_PREFIX = "myconfig"; /** * 不加该注解也能正常得到值 */ @NestedConfigurationProperty private UserConfig user; private String job; }
代码中我们定义了一个常量MY_PREFIX,这个是配置文件中的前缀,springboot会读取这个前缀的配置来注入到这个实体当中,当然,配置肯定不会是在我们这个starter项目中来配置,是我们实际使用的project中配置的哦!要不然我还不如直接写死,对吧,嘻嘻。
除了基本属性之外,还提供了一个实体属性,UserConfig。来看看这个东西吧。
package com.wt.myaop.config; public class UserConfig { private String username; private Integer age; private String sex; }
配置信息的接收实体有了,我们现在来定义一个service,这个service的作用就是注入这个实体,然后输出配置信息,以检查我们的配置生效了。service的接口就不贴了哈,只贴实现类了。
package com.wt.myaop.service; public class MyConfigServiceImpl implements MyConfigService { private final MyConfig myconfig; public MyConfigServiceImpl(MyConfig myConfig) { this.myconfig = myConfig; } @Override public void printMyConfig() { System.out.println(myConfig); } }
看构造方法和属性,构造方法注入了我们的配置,当然,我们如果需要使用这个service,我们就需要手动将这个配置注入进来,以确保service实例化时,myconfig不会为null,里面的方法很简单,仅仅打印了我们的配置类MyConfig。
starter像这样就算完了吗?当然没有,可以感受到以上这些其实都跟普通的project的配置没有太多差别,很简单。
回忆一下我们自动配置的核心是不是叫xxxAutoConfiguration的东西呢?spring.vactories中的哦!
好了,来吧,开始定义我们自己的AutoConfiguration。
package com.wt.myaop.autoconfig; @Configuration @ComponentScan({"com.wt.myaop.aspect"}) @AutoConfigureAfter(AopAutoConfiguration.class) @EnableConfigurationProperties(MyConfig.class) public class MyArgsMonitorAopAutoConfig { private MyConfig myConfig; public MyArgsMonitorAopAutoConfig(MyConfig myConfig) { this.myConfig = myConfig; } @Bean public MyConfigService getMyConfigService(){ return new MyConfigServiceImpl(myConfig); } }
我们现在来研究一下这个类都有什么。
@Configuration: 表明这个类是一个配置类; @ComponentScan: 指出需要扫描的包,可以看到上面扫描的包中包含了Aspect注解的配置,当然使用aop这部分是必不可少的; @AutoConfigureAfter: 指出当前类需要再某个自动配置完成之后才开始配置; @EnableConfigurationProperties: 为@ConfigurationProperties注解提供支持,什么意思呢; 解释一下这个,把@ConfigurationProperties标注的类(MyConfig)注册成bean,以支持依赖注入,本身这些类 是不会被注册成bean的,当然我们可以在配置类上加@Component注解。使用这个注解可以在我们需要某个配置类 注册成bean的时候,就使用,侵入性小,避免了配置类上加@Component注解。
从上面代码中可以看到我们的配置类MyConfig通过构造方法被注入到了MyArgsMonitorAopAutoConfig当中,而MyArgsMonitorAopAutoConfig是一个配置类,里面通过@Bean的方式配置了MyConfigService。
看起来很简答吧,实际上也很简单,autoConfiguration的配置类就好了,引入这个类,就相当于引入了一个Myconfig的配置类,和一个我们能够使用的MyConfigService。
自动配置的类有了,需要放到spring.factories中才能生效。
# META-INF/spring.factories org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.wt.myaop.autoconfig.MyArgsMonitorAopAutoConfig
这样starter部分就算是完成了。
Tips: 自动配置其实很简单,把需要的配置都放到一个叫做starter的工程里面,然后创建一个XxxAutoConfiguration的自动配置类,把需要的配置都放到这个类里面配置好。最后把这个自动配置类加到META-INF/spring.factories中就行了,是不是很容易,嘻嘻。
demo其实也是使用的之前分析源码那个工程,下面有地址。重点来配置和启动一下我们自己的starter。
这里是示例工程demo.
有了starter之后,使用mvn clean install命令将其jar安装到本地。
在demo工程中引入这个依赖。
<dependency> <groupId>com.wt.starter</groupId> <artifactId>spring-boot-myaop-starter</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
我们starter里面有个MyConfig的配置对吧,好了,现在我们可以在yml或者properties文件中来定义了。我这里用的是yml哈。
myconfig: job: programer user: username: wt age: 25 sex: real_man
注意我们的前缀是myconfig,下面的job和user都是实体类MyConfig的属性,因为user是个实体了类,因此下面也列出了它的属性username,age,sex.(可以去前面的MyConfig和UserConfig两个实体的属性进行对比)。
starter中除了上面的MyConfig之外,还有个aop监控参数的功能,我们马上把它用起来。
先定义一个service,接口就不贴了
@Service public class MyStarterServiceImpl implements MyStarterService { @Override @MyAopAnnotation(argTypes = {String.class}) public void helloStarter(String msg, Long currentTime) { System.out.println("----hello starter,msg = " + msg + ",currentTime = " + currentTime); } }
方法加上了注解MyAopAnnotation,为了被starter当中的aop拦截到。
再来定义一个controller用来测试。
@RestController @RequestMapping("/starter") public class MyStarterController { @Autowired private MyConfigService myConfigService; @Autowired private MyStarterService myStarterService; @RequestMapping("/test") public Object starter() { myConfigService.printMyConfig(); myStarterService.helloStarter("wt", System.currentTimeMillis()); return "success"; } }
注意区分一下,MyConfigService是我们starter里面的,MyStarterService是我们demo工程里面的。
现在启动工程,访问http://127.0.0.1:8080/starter/test试试!
来看看输出(复制了输出,没有使用截图):
MyConfig{user=UserConfig{username='wt', age=25, sex='real_man'}, job='programer'} ------------------myaop-starter args monitor start-------------------- type:class java.lang.String<--->arg:wt ------------------myaop-starter args monitor end-------------------- ----hello starter,msg = wt,currentTime = 1564472340205
第一行是 myConfigService.printMyConfig()的输出,他输出了我们的在yml中的配置,这个输出说明了我们的配置被成功赋值给MyConfig了。说明我们的config生效了。
第二行和第四行是starter当中aop部分@Before方法的前后输出,中间第三行输出了参数类型String和参数的值wt,因为我们注解上只指定了一个String.class,因此在这里没有把第二个参数也输出来,具体逻辑就去看starter当中aop的那个@Before的方法了。
最后一行是被加强的方法的输出,打印了msg和currentTime。
现在可以来想象一下springboot在yml或properties文件中的Datasource等配置咯!
看到这里starter部分就算结束了
看完上述内容,你们掌握如何自定义springboot starter的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。