自定义Starter:

  Starter会把所有用到的依赖都给包含进来,避免了开发者自己去引入依赖所带来的麻烦。Starter 提供了一种开箱即用的理念,其中核心就是springboot的自动配置原理相关,调用相关的注解实现条件判断,进而进行Bean的注入管理。

  基于SpringBoot自动配置原理的学习,现在我们来实现一下自定义starter。我们假设有一个格式化的,暂定两个实现,一个是Object-> String,一个是Object->JSON.

1.新建一个maven工程  format-spring-boot-starter,这里的命名在SpringBoot官网有建议:For example, assume that you are creating a starter for "acme" and that you name the auto-configure module acme-spring-boot-autoconfigure and the starter acme-spring-boot-starter. If you only have one module that combines the two, name it acme-spring-boot-starter. pom文件如下:

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1..RELEASE</version>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.</version>
<optional>true</optional><!--可选-->
</dependency>
   <!--支持ConfigurationProperties-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.1..RELEASE</version>
<optional>true</optional>
</dependency>
</dependencies>

2.构建格式化接口并且定义实现,咱们这里想实现动态注入的想过,定义两个实现以做对比:

public interface FormatProcessor {
//定义一个格式化的方法
<T> String format(T obj);
}
//实现1 JSON
public class JsonFormatProcessor implements FormatProcessor{
@Override
public <T> String format(T obj) {
return "JsonFormatProcessor:"+ JSON.toJSONString(obj);
}
}
//实现2 String
public class StringFormatProcessor implements FormatProcessor{ @Override
public <T> String format(T obj) {
return "StringFormatProcessor:"+Objects.toString(obj);
}
}

3.这里我们需要把这两个类根据  Conditional 注解动态注入到Spring 容器中,在springboot自动配置中我们说到有个 metadata 文件可以做过滤,而这里的 ConditionalOnClass 是一样的,只是方式不一样:

@Configuration
public class FormatAutoConfiguration {
//metadata-auto....
@ConditionalOnMissingClass("com.alibaba.fastjson.JSON")
@Bean
@Primary
public FormatProcessor stringFormat(){
return new StringFormatProcessor();
} @ConditionalOnClass(name = "com.alibaba.fastjson.JSON")
@Bean
public FormatProcessor jsonFormat(){
return new JsonFormatProcessor();
} }

4.我们这里参照着  jdbcTemplate 的模板来实现我们这个需求:

public class HelloFormatTemplate {

    private FormatProcessor formatProcessor;public HelloFormatTemplate(FormatProcessor formatProcessor) {this.formatProcessor = formatProcessor;
}
   //定义一个格式化方法,具体的实现由FormatProcessor实现类实现
public <T> String doFormat(T obj){
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append("begin:Execute format").append("<br/>");
stringBuilder.append("Obj format result:").append(formatProcessor.format(obj)).append("<br/>");
return stringBuilder.toString(); }
}

5.然后我们需要动态的注入:

@Import(FormatAutoConfiguration.class)
@Configuration
public class HelloAutoConfiguration { @Bean
public HelloFormatTemplate helloFormatTemplate(FormatProcessor formatProcessor){
return new HelloFormatTemplate(formatProcessor);
}
}

6.接下去需要在classpath下的META-INF文件夹下创建一个文件 spring.factories:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.wuzz.starter.autoconfiguration.HelloAutoConfiguration

  然后将该工程打成Jar,然后我们需要做的是在我们需要用到这个Starter的boot项目重中导入该starter

1.导入starter,我们会看到有些starter里面是空的,其实他做的仅仅是依赖传递,这样容器中存在某个类,这个时候符合另外一个类的加载,也能起到开箱即用的效果:

<dependency>
<groupId>com.wuzz.starter</groupId>
<artifactId>format-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

2.定义一个实体类如下:

public class User {
private String name;
private int age;
   //省略 get set
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

3.我们写一个controller来测试效果:

@RestController
public class FormatController { @Autowired
HelloFormatTemplate helloFormatTemplate; @GetMapping("/format")
public String format(){
User user=new User();
user.setAge();
user.setName("wuzz-starter");
return helloFormatTemplate.doFormat(user);
}
}

  其他无需任何配置,我们直接启动该项目,通过  localhost:8080/format 来访问会看到以下效果:

  再来,我们导入以下依赖:

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.</version>
</dependency>

  重启项目再去访问:

  是不是很爽?这样子就实现了Starter的自定义,

SpringBoot外部配置:

  这个时候我们还存在另外一个问题没有解决,就类似于我们导入了Eureka的starter,那么这个时候我们可以在 application.properties 中可以配置很多的信息,这个就是springboot的外部配置,取决于注解 @ConfigurationProperties。

  我们是不是也能实现这样的效果呢?答案是当然咯,那么接下去我们就基于原来的工程进行再一次的改造。

1.增加我们自定义的Properties 类:

@ConfigurationProperties(prefix="wuzz.hello.format")
public class HelloProperties { private String appOwner; private Map<String,Object> info; public String getAppOwner() {
return appOwner;
} public void setAppOwner(String appOwner) {
this.appOwner = appOwner;
} public Map<String, Object> getInfo() {
return info;
} public void setInfo(Map<String, Object> info) {
this.info = info;
}
}

2.修改HelloTemplate 如下:

public class HelloFormatTemplate {

    private FormatProcessor formatProcessor;

    private HelloProperties helloProperties;

    public HelloFormatTemplate(HelloProperties helloProperties, FormatProcessor formatProcessor) {
this.helloProperties = helloProperties;
this.formatProcessor = formatProcessor;
} public <T> String doFormat(T obj) { StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("begin:Execute format").append("<br/>");
stringBuilder.append("HelloProperties:").append(helloProperties.getAppOwner()).append("<br/>")
.append(formatProcessor.format(helloProperties.getInfo())).append("<br/>");
stringBuilder.append("Obj format result:").append(formatProcessor.format(obj)).append("<br/>");
return stringBuilder.toString(); }
}

3.修改HelloAutoConfiguration如下:

@Import(FormatAutoConfiguration.class)
@EnableConfigurationProperties(HelloProperties.class)
@Configuration
public class HelloAutoConfiguration { @Bean
public HelloFormatTemplate helloFormatTemplate(HelloProperties helloProperties,FormatProcessor formatProcessor){
return new HelloFormatTemplate(helloProperties,formatProcessor);
}
}

然后我们重新打个包,再在需要依赖的那个工程中更新导入一下maven。然后我们在application.properties中就可以实现我们的配置:

  配置两条配置项:wuzz.hello.format.app-owner=wuzz ,wuzz.hello.format.info.app=starter-demo

  然后启动项目我们再次访问:

  效果非常的好,在我们需要自定义的封装一些自定义组件的时候就可以使用这个拓展啦。

最新文章

  1. SQL SERVER几种数据迁移/导出导入的实践
  2. 转 jdk1.5新特性 ConcurrentHashMap
  3. [python拾遗]列表
  4. golang执行linux命令
  5. Apache搭建多个站点方法详解
  6. javascript基础学习(十)
  7. 修改Servlet模板
  8. windows环境下搭建Cocos2d-X开发环境
  9. 【.Net Framework 体积大?】不安装.net framework 也能运行!?开篇叙述-1
  10. Scrum Meeting Alpha - 6
  11. Spring MVC框架下的第一个Hello World程序
  12. WinDbg调试 C# dmp
  13. 下载中间件--随机IP代理以及随机User_Agent
  14. python 数据可视化(matplotlib)
  15. 多线程tips(面试常用)
  16. js实现瀑布流以及加载效果
  17. Nowcoder 提高组练习赛-R1
  18. BZOJ2597 WC2007剪刀石头布(费用流)
  19. 1253 Dungeon Master
  20. python操作docx学习资料

热门文章

  1. 使用 python 开发 Web Service
  2. java面向对象3-继承(继承、抽象类、抽象接口)
  3. Ubuntu中linux虚拟机全屏
  4. 【Linux】CentOS6上redis安装
  5. IP地址(参考百度百科)
  6. Type.GetType反射的对象创建Activator.CreateInstance
  7. fiddler界面工具栏介绍(二)
  8. Python 爬虫十六式 - 第七式:正则的艺术
  9. 由于数据库 &#39;XXX&#39; 离线,无法打开该数据库。
  10. VSCode支持jsx自动补全