1. Add automatic configuration dependencies to pom files:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency>
2. If a jar exists to configure it, the dependency needs to be added. Add httpclient here:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency>
3. Write default configuration classes:
package com.springboot.autoconfig; import org.springframework.boot.context.properties.ConfigurationProperties; //Configuration in application.properties will override the default values below @ConfigurationProperties(prefix = "spring.httpclient") public class HttpClientProperties { private Integer connectTimeOut = 1000; private Integer socketTimeOut = 10000; private String agent = "agent"; private Integer maxConnPerRoute = 10; private Integer maxConnTotaol = 50; public Integer getConnectTimeOut() { return connectTimeOut; } public void setConnectTimeOut(Integer connectTimeOut) { this.connectTimeOut = connectTimeOut; } public Integer getSocketTimeOut() { return socketTimeOut; } public void setSocketTimeOut(Integer socketTimeOut) { this.socketTimeOut = socketTimeOut; } public String getAgent() { return agent; } public void setAgent(String agent) { this.agent = agent; } public Integer getMaxConnPerRoute() { return maxConnPerRoute; } public void setMaxConnPerRoute(Integer maxConnPerRoute) { this.maxConnPerRoute = maxConnPerRoute; } public Integer getMaxConnTotaol() { return maxConnTotaol; } public void setMaxConnTotaol(Integer maxConnTotaol) { this.maxConnTotaol = maxConnTotaol; } }
4. Write configuration automatic configuration class. This class will read the default configuration class written before and create an instance of the default configuration without configuration:
package com.springboot.autoconfig; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClientBuilder; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.io.IOException; @Configuration//Note that this class is a Java configuration class @ConditionalOnClass({HttpClient.class})//Automatic configuration occurs when HttpClient exists @EnableConfigurationProperties(HttpClientProperties.class)//Read the default configuration public class HttpClientAutoConfiguration { private final HttpClientProperties properties; //Configuration in application.properties will be used to create a good configuration public HttpClientAutoConfiguration(HttpClientProperties properties){ this.properties = properties; } @Bean//Declare as bean to inject automatically @ConditionalOnMissingBean(HttpClient.class)//When there is no created HttpClient instance, this method is used to create it. public HttpClient httpClient(){ //Building RequConfig RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(properties.getConnectTimeOut())//Set connection timeout, default 1 second .setSocketTimeout(properties.getSocketTimeOut()).build();//Set the read timeout time by default of 10 seconds HttpClient client = HttpClientBuilder.create() .setDefaultRequestConfig(requestConfig) //Setting request Config .setUserAgent(properties.getAgent())//Setting up User-Agent .setMaxConnPerRoute(properties.getMaxConnPerRoute())//Set the maximum number of connections for a remote IP .setMaxConnTotal(properties.getMaxConnTotaol())//Set the total number of connections .build(); return client; } @Bean @ConditionalOnBean(name="httpClient",value=HttpClient.class)//Existing HttpClient instance httpClient @ConditionalOnProperty(name = "spring.httpclient.testConfig", havingValue = "true")//Read Configuration Sets this Property to true public HttpClient httpClient1(HttpClient httpClient) throws IOException { Long contentLength=httpClient.execute(new HttpGet("https://www.taobao.com")).getEntity().getContentLength(); if(contentLength>10){ System.out.println("test success.."); }else{ System.out.println("test fail.."); } return httpClient; } }
@ Conditional OnMissing Bean: If the user does not customize a bean, the bean will be built
@ Conditional OnProperty: If the user does not open a property, it will not be built. Only open can build
@ Conditional OnClass: A class is built only if it exists.
5. Write test classes:
package com.springboot; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.util.EntityUtils; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.io.IOException; @RunWith(SpringRunner.class) @SpringBootTest public class SelfStarterApplicationTests { /** * Check if the automatic configuration HttpClient AutoConfiguration we wrote is valid */ @Autowired private HttpClient httpClient; @Autowired private HttpClient httpClient1; /** * httpclient bean Definition * There are three ways to make the automatic configuration of HttpClient AutoConfiguration work * 1.By making the package where the automatic configuration is located a subpackage annotated with the @SpringBootApplication startup class * 2.By defining the META-INF/spring.factories file, add the mapping relationship between Enable AutoConfiguration and automatic configuration * 3.By adding the annotation EnableHttpClient to the startup class, EnableHttpClient wants @Import(HttpClientAutoConfiguration.class) * @return */ @Test public void testHttclient() throws IOException { //Visit Baidu and Export Baidu Page System.out.println(EntityUtils.toString(httpClient.execute(new HttpGet("http://www.baidu.com")).getEntity())); } @Test public void testHttclient1() throws IOException { //Visit Baidu and Export Baidu Page System.out.println(EntityUtils.toString(httpClient1.execute(new HttpGet("http://www.baidu.com")).getEntity())); } }
6. At this point, since the current package is under the application entry class, the annotation @Configuration will be scanned automatically directly:
Running test class methods can successfully return results.
If the current package is not under the application entry class, that is, normally, when it is published to the outside as a third-party dependency. At this point, it will not be possible to scan the annotations automatically. There are two solutions:
Scenario 1. Create custom annotations:
package com.springboot.autoconfig; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.Import; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(HttpClientAutoConfiguration.class) public @interface EnableHttpClient { }
In the annotation, the HttpClientAutoConfiguration configuration is introduced using @Import(HttpClientAutoConfiguration.class). At this point, just add custom annotations to the application entry:
package com.springboot; import com.springboot.autoconfig.EnableHttpClient; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @EnableHttpClient @SpringBootApplication public class SelfStarterApplication { public static void main(String[] args) { SpringApplication.run(SelfStarterApplication.class, args); } }
Scenario 2. Create spring.factories and define scanning classes:
spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.springboot.autoconfig.HttpClientAutoConfiguration
The files are placed under META-INF in the resources directory:
Discrimination of the use of the two:
- When using scheme 2, after adding dependencies, it will automatically scan the configuration.
- For a while, after adding dependencies, you need to add custom annotations to the application entry to turn on the automatic scanning configuration.
Both schemes are used in practice.
7. Follow-up actions: Use mvn command to type the project into Jar package, add local warehouse, and then introduce its dependencies into other projects and complete relevant automatic configuration:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.springboot</groupId> <artifactId>self-starter</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies>
Relevant procedures: https://gitee.com/LangWangHuangShiFu/self-starter