SpringBoot学习之自动装配

小编 2026-06-04 阅读:1080 评论:0
  在前面使用SSM集成时,我们可以使用注解实现无配置化注入,但是这种依赖被进行“人工干预了的”...

  在前面使用SSM集成时,我们可以使用注解实现无配置化注入,但是这种依赖被进行“人工干预了的”,换句话就是说我们手动进行装配,那么此时还没有达到SpringBoot这种自动装配的效果,那么究竟SpringBoot如何进行自动装配的呢?下面我们就一探究竟

一。SpringBoot中创建对象的注解扩充

  其实说白了,SpringBoot并不属于一种新的技术,只不过Spring-Boot-Starter-xxxx的启动器帮我们配置了若干个被Spring管理的bean,当我们的项目依赖这些jar并启动Spring应用时,Spring的Container容器已经把jar包下的对象加以创建及管理了,我们请看下面的例子:

该例子是spring-boot-autoconfigure-2.0.0.M7.jar包的内容,我们找到如下类: DispatcherServletAutoConfiguration ,我贴出源代码:

SpringBoot学习之自动装配SpringBoot学习之自动装配
/* * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.boot.autoconfigure.web.servlet;import java.util.Arrays;import java.util.List;import javax.servlet.MultipartConfigElement;import javax.servlet.ServletRegistration;import org.springframework.beans.factory.ObjectProvider;import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;import org.springframework.boot.autoconfigure.AutoConfigureAfter;import org.springframework.boot.autoconfigure.AutoConfigureOrder;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.boot.autoconfigure.condition.ConditionMessage;import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;import org.springframework.boot.autoconfigure.condition.ConditionOutcome;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.ConditionalOnWebApplication;import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;import org.springframework.boot.autoconfigure.condition.SpringBootCondition;import org.springframework.boot.autoconfigure.web.ServerProperties;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.boot.web.servlet.ServletRegistrationBean;import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ConditionContext;import org.springframework.context.annotation.Conditional;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Import;import org.springframework.core.Ordered;import org.springframework.core.annotation.Order;import org.springframework.core.type.AnnotatedTypeMetadata;import org.springframework.web.multipart.MultipartResolver;import org.springframework.web.servlet.DispatcherServlet;/** * {@link EnableAutoConfiguration Auto-configuration} for the Spring * {@link DispatcherServlet}. Should work for a standalone application where an embedded * web server is already present and also for a deployable application using * {@link SpringBootServletInitializer}. * * @author Phillip Webb * @author Dave Syer * @author Stephane Nicoll * @author Brian Clozel */@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)@Configuration@ConditionalOnWebApplication(type = Type.SERVLET)@ConditionalOnClass(DispatcherServlet.class)@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)@EnableConfigurationProperties(ServerProperties.class)public class DispatcherServletAutoConfiguration {    /*     * The bean name for a DispatcherServlet that will be mapped to the root URL "/"     */    public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";    /*     * The bean name for a ServletRegistrationBean for the DispatcherServlet "/"     */    public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";    @Configuration    @Conditional(DefaultDispatcherServletCondition.class)    @ConditionalOnClass(ServletRegistration.class)    @EnableConfigurationProperties(WebMvcProperties.class)    protected static class DispatcherServletConfiguration {        private final WebMvcProperties webMvcProperties;        public DispatcherServletConfiguration(WebMvcProperties webMvcProperties) {            this.webMvcProperties = webMvcProperties;        }        @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)        public DispatcherServlet dispatcherServlet() {            DispatcherServlet dispatcherServlet = new DispatcherServlet();            dispatcherServlet.setDispatchOptionsRequest(                    this.webMvcProperties.isDispatchOptionsRequest());            dispatcherServlet.setDispatchTraceRequest(                    this.webMvcProperties.isDispatchTraceRequest());            dispatcherServlet.setThrowExceptionIfNoHandlerFound(                    this.webMvcProperties.isThrowExceptionIfNoHandlerFound());            return dispatcherServlet;        }        @Bean        @ConditionalOnBean(MultipartResolver.class)        @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)        public MultipartResolver multipartResolver(MultipartResolver resolver) {            // Detect if the user has created a MultipartResolver but named it incorrectly            return resolver;        }    }    @Configuration    @Conditional(DispatcherServletRegistrationCondition.class)    @ConditionalOnClass(ServletRegistration.class)    @EnableConfigurationProperties(WebMvcProperties.class)    @Import(DispatcherServletConfiguration.class)    protected static class DispatcherServletRegistrationConfiguration {        private final ServerProperties serverProperties;        private final WebMvcProperties webMvcProperties;        private final MultipartConfigElement multipartConfig;        public DispatcherServletRegistrationConfiguration(                ServerProperties serverProperties, WebMvcProperties webMvcProperties,                ObjectProvider<MultipartConfigElement> multipartConfigProvider) {            this.serverProperties = serverProperties;            this.webMvcProperties = webMvcProperties;            this.multipartConfig = multipartConfigProvider.getIfAvailable();        }        @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)        @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)        public ServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration(                DispatcherServlet dispatcherServlet) {            ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(                    dispatcherServlet,                    this.serverProperties.getServlet().getServletMapping());            registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);            registration.setLoadOnStartup(                    this.webMvcProperties.getServlet().getLoadOnStartup());            if (this.multipartConfig != null) {                registration.setMultipartConfig(this.multipartConfig);            }            return registration;        }    }    @Order(Ordered.LOWEST_PRECEDENCE - 10)    private static class DefaultDispatcherServletCondition extends SpringBootCondition {        @Override        public ConditionOutcome getMatchOutcome(ConditionContext context,                AnnotatedTypeMetadata metadata) {            ConditionMessage.Builder message = ConditionMessage                    .forCondition("Default DispatcherServlet");            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();            List<String> dispatchServletBeans = Arrays.asList(beanFactory                    .getBeanNamesForType(DispatcherServlet.class, false, false));            if (dispatchServletBeans.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {                return ConditionOutcome.noMatch(message.found("dispatcher servlet bean")                        .items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));            }            if (beanFactory.containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {                return ConditionOutcome                        .noMatch(message.found("non dispatcher servlet bean")                                .items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));            }            if (dispatchServletBeans.isEmpty()) {                return ConditionOutcome                        .match(message.didNotFind("dispatcher servlet beans").atAll());            }            return ConditionOutcome.match(message                    .found("dispatcher servlet bean", "dispatcher servlet beans")                    .items(Style.QUOTE, dispatchServletBeans)                    .append("and None is named " + DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));        }    }    @Order(Ordered.LOWEST_PRECEDENCE - 10)    private static class DispatcherServletRegistrationCondition            extends SpringBootCondition {        @Override        public ConditionOutcome getMatchOutcome(ConditionContext context,                AnnotatedTypeMetadata metadata) {            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();            ConditionOutcome outcome = checkDefaultDispatcherName(beanFactory);            if (!outcome.isMatch()) {                return outcome;            }            return checkServletRegistration(beanFactory);        }        private ConditionOutcome checkDefaultDispatcherName(                ConfigurableListableBeanFactory beanFactory) {            List<String> servlets = Arrays.asList(beanFactory                    .getBeanNamesForType(DispatcherServlet.class, false, false));            boolean containsDispatcherBean = beanFactory                    .containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);            if (containsDispatcherBean                    && !servlets.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {                return ConditionOutcome                        .noMatch(startMessage().found("non dispatcher servlet")                                .items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));            }            return ConditionOutcome.match();        }        private ConditionOutcome checkServletRegistration(                ConfigurableListableBeanFactory beanFactory) {            ConditionMessage.Builder message = startMessage();            List<String> registrations = Arrays.asList(beanFactory                    .getBeanNamesForType(ServletRegistrationBean.class, false, false));            boolean containsDispatcherRegistrationBean = beanFactory                    .containsBean(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);            if (registrations.isEmpty()) {                if (containsDispatcherRegistrationBean) {                    return ConditionOutcome                            .noMatch(message.found("non servlet registration bean").items(                                    DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));                }                return ConditionOutcome                        .match(message.didNotFind("servlet registration bean").atAll());            }            if (registrations                    .contains(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)) {                return ConditionOutcome.noMatch(message.found("servlet registration bean")                        .items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));            }            if (containsDispatcherRegistrationBean) {                return ConditionOutcome                        .noMatch(message.found("non servlet registration bean").items(                                DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));            }            return ConditionOutcome.match(message.found("servlet registration beans")                    .items(Style.QUOTE, registrations).append("and none is named "                            + DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));        }        private ConditionMessage.Builder startMessage() {            return ConditionMessage.forCondition("DispatcherServlet Registration");        }    }}
View Code

 

 

该代码是创建SpringMvc的典型示例  我想@Bean @Configuration 这个大家在熟悉不过了,下面我们来看几个比较陌生的注解,我简单解释一下:

1.spring-boot利用Conditional来确定是否创建Bean实例,这个注解我们可以理解为满足一定条件我们才创建Bean

2.这些注解我们可以在spring-boot-autoconfigure-2.0.0.M7.jar下 org.springframework.boot.autoconfigure.condition下找到

3.常见的注解解释:

  3.1 @ConditionalOnBean :匹配给定的class类型或者Bean的名字是否在SpringBeanFactory中存在

  3.2 @ConditionalOnClass:匹配给定的class类型是否在类路径(classpath)中存在

  3.3 @ConditionalOnExpression : 匹配给定springEL表达式的值返回true时

  3.4 @ConditionalOnJava :匹配JDK的版本,其中range属性是枚举类型有两个值可以选择 

      3.4.1 EQUAL_OR_NEWER 不小于

      3.4.2 OLDER_THAN 小于

                  3.4.3 value属性用于设置jdk版本

  3.5 ConditionalOnMissingBean:spring上下文中不存在指定bean时

    3.6 ConditionalOnWebApplication:在web环境下创建

 

@ConditionalOnBean is evaluated after all configuration classes have been processed, i.e you can't use it to make a whole configuration class conditional on the presence of another bean. You can, however, use it where you have to make all of the configuration's beans conditional on the presence of another bean.注意:Conditional 只有在所有配置类被加载完的时候被评估是否要创建,因此Conditional不能在配置类里根据其他创建的方法进行判断


@Bean
@ConditionalOnBean({Teacher.class})
public Student student(StudentProperties studentProperties) {
Student student = new Student();
student.setStuName(studentProperties.getName());
return student;
}

@Bean
@ConditionalOnMissingBean
public static Teacher teacher() {
return new Teacher();
}

@Bean
@ConditionalOnMissingBean
public static School school() {
return new School();
}
比如上述代码 Student是不会被创建的,如果非要@Bean和@Conditional使用,则可以借助于@Import方式实现
@Configuration
@EnableConfigurationProperties(StudentProperties.class)
@Import(TeacherAutoConfiguration.class)
public class MyTestAutoConfiguration {

@Bean
@ConditionalOnBean(Teacher.class)
public Student student(StudentProperties studentProperties) {
Student student = new Student();
student.setStuName(studentProperties.getName());
return student;
}



}

@Configuration
public class TeacherAutoConfiguration {

@Bean
@ConditionalOnMissingBean
public static Teacher teacher() {
return new Teacher();
}
}

 

 

二。实现简单的SpringBoot示例

1.我们先创建两个类分别为 Teacher Student,项目结构图

SpringBoot学习之自动装配

 

 

 注意图中标圈的文件:spring-configuration-metadata.json文件,我们配置这个文件后,可以在idea或者spring sts中配置application.yml得到相关智能提示

 json数据如下

SpringBoot学习之自动装配SpringBoot学习之自动装配
{  "hints":[],  "groups":[],  "properties": [    {      "sourceType": "com.bdqn.lyrk.springboot.study.configuration.MyProperties",      "name": "my.loginName",      "description": "登录名",      "type": "java.lang.String"    }  ]}
View Code

 

2.MyObjectAutoConfiguration类代码:

SpringBoot学习之自动装配SpringBoot学习之自动装配
package com.bdqn.lyrk.springboot.study.configuration;import com.bdqn.lyrk.springboot.study.pojo.School;import com.bdqn.lyrk.springboot.study.pojo.Student;import com.bdqn.lyrk.springboot.study.pojo.Teacher;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * 自动创建对象示例,例子中我们创建Teacher与Student对象。 * 当项目打成jar包依赖到其他Spring容器中,这些对象我们可以自动进行注入 */@Configuration@EnableConfigurationProperties(MyProperties.class)public class MyObjectAutoConfiguration {    @Configuration    static class TeacherAutoConfiguration {        @Bean        @ConditionalOnClass({Teacher.class, School.class})        public static Teacher teacher() {            return new Teacher();        }    }    @Configuration    static class StudentAutoConfiguration {        @Bean        @ConditionalOnMissingBean        public Student student(@Autowired MyProperties myProperties) {            return new Student(myProperties.getLoginName());        }    }}
View Code

 

3.MyProperties代码:

SpringBoot学习之自动装配SpringBoot学习之自动装配
package com.bdqn.lyrk.springboot.study.configuration;import org.springframework.boot.context.properties.ConfigurationProperties;/** * 用于实现读取application.yml中的配置 */@ConfigurationProperties(prefix = MyProperties.PREFIX)public class MyProperties {    public static final String PREFIX = "my";    private String loginName;    public String getLoginName() {        return loginName;    }    public void setLoginName(String loginName) {        this.loginName = loginName;    }}
View Code

4.application.yml配置:

SpringBoot学习之自动装配SpringBoot学习之自动装配
my:  loginName: testspring:  main:    web-environment: false
View Code

5.Application代码:

SpringBoot学习之自动装配SpringBoot学习之自动装配
package com.bdqn.lyrk.springboot.study;import com.bdqn.lyrk.springboot.study.pojo.Student;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplicationpublic class Application {    public static void main(String[] args) {        ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);        Student student = applicationContext.getBean(Student.class);        System.out.println(student.getLoginName());    }}
View Code

当运行成功时:我们可以看到输出Student的loginName属性是test

SpringBoot学习之自动装配

 6.在META-INF/spring.factories编写如下代码:

 

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.bdqn.lyrk.springboot.study.configuration.MyTestAutoConfiguration

 


注意:此配置文件非常重要,当我们这个jar包被SpringBoot依赖时,spring会读取org.springframework.boot.autoconfigure.EnableAutoConfiguration所定义的配置类并加载



版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
标签列表