自动装配是springboot中一大特性,即springboot在程序初始化时可以根据classpath类、property属性、context中实例、以及运行容器特征等各种动态条件,来按需初始化相应的bean并交付给终端使用。
1、@ConditionalOnBean:如果此Bean实例已存在,则执行(如果修饰在class上,则此类加载;如果修饰在方法上 ,则此方法执行)。通常用于限定“如果必备的bean已经被初始化时,才会自动装备当前实例”。
2、@ConditionalOnMissingBean:如果此Bean实例尚未被初始时,则执行。
3、@ConditionalOnClass:如果classpath中存在此类(且可被加载)时,则执行。
4、@ConditionalOnMissingClass:如果class中不存在此类时,则执行。
5、@ConditionalOnProperty:如果Envrionment中存在此property、或者相应的property参数值匹配时,则执行。比如springboot中,各种内置的组件是否enabled,就是根据此条件判断。
6、@ConditionalOnWebApplication:如果当前容器为WEB时,则执行。比如初始化springMVC、restTemplate、各种endpoint初始化等。
此外springboot还提供了其他更多的condition判断,大家按需使用即可。在springbean容器初始化之前、Envrionment准备就绪之后,将根据spring.factories文件中指定的AutoConfiguration类列表逐个解析上述Condition,并在稍后有序加载、初始化相关bean。
源码,请参见:ConfigurationClassParser,ConfigurationClassBeanDefinitionReader,SpringBootCondition。
装配时机:
1、@AutoConfigureAfter:在指定的其他自动装配类初始化之后,才装配当前类。
2、@AutoConfigureBefore:在指定的其他装配类初始化之后,才装配当前类。
3、@AutoConfigureOrder:指定当前类装配的优先级,类似于Ordered接口。
每个可以自动装配的springboot类,通常具备如下几个特征:
1)使用@Configuration修饰,且此类不应该被@ComponentScan包含。
2)类上可以被@Conditional*修饰。
3)构造函数不应该为private;构造函数中的参数类,可以被spring容器注入。
4)此类必须在META-INF/spring.factories中声明(注册),才能被springboot感知。
5)springboot中自动装配的类,需要设计好加载或者引用其他bean的顺序,否则可以引入“循环依赖”问题,导致容器初始化失败。
6)自动装配类,通常配合@ConfigurationProperties完成一些属性的配置和bean加载,当然@ConfigurationProperties并不是必须的。
本文展示一下,如何使用springboot自动装配,实现RestTemplate类的自定义设置。
一、HttpClientAutoConfiguration
import okhttp3.OkHttpClient; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.client.HttpClient; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.boot.web.client.RestTemplateCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; import java.util.HashMap; import java.util.Map; /** * @author liuguanqing * created 2018/6/28 上午11:33 * http客户端 **/ @Configuration @ConditionalOnWebApplication @ConditionalOnBean(Context.class) @AutoConfigureAfter({ContextAutoConfiguration.class}) @EnableConfigurationProperties({HttpProperties.class}) public class HttpClientAutoConfiguration { private final HttpProperties httpProperties; private final Context context; public HttpClientAutoConfiguration(HttpProperties httpProperties, ObjectProvider<Context> contextObjectProvider, ObjectProvider<RestTemplateBuilder> restTemplateBuilderObjectProvider) { this.httpProperties = httpProperties; this.context = contextObjectProvider.getIfUnique(); } @Bean @ConditionalOnMissingBean public HttpClientConfiguration httpClientConfiguration() { HttpClientConfiguration configuration = HttpClientConfiguration.common(); String charset = httpProperties.getCharset(); if (charset != null) { configuration.setCharset(charset); } ..... return configuration; } @Bean public MeteorRestTemplateCustomizer meteorRestTemplateCustomizer(HttpClientConfiguration httpClientConfiguration) { return new MeteorRestTemplateCustomizer(httpClientConfiguration); } private static ClientHttpRequestFactory clientHttpRequestFactory(HttpClientConfiguration configuration) { String clientType = configuration.getClientType(); if (HttpClientConfiguration.HTTP_CLIENT_TYPE_OK_HTTP.equalsIgnoreCase(clientType)) { OkHttpClient httpClient = OkHttpClientBuilder.build(configuration); return new OkHttp3ClientHttpRequestFactory(httpClient); } HttpClient httpClient = HttpComponentsClientBuilder.build(configuration); return new HttpComponentsClientHttpRequestFactory(httpClient); } public static class MeteorRestTemplateCustomizer implements RestTemplateCustomizer { private final HttpClientConfiguration configuration; public MeteorRestTemplateCustomizer(HttpClientConfiguration configuration) { this.configuration = configuration; } @Override public void customize(RestTemplate restTemplate) { restTemplate.setRequestFactory(clientHttpRequestFactory(configuration)); //restTemplate.getInterceptors().add(new MeteorHttpClientRequestHeaderInterceptor(configuration)); } } }
1)HttpClientConfiguration为自定义的构建配置,原则不影响对本文的阅读,感兴趣可以参见如下两个博客地址:“HttpComponents客户端”、“okHttp客户端”。
2)HttpProperties为本文自定义的、用于配置http客户端参数的配置类,请参见下文。
3)Context为本例的一个额外类,仅供演示自动装配时如何注入外部类。不影响阅读。
@EnableConfigurationProperties注释中指定的Properties类(@ConfigurationProperties修饰的类,可以多个),可以被AutoConfiguration类构造函数中直接注入(最好它们已经被初始化结束);此外对于其他spring bean,则不能直接在构造函数中引入,我们需要使用ObjectProvider来“告知容器”指定和获取,比如本文中的Context实例类。
在springboot环境下,我们初始化RestTemplate,尽量使用RestTemplateBuilder来构建,参见下文。
二、HttpProperties
import org.springframework.boot.context.properties.ConfigurationProperties; import java.time.Duration; import java.util.Map; /** * @author liuguanqing * created 2018/7/29 下午8:40 * 用于构建Context实例,单例 **/ @ConfigurationProperties("http") public final class HttpProperties { private String charset = ContextConstants.DEFAULT_CHARSET; //连接创建,HTTP/TCP等RPC private Duration connectionTimeout = Duration.ofMillis(500); //SO_TIMEOUT private Duration socketTimeout = Duration.ofMillis(500); //连接池中的连接被保活的时长 private Duration keepAliveTime = Duration.ofMillis(6000); //请求异常(exception),重试的次数,默认为0,不重试 private Integer retryTimes = 0; //是否重试 private Boolean retryOnFailure = false; //业务全局header,默认会添加到http请求中,每项为K-V private Map<String, String> globalHeaders; private String clientType = HttpClientConfiguration.HTTP_CLIENT_TYPE_HTTP_COMPONENTS; public String getCharset() { return charset; } public void setCharset(String charset) { this.charset = charset; } public Duration getConnectionTimeout() { return connectionTimeout; } public void setConnectionTimeout(Duration connectionTimeout) { this.connectionTimeout = connectionTimeout; } public Duration getSocketTimeout() { return socketTimeout; } public void setSocketTimeout(Duration socketTimeout) { this.socketTimeout = socketTimeout; } public Duration getKeepAliveTime() { return keepAliveTime; } public void setKeepAliveTime(Duration keepAliveTime) { this.keepAliveTime = keepAliveTime; } public Integer getRetryTimes() { return retryTimes; } public void setRetryTimes(Integer retryTimes) { this.retryTimes = retryTimes; } public Boolean getRetryOnFailure() { return retryOnFailure; } public void setRetryOnFailure(Boolean retryOnFailure) { this.retryOnFailure = retryOnFailure; } public Map<String, String> getGlobalHeaders() { return globalHeaders; } public void setGlobalHeaders(Map<String, String> globalHeaders) { this.globalHeaders = globalHeaders; } public String getClientType() { return clientType; } public void setClientType(String clientType) { this.clientType = clientType; } }
三、声明自动装配
我们需要在META-INF/spring.factories文件中,声明所有的自动装配类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.test.commons.springboot.context.ContextAutoConfiguration,\ com.test.commons.springboot.httpclient.HttpClientAutoConfiguration,\ com.test.commons.springboot.web.WebApplicationAutoConfiguration,\ com.test.commons.springboot.metrics.HttpMetricsExportAutoConfiguration
每行声明一个类,多个类时以“,”分割,“\”作为换行符。
四、初始化RestTemplate
@SpringBootApplication public class Application { public static void main(String[] args) { Application.run(DemoApplication.class, args); } @Bean public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { return restTemplateBuilder.build(); } }
我们需要在使用@Configuration修饰的bean中,初始化RestTemplate,请注意不要尝试在AutoConfiguration类中为应用初始化RestTemplate,因为这是违反设计的。
此外,我们通常使用RestTemplateBuilder来初始化restTemplate,此时我们在AutoConfiguration类中指定的各种Customizer则会生效。
相关推荐
总结,Spring Boot的自动装配和starter技术大大简化了Java应用的配置,通过`@Import`注解和自动配置机制,我们可以高效地管理Bean的生命周期。理解这些原理对于优化和调试Spring Boot应用至关重要。
自动装配是SpringBoot的一项功能,它通过`@Autowired`注解来自动注入依赖对象,无需显式地在配置文件中声明。SpringBoot会根据类型或名称自动找到合适的bean并注入到需要的对象中。 2. **基于注解的配置** ...
在Spring Boot项目中,自动装配Bean是指在应用程序启动时自动将Bean实例化并注入到容器中的过程。在本例中,我们使用@Reference注解来标记需要自动装配的字段。 在配置类中,我们使用...
在启动 Spring IoC 时,容器自动装载了一个 AutowiredAnnotationBeanPostProcessor 后置处理器,当容器扫描到 @Autowired、@Resource 或 @Inject 时,就会在 IoC 容器自动查找需要的 bean,并装配给该对象的属性。...
自动装配是通过`@EnableAutoConfiguration`注解来开启的,这个注解会触发一系列预定义的`AutoConfiguration`类,这些类根据应用中已存在的依赖(如类路径中的JAR文件或配置类)来决定哪些bean需要被创建和装配。...
自动装配的基础,是 Spring 从 4.x 版本开始支持 JavaConfig,让开发者可以免去繁琐的 xml 配置形式,而是使用熟悉的 Java 代码加注解,通过 @Configuration、@Bean 等注解可以直接向 Spring 容器注入 Bean 信息。
在Spring框架中,动态装配bean并将其注入到Controller中是一种常见的需求,这允许我们根据运行时的条件或配置来创建和管理对象。本篇将详细解释两种实现方式:基于XML配置和使用`@PostConstruct`注解。 首先,让...
1. **@Autowired**:这是最常用的注解,用于自动装配bean。Spring会尝试找到类型匹配的bean进行注入。如果存在多个候选bean,则可以通过`@Qualifier`进一步指定。 2. **@Qualifier**:与`@Autowired`配合使用,用于...
自动装配是Spring自动检测Bean之间的依赖关系,并自动注入这些依赖的过程。它可以极大减少配置量,但缺点是可能因为过于复杂而难以预测注入结果,特别是在复杂的项目中。Spring提供了五种自动装配模式:no(默认不...
SpringBoot 打成jar包供第三方引用自动装配方案实现 每天多学一点点~ 话不多说,这就开始吧… ...虽然知道目前水平有限,先试试普通的jar包如何与spring自动装配吧~ 环境 jdk1.8 springboot 2.1.12.RELEASE 2.使用者手
在Spring Boot的应用程序启动流程中,自动装配是一个关键特性,它使得开发者无需手动配置bean,而是由Spring Boot自动识别和管理。本节我们将深入探讨自动装配的原理。 首先,Spring Boot的启动是从`run`方法开始的...
`@Autowired`是Spring提供的一个依赖注入注解,它能够自动将匹配的Bean注入到需要的地方。例如: ```java @Autowired private MyService myService; ``` 这里,`MyService`类型的Bean会被自动注入到`myService...
Spring Boot通过`@Autowired`注解自动将匹配的bean注入到需要的地方。例如,如果一个类需要数据库连接,Spring Boot会根据配置自动注入一个合适的DataSource。此外,Spring Boot还提供了一些默认配置,使得许多常见...
然而,在实际开发过程中,可能会遇到在拦截器中注入Service为空的问题,这个问题通常是由于SpringBoot的自动装配机制没有正确地识别和管理拦截器中的依赖。本文将详细讲解如何解决这个常见问题。 首先,我们来看...
自动装配的概念源于Spring框架的依赖注入(Dependency Injection, DI),但在Spring Boot中被进一步加强,使得开发者能够快速构建可运行的应用。本教程将深入探讨Spring Boot的自动装配机制,并通过实例进行演示。 ...
在Spring Boot框架中,Bean是核心概念之一,它代表了应用程序中的对象,这些对象由Spring容器管理,包括它们的创建、初始化、装配以及销毁。理解并熟练使用Bean对于开发高效且可维护的Spring Boot应用至关重要。本文...
"bean的注入问题"可能是指在Spring Boot框架中遇到的依赖注入问题,这通常是通过@Autowired注解来解决的,用于在运行时自动装配所需的bean。"springboot的异步加载bean"则提到了Spring Boot的异步特性,这允许应用...
- `@Autowired`:自动装配,用于注入依赖,SpringBoot会自动查找类型匹配的Bean进行注入。 - `@RequestMapping`:用于处理HTTP请求,可以与`@GetMapping`、`@PostMapping`等结合使用,指定URL映射。 3. **...
5. **@Resource**:与@Autowired类似,但它是JSR-250规范的一部分,不仅可以按类型装配,还可以通过名称来装配Bean。 #### 实现机制 Spring基于注解的依赖注入主要通过以下步骤实现: - **注解处理器**:Spring的...
对于 prototype 作用域的 bean,有一点非常重要,那就是 Spring 不能对一个 prototype bean 的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个 prototype 实例后,将它交给客户端,随后就对该 ...