springboot自动装配理解

小白记录跟着狂神学习心得,在此感谢狂神大神,记录如有不对请指教。
1.回顾spring
spring配置bean的方法:1.配置文件配置(set注入和构造器构造)ClassPathXmlApplicationContext来获取配置文件来获取bean,2.java配置类来配置AnnotationConfigApplicationContext来获取配置类来获取bean。
本次重点研究java配置类来配置:
第一次尝试
构建Java配置类

@Configuration//表明java配置类,代替xml配置文件
@ComponentScan("com.yuke.pro.config.MyConfig")//扫描包路径,限制他只能扫自己
public class MyConfig
{
    //标注为一个bean
    @Bean
    public User user() {
        return new User();
        
    }    
}

实体

@Component
public class User
{
    @Value("yuke")
    private String name;
    @Value("男")
    private String sex;
}

测试结果

@Test
    public void testNoXML() {
        ApplicationContext context=new AnnotationConfigApplicationContext(MyConfig.class);
        User user = context.getBean("user",User.class);
        System.out.println(user.toString());
    }

在这里插入图片描述

第二次尝试
当有两个配置文件,一个java配置类不能完成时怎么办?引出@Import注解,构建两个java配置类调用java配置类2

@Configuration
@ComponentScan("com.yuke.pro.config.MyConfig")
 //引入配置类2
@Import(MyConfig2.class)
public class MyConfig
{
    //标注为一个bean
    @Bean
    public User user() {
        return new User();
        
    }
    
}
java配置类2
@Configuration

public class MyConfig2
{
    @Bean
    public Hobby hobby() {
        return new Hobby();
    }
}

实体1

@Component
public class User
{
    @Value("yuke")
    private String name;
    @Value("男")
    private String sex;
    @Autowired
    private Hobby hobby;
}

实体2

public class Hobby
{
    @Value("篮球")
    private String name;
    public Hobby() {
    }
}

测试

 @Test
    public void testNoXML() {
        ApplicationContext context=new AnnotationConfigApplicationContext(MyConfig.class);
        User user = context.getBean("user",User.class);
        System.out.println(user.toString());
    }

在这里插入图片描述

第三次尝试
整合过ssm框架时,配置文件存在多个时,即有多个配置类怎么办?就像起初在配置web.xml时我们要配置多个servlet,而springmvc巧妙的通过加一层简化了问题:配DispatcherServlet,在所有servlet前面加一层,就解决了问题(没有什么是加一层解决不了的)。我们是否可以**@Import(MyImportSelector.class)**,引入的MyImportSelector这个类就是为了选择我们想引入的配置类(达到加一层的效果)
多个配置类
第一个总配置类

@Configuration
@ComponentScan("com.yuke.pro.config.MyConfig")
//MyImportSelector引入其他配置类
@Import(MyImportSelector.class)
public class MyConfig
{
    @Bean
    public User user() {
        return new User();
    }
}

其他配置类2

@Configuration
public class MyConfig2
{
    @Bean
    public Hobby hobby() {
        return new Hobby();
    }
}

其他配置类3

@Configuration
public class MyConfig3
{
    @Bean
    public Food food() {
        return new Food();
    }
}

创建MyImportSelector,通过MyImportSelector引入配置类

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 导入配置类2,配置类3
        return new String[]{"com.yuke.pro.config.MyConfig2""com.yuke.pro.config.MyConfig3"};
    }
}

测试

 @Test
    public void testNoXML() {
        ApplicationContext context=new AnnotationConfigApplicationContext(MyConfig.class);
        User user = context.getBean("user",User.class);
        System.out.println(user.toString());
    }

在这里插入图片描述

可见加一层的效果是可行的,但是将路径硬编码到代码中,肯定是不够优化的,我们在新加配置文件时,总要更改MyImportSelector编码,所有要通过配置文件把我们要引入的配置类读到MyImportSelector,实现添加配置文件达到效果。
修改优化MyImportSelector

public class MyImportSelector implements ImportSelector
{
    public String[] selectImports(AnnotationMetadata importingClassMetadata) { 
        
        {
            try {
                //读取配置文件
                Properties loadAllProperties = PropertiesLoaderUtils.loadAllProperties("config.properties");
                //获取values集合
                Collection<Object> values = loadAllProperties.values();
                return values.toArray(new String[values.size()]);
            }
            catch (IOException e) {
                e.printStackTrace();
            }    
        }
        return null;
    }
}

配置文件config.properties

config2=com.yuke.pro.config.MyConfig2
config3=com.yuke.pro.config.MyConfig3

测试结果
在这里插入图片描述

配置成功,从三次实验可以看出,最后只要我们在配置文件中配置java配置类的全路径,就可以获取这个对象,这个看懂了就可以开始springboot自动装配。

2.springboot自动装配
1.点开@SpringBootApplication,发现这是一个组合注解,其中前四个不用看(后面不在说明)
在这里插入图片描述

对比前面spring总配置类
在这里插入图片描述

2.点开@SpringBootConfiguration

在这里插入图片描述

是不是很惊喜,也就是说@SpringBootConfiguration最终还是表明这是一个Java配置类,剩下的就是怎么获取其他配置了。
3.点开@EnableAutoConfiguration
在这里插入图片描述

意不意外,有对上了,不用想AutoConfigurationImportSelector这个类一定和前面一样是要获取配置类路径,返回一个字符串数组给我们加载需要的配置类。
4.点开AutoConfigurationImportSelector
在这里插入图片描述

完全符合我们的猜测!
5.跳转到getCandidateConfigurations这个方法,看看他到底怎么获取配置
在这里插入图片描述

6.点开loadFactoryNames
在这里插入图片描述

7.点开 FACTORIES_RESOURCE_LOCATION
在这里插入图片描述

符合预测!就是这么简单。
8.看看这个重复出现的配置文件
在这里插入图片描述

3.对比spring和springboot
两者过程图比较

在这里插入图片描述

可以springboot相较于我们的实验三,复杂就复杂在配置类路径读取上,我们手写配置文件时,已经确认了我们要导入的配置类,而springboot还需要筛选等操作。到现在差不多了解到springboot是怎么加载到配置类的,那怎么给配置类赋初始化值?
4.给springboot配置类绑定配置属性,这里只演示yaml(properties不推荐)
(1).编写yaml

#yaml配置注入到实体类,可以添加占位符
person:
 name: 329410684@qq.com
 age: 18
 hoppy: [sleep,eat]
 happy: true
 dog: {name: wow,age: 3}
 map: {key: clannad,leaf: snow}
 date: 1998/01/29

(2).绑定配置文件@ConfigurationProperties(prefix=“person”)

@Component
@ConfigurationProperties(prefix="person")

public class Person
{    
    public String name;
    
    public Integer age;
    public List<String> hoppy;
    public boolean happy;
    public Dog dog;
    public Map<String, Object> map;
    public Date date;
    }

测试赋值
在这里插入图片描述
5.springboot自动装配属性设置
上面是我们在springboot赋值,接下来点开spring.factories里面记录的类,发现所有的类都标有@Configuration,表明里面都是配置类。我们从一个简单的配置类入手HttpEncodingAutoConfiguration

//表示这是一个配置类,和以前编写的配置文件一样,也可以给容器中添加组件;
@Configuration 

//启动指定类的ConfigurationProperties功能;
  //进入这个ServerProperties查看,将配置文件中对应的值和ServerProperties绑定起来;
  //并把ServerProperties加入到ioc容器中
@EnableConfigurationProperties(ServerProperties.class) 

//Spring底层@Conditional注解
  //根据不同的条件判断,如果满足指定的条件,整个配置类里面的配置就会生效;
  //这里的意思就是判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnWebApplication(
    type = ConditionalOnWebApplication.Type.SERVLET
)

//判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
@ConditionalOnClass(CharacterEncodingFilter.class)

//判断配置文件中是否存在某个配置:spring.http.encoding.enabled;
  //如果不存在,判断也是成立的
  //即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
@ConditionalOnProperty(
    prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true
)

public class HttpEncodingAutoConfiguration {
    //他已经和SpringBoot的配置文件映射了
    private final Encoding properties;
    //只有一个有参构造器的情况下,参数的值就会从容器中拿
    public HttpEncodingAutoConfiguration(HttpProperties properties) {
        this.properties = properties.getEncoding();
    }
    
    //给容器中添加一个组件,这个组件的某些值需要从properties中获取
    @Bean
    @ConditionalOnMissingBean //判断容器没有这个组件?
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
        return filter;
    }
    
}

一句话总结 :根据当前不同的条件判断,决定这个配置类是否生效!
一但这个配置类生效;这个配置类就会给容器中添加各种组件;
这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;
所有在配置文件中能配置的属性都是在xxxxProperties类中封装着;
配置文件能配置什么就可以参照某个功能对应的这个属性类
6.点开ServerProperties
在这里插入图片描述
和我们上面一样,他绑定了一个server类,而server里面的属性就是我们可以设置的属性,例如最常见的端口port

#配置端口为8081
server:
 port: 8081

官方默认配置属性,官方配置链接
在这里插入图片描述
我们不配置时,配置类的值为官方默认值,我们在application里面配置时就会覆盖官方默认值,而配置的格式就是根据配置类属性来的。
总结
1、SpringBoot启动会加载大量的自动配置类
2、我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;
3、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)
4、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
xxxxAutoConfigurartion:自动配置类;给容器中添加组件
xxxxProperties:封装配置文件中相关属性;
7.最后判断配置类生效
了解完自动装配的原理后,我们来关注一个细节问题,自动配置类必须在一定的条件下才能生效;
@Conditional派生注解(Spring注解版原生的@Conditional作用)
作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;
在这里插入图片描述
那么多的自动配置类,必须在一定的条件下才能生效;也就是说,我们加载了这么多的配置类,但不是所有的都生效了。
我们怎么知道哪些自动配置类生效?
我们可以通过启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;

#查看配置类生效情况
debug: true

在这里插入图片描述
Positive matches:(自动配置类启用的:正匹配)
Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)
Unconditional classes: (没有条件的类)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值