SpringBoot学习笔记【part02】底层注解

导读:本篇文章讲解 SpringBoot学习笔记【part02】底层注解,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

SpringBoot 学习笔记 Part02

1. 组件添加

1.1 @Configuration

@Configuration注解标注于类名上,可以告诉SpringBoot这是一个配置类(作用==配置文件)。

配置类本身也是个组件,也会被存入IoC容器中去。

@Configuration
public class MyConfig {
}

@Configuration有个布尔类型的属性为proxyBeanMethods,意为代理bean的方法,默认是开启的。

proxyBeanMethods为true时:
	外部无论对配置类的这个组件注册方法(@Bean标注的那些方法)调用多少次获取的都是之前注册容器中的单实
例对象。从IoC容器中获取两个出来进行比对,结果是true。
	本质上是,经过该标注,这个类的方法都变成了代理对象调用方法,调用时会检查容器中是否有没有这个方法返
回的组件,如果有就拿,没有才调用新创。
	作用:保持组件单实例,用于组件依赖。
	
proxyBeanMethods为false时:	
	该类方法将不再是代理对象调用方法,简单来说就是每次调用都会重新创建对象进容器。
	本质上是,每次调用都不会再喝代理方法那样去检查容器是否有这个对象了,而是直接创建,程序速度会因此大
大提升。
	作用:保持组件多实例。

下面是一个组件多实例的例子,不难看出分别调用了两次pet01()方法将会被创建两个不同的Pet对象。

@Configuration(proxyBeanMethods = false)
public class MyConfig {

    @Bean
    public User user01(){
        User user = new User("zhangsan", 18);
        user.setPet(pet01());
        return user;
    }

    @Bean("tom")
    public Pet pet01(){
        return new Pet("tomcat",5);
    }
}

测试一下结果,如下:

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
        
        User user = run.getBean("user01", User.class);
        Pet pet = run.getBean("tom", Pet.class);
        System.out.println(user.getPet()==pet);//false
    }
}

总结:Full模式和Lite模式

Full模式:proxyBeanMethods=true
    配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式。
	简单来说就是,若组件在下边别人还要用,即还存在依赖,则调成true。这样能保证容器中它依赖的组件就是
容器中的组件。
	
Lite模式:proxyBeanMethods=false
	配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断。
	简单来说就是,给容器中只是单单注册组件,之间没有依赖,则调成false。这样springboot启动过程会非常
快。
	
(组件依赖必须使用Full模式默认。其他默认是否Lite模式)

1.2 @Bean

@Bean贴在一个返回值为组件类型的方法上可以给容器中添加组件。若没有声明name属性,则以方法名为组件的id,返回类型就是组件的类型,返回的值就是组件在容器中的实例。

@Configuration
public class MyConfig {

    @Bean
    public User user01(){
        return new User("zhangsan",18);
    }

    @Bean("tom")
    public Pet pet01(){
        return new Pet("tomcat",5);
    }
}

配置类里使用@Bean标注在方法上给容器注册组件时,默认是单实例的。

1.3 @Component

给容器中注册组件,除了用@Configuration编写一个配置类,我们还可以用之前在spring中学到的一些注解。只要在这些类在包内,就都可以被扫描到。

@Component:代表一个组件
@Controller:代表一个控制器
@Service:代表一个业务逻辑组件
@Repository:代表一个数据库层组件

1.4 @ComponentScan

指定包扫描规则,在之前spring的学习中也 使用过。

1.5 @Import

该注解只有一个字节码数组属性 Class<?>[] value() ,它用于指定字节码文件自动地给容器中创建对应类型的组件。

@Import 将调用填入的class文件的无参构造器,创建出指定类型的组件对象,且默认组件的名字是它的全类名(如User.class创建出来的组件名将是com.swz.domain.User)。

@Import({User.class, DBHelper.class})
@Configuration
public class MyConfig {
}

1.6 @Conditional

条件装配:满足Conditional指定的条件时,则进行组件注入。

在这里插入图片描述

如上图,Conditional有许多拓展注解,且每个注解对应不同类型的条件装配,如:ConditionalOnBean代表当容器中有指定bean类型时才会注入,而ConditionalOnMissBean则相反。下面来介绍下部分常用的拓展条件装配组件。

@Conditional扩展注解 作用(判断是否满足当前指定条件)
@ConditionalOnJava 系统的java版本是否符合要求
@ConditionalOnBean 容器中存在指定Bean;
@ConditionalOnMissingBean 容器中不存在指定Bean;
@ConditionalOnExpression 满足SpEL表达式指定
@ConditionalOnClass 系统中有指定的类
@ConditionalOnMissingClass 系统中没有指定的类
@ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty 系统中指定的属性是否有指定的值
@ConditionalOnResource 类路径下是否存在指定资源文件
@ConditionalOnWebApplication 当前是web环境
@ConditionalOnNotWebApplication 当前不是web环境
@ConditionalOnJndi JNDI存在指定项

我们可以使用条件注入注解贴在对应的方法上来按条件创建一些bean对象。当然,@Conditional系列注解也可以贴在类上,意为若不满足条件,这个类组件不会被创建进容器。

以下代码意为当容器中没有tom对象时则把user01和tom22都创建出来,这就展现了条件注入反向操作的魅力。

@ConditionalOnMissingBean(name = "tom")
@Configuration
public class MyConfig {

    @Bean
    public User user01(){
        User user = new User("zhangsan", 18);
        user.setPet(pet01());
        return user;
    }


    @Bean("tom22")
    public Pet pet01(){
        return new Pet("tomcat",5);
    }
}

2. @ImportResource

@ImportResource 是原生配置文件引入注解。
当你的组员还在使用xml方式配置bean时,而你想坚持注解,这时我们可以使用@ImportResource把xml文件导入进来。

(在其中一个Configuration类中导入即可,IoC容器是共享的)

@ImportResource("classpath:beans.xml")
@Configuration
public class MyConfig {  
}

3. @ConfigurationProperties

@ConfigurationProperties 是一个配置绑定注解。
当我们用Java原生方法去读取properties等配置文件中的数据时,是很繁琐及复杂的。

@ConfigurationProperties 这个注解可以自动读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用。

application.properties有如下属性。

mycar.brand=比亚迪
mycar.price=20000

使用上面的注解就可以在 Car 的 bean 类里进行自动提取配置数据了。

其中默认属性 prefix 为配置文件的键值前缀。

方式一:@Component + @ConfigurationProperties

(注:加上 @Component 注解,标识该类是一个组件,才会被加载进容器。因为只有在容器中的组件,才会拥有Springboot提供的强大功能)

@Component
@ConfigurationProperties(prefix = "car")
public class Car {
    private String brand;
    private Double price;
    
    public getter/setter/toString(){}
    
}

方式二:@EnableConfigurationProperties + @ConfigurationProperties

@EnableConfigurationProperties 需要写在配置类里,属性中写对应的字节码文件,下面以Car这个类为例说明。

共有两个功能:

  1. 开启Car这个类的配置绑定功能
  2. 把Car这个组件自动注册到容器中去(替换了在Car类手动加@Component的过程)
@EnableConfigurationProperties(Car.class) //把这个Car这个组件自动配置绑定并注册到容器中
@Configuration
public class MyConfig {
}

而Car的bean类就可以省去方法一种的@Component。

@ConfigurationProperties(prefix = "mycar")
public class Car {

    private String brand;
    private Double price;
    
	public getter/setter/toString(){}
    
}

总结:方式二使用情况更多,因为绝大部分时我们使用的是第三方的包,这时候我们无法用方式一去给第三方包中的源码加上@Component注解。

因此,使用方式二在配置类声明要我们需求配置绑定的类并自动加载进内存是个不二之选。

4. 解决 *.properties 中文乱码问题

在使用@ConfigurationProperties注解后,访问控制器方法的JSON中出现了中文乱码,经过排查,是提取properties配置文件过程中的编码问题。因为虽然Springboot为我们解决了web端的servlet中文乱码问题,但是properties配置文件提取时仍会出现中文乱码。

总结解决办法如下两步骤:

  1. 在idea中设置,将中文全部转成ASCII码

在这里插入图片描述

  1. 在Configuration类中加入注解@PropertySource(encoding = “utf-8”,value = “classpath:application.properties”),指定编码格式。
@PropertySource(encoding = "utf-8",value = "classpath:application.properties")
@EnableConfigurationProperties(Car.class)
@Configuration
public class MyConfig {
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/84481.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!