1、@Configuration
@Configuration 用于定义配置类,可替换XML配置文件,被注解的类内部包含一个或多个@Bean注解方法。配置类可以被AnnotationConfigApplicationContext
或者AnnotationConfigWebApplicationContext
进行加载。用于构建bean定义以及初始化Spring容器。
(1)配置类里面使用@Bean注解在方法上给容器注册组件(默认是单例)
@Configuration //告诉Spring Boot这是一个配置类==配置文件,配置类也是一个组件
public class MyConfig {
@Bean //给容器中添加组件:方法名作为组件的id,返回类型就是组件类型,返回值就是组件在容器中的实例
public Book book1(){
return new Book("三国演义","罗贯中",30,new Date());
}
@Bean("book") //此时组件的id为@Bean("")的括号里指定的名称
public Book book2(){
return new Book("水浒传","施耐庵",35,new Date());
}
}
(2)返回IOC容器,查看容器中的组件
//返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class,args);
//查看容器里的所有组件名称
String[]names = run.getBeanDefinitionNames();
for(String name:names){
System.out.println(name);
}
//获取容器中的组件
Book book1 = run.getBean("book2",Book.class); //"book"指定容器中存在的组件名称
可以发现,容器中已经存在book1和book两个组件。
注意:
@Configuration有个属性proxyBeanMeathods
(代理Bean的方法),该属性有两种取值:Full 全模式和Lite 轻量级模式,默认为Full全模式。
① Full(proxyBeanMethods = true) :proxyBeanMethods参数设置为true时即为:Full 全模式。 该模式下注入容器中的同一个组件无论被取出多少次都是同一个bean实例,即单实例对象,在该模式下SpringBoot每次启动都会判断检查容器中是否存在该组件。
② Lite(proxyBeanMethods = false) :proxyBeanMethods参数设置为false时即为:Lite 轻量级模式。该模式下注入容器中的同一个组件无论被取出多少次都是不同的bean实例,即多实例对象,在该模式下SpringBoot每次启动会跳过检查容器中是否存在该组件。
什么时候用Full全模式,什么时候用Lite轻量级模式?
当在你的同一个Configuration配置类中,注入到容器中的bean实例之间有依赖关系时,建议使用Full全模式;
当在你的同一个Configuration配置类中,注入到容器中的bean实例之间没有依赖关系时,建议使用Lite轻量级模式,以提高springboot的启动速度和性能。
总结:
@Configuation等价于<Beans></Beans>
@Bean 等价于<Bean></Bean>
@ComponentScan等价于<context:component-scan base-package="com.dxz.demo"/>
@Component 等价于<Bean></Bean>
@Bean 与 @Component比较:
● 两个注解的结果是相同的,bean都会被添加到Spring上下文中。
● @Component 标注的是类,允许通过自动扫描发现;@Bean需要在配置类@Configuation中使用。
● @Component类使用的方法或字段时不会使用CGLIB增强;而在@Configuration类中使用方法或字段时则使用CGLIB创建代理对象。
2、@import
@import的参数value接收一个Class数组,通过快速导入的方式实现把实例(以全类名作为id)注册入spring的IOC容器中。
注意:@Import只能用在类上
;@Import注解可以用于导入第三方包。
(1)@Import的三种用法
● 直接填class数组方式
● ImportSelector方式【重点】
● ImportBeanDefinitionRegistrar方式
①第一种用法:直接填class数组
@Import({ 类名.class , 类名.class... })
public class Test {
}
import的bean都将加入到spring的IOC容器中,这些在容器中bean名称是该类的全类名
,比如com.newstar.类名。
②第二种用法:ImportSelector方式
ImportSelector是一个接口,必须要创建一个类来继承实现它。
public class MyImportSelector implements ImportSelector {
//实现接口中方法
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.test.importdemo.Test"}; //一定要写全类名!!!
}
}
参数说明:
●参数: AnnotationMetadata表示当前被@Import注解给标注的所有注解信息(固定写法)。
●返回值:要导入到容器中的组件全类名。
③第三种用法:ImportBeanDefinitionRegistrar方式
同样是一个接口,类似于第二种ImportSelector用法,只不过这种用法比用于自定义化
注册。
public class MyImport implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
//指定bean定义信息(包括bean的类型、作用域...)
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestDemo4.class); //指定bean的类型
//注册一个bean指定bean名字(id)
beanDefinitionRegistry.registerBeanDefinition("TestDemo4444",rootBeanDefinition); //自定义bean的名字
}
}
参数说明:
●第一个参数:annotationMetadata 和之前的ImportSelector参数一样都是表示当前被@Import注解给标注的所有注解信息(固定写法)。
●第二个参数表示用于注册定义一个bean(固定写法)。
示例
//第二种方式
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"newstar.springboot.entity.Book1"}; //一定要写全类名!!!
}
}
//第三种方式
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
//指定bean定义信息(包括bean的类型、作用域...)
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Book2.class); //指定bean的类型
//注册一个bean指定bean名字(id)
beanDefinitionRegistry.registerBeanDefinition("book123",rootBeanDefinition); //自定义bean的名字
}
}
//第一种方式直接填充class
@Import({Book.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
public class Test {
@Bean
public Book booktest(){
return new Book();
}
}
//打印IOC容器中组件名称
public class AnnotationTestDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(Test.class); //这里的参数代表要做操作的类
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames){
System.out.println(name);
}
}
}
结果如下:
类全部注册进IOC容器中。
3、@Conditional
条件装配:@Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,需要注入的Bean满足给定条件才可以注入到Spring IOC容器中
。
(1)标注在类上:@Conditional标注在类上就决定了一批bean是否注入。
//如果WindowsCondition的实现方法返回true,则该类下的所有bean全部注入容器,否则全不注入。
@Conditional({WindowsCondition.class})
@Configuration
public class BeanConfig {
@Bean(name = "bill")
public Person person1(){
return new Person("Bill Gates",62);
}
@Bean("linus")
public Person person2(){
return new Person("Linus",48);
}
}
(2)标注在方法上:@Conditional标注在方法上只能控制一个bean实例是否注入。
@Configuration
public class BeanConfig {
//如果WindowsCondition的实现方法返回true,则注入这个bean
@Conditional({WindowsCondition.class})
@Bean(name = "bill")
public Person person1(){
return new Person("Bill Gates",62);
}
//如果LinuxCondition的实现方法返回true,则注入这个bean
@Conditional({LinuxCondition.class})
@Bean("linus")
public Person person2(){
return new Person("Linus",48);
}
}
@Conditional有许多适用于不同场景的扩展注解如下:
1.class条件注解
@ConditionalOnClass:某个class位于类路径上,才会实例化一个Bean。
@ConditionalOnMissingClass:某个class类路径上不存在的时候,才会实例化一个Bean。
2.Bean条件注解
@ConditionalOnBean:当容器中有指定Bean的条件下进行实例化。
@ConditionalOnMissingBean:当容器里没有指定Bean的条件下进行实例化。
3.属性条件注解
@ConditionalOnProperty:当指定的属性有指定的值时进行实例化。
4.Resource条件注解
@ConditionalOnResource:当类路径下有指定的资源时触发实例化。
5.web条件注解
@ConditionalOnNotWebApplication:不是web应用,才会实例化一个Bean。
@ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。
6.表达式条件注解
@ConditionalOnExpression:基于SpEL表达式的条件判断,当表达式为true的时候,才会实例化一个Bean。
@ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。
@ConditionalOnJndi:在JNDI存在的条件下触发实例化。
@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化。
4、@ImportResource()
@ImportResource注解用于导入Spring的配置文件,让配置文件里面的内容生效
(就是以前写的springmvc.xml、applicationContext.xml或者自定义的xxx.xml)。
Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,不能自动识别;如果想让Spring的配置文件生效加载进来,就必须使用@ImportResource注解。
@ImportResource注解标注在一个配置类上或者主程序入口类上均可
。
(1)配置文件beans.xml
//配置文件beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="book4" class="newstar.springboot.entity.Book4">
<property name="name" value="西游记"/>
<property name="author" value="吴承恩"/>
</bean>
</beans>
(2)配置文件导入生效
//方式一:配置类中导入
@ImportResource("classpath:beans.xml") //beans.xml放在src/resources/目录下
@Configuration //告诉Spring Boot这是一个配置类==配置文件
public class MyConfig {
}
//方式二:在主程序入口类中导入
@ImportResource("classpath:beans.xml")
@SpringBootApplication
public class Application {
public static void main(String[] args) {
...
}
5、@ConfigurationProperties
Spring boot 应用中,当使用注解方式定义一个 bean 时,同时可以利用 @ConfigurationProperties 导入外部属性填充到这个 bean 的实例。
在配置文件 src/main/resources/application.properties 做以下配置:
section1.name=Tom
section2.name=Jerry
section3.name=Dog
(1)方式1 : @ConfigurationProperties + @Component
注解到 bean 定义类上
// 将类定义为一个bean的注解,比如 @Component,@Service,@Controller,@Repository
// 或者 @Configuration
@Component
// 表示使用配置文件中前缀为 section1 的属性的值初始化该bean定义产生的的bean实例的同名属性
// 在使用时这个定义产生的bean时,其属性 name 会是 Tom
@ConfigurationProperties(prefix = "section1")
public class Bean1 {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
(2)方式2 : @ConfigurationProperties + @Bean
注解在配置类的 bean 定义方法上
// 这是一个一般java类,POJO,没有任何注解
public class Bean2 {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 声明为为一个配置类
@configuration
public class Application {
@Bean
// 使用配置文件中前缀为section2的属性的值初始化这里bean定义所产生的bean实例的同名属性,
// 在使用时这个定义产生的bean时,其属性 name 会是 Jerry
@ConfigurationProperties(prefix = "section2")
public Bean2 bean2() {
// 注意,这里的 Bean2 是上面所示的一个POJO类,没有任何注解
return new Bean2();
}
}
(3)方式3 : @ConfigurationProperties 注解到普通类然后通过 @EnableConfigurationProperties 定义为 bean
// 该注解声明如果该类被定义为一个bean,则对应的bean实例的属性值将来自配置文件中前缀为
// section3的同名属性。但是这个注解本身并不会导致该类被作为一个bean注册
@ConfigurationProperties(prefix = "section3")
public class Bean3 {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@SpringBootApplication
// 该注解会将类Bean3作为一个bean定义注册到bean容器,而类Bean3上的注解
// @ConfigurationProperties(prefix = "section3")会导致目标bean
// 实例的属性值使用配置文件中前缀为section3的同名属性值来填充,也就是目标
// bean的属性name的值会是Dog
@EnableConfigurationProperties({Bean3.class})
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}