1、主启动类
package com.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/*
* @SpringBootApplication:表示这是一个springboot应用
* */
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
}
}
2、SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(......)
public @interface SpringBootApplication
2.1、@SpringBootConfiguration
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.boot;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Indexed;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
可以发现SpringBootConfiguration注解的底层是由Configuration注解修饰的,因此有引出来新的问题:
Configuration主要是干什么的?
由**@Configuration**修饰的类就相当于spring中常用的配置文件(bean.xml)
由此可以看出咱使用的SpringBootApplication注解类也是一个配置类
测试
需要的实体类:
package com.boot.pojo;
public class Pet {
private String name;
public Pet() {
}
public Pet(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
'}';
}
}
package com.boot;
import com.boot.pojo.Pet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
/*
* @SpringBootApplication:表示这是一个springboot应用
* */
@SpringBootApplication
public class MyApplication {
@Bean
public Pet getPet(){
return new Pet("Tom");
}
public static void main(String[] args) {
//返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
boolean getPet = run.containsBeanDefinition("getPet");
System.out.println("是否包含Pet组件:"+getPet);
}
}
/***
* OUTPUT:
* 是否包含Pet组件:true
*/
因此可以得出我们的主启动器下也可以作为配置类使用;为了方便维护,与整洁考虑,但一般不建议把该类当做配置类。
2.2、@EnableAutoConfiguration
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration
=======================================================
1、@AutoConfigurationPackage
自动配置包,指定了默认的包规则
@Import({Registrar.class})
public @interface AutoConfigurationPackage
//利用Registrar给容器中导入一系列组件
//将指定的一个包下的所有组件导入进来,MainApplication 所在包下。
2、Registrar.class
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
/**
* (String[])(new AutoConfigurationPackages.PackageImports(metadata))
* .getPackageNames().toArray(new String[0])
* 该语句会获取你创建的主启动器所在的包名
*/
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
}
}
3、AutoConfigurationImportSelector.class
1、利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
2、调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
3、利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
4、从META-INF/spring.factories位置来加载一个文件。默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
package com.boot;
import com.boot.pojo.Pet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
/*
* @SpringBootApplication:表示这是一个springboot应用
* */
@SpringBootApplication
public class MyApplication {
@Bean
public Pet getPet(){
return new Pet("Tom");
}
public static void main(String[] args) {
//返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
boolean getPet = run.containsBeanDefinition("getPet");
System.out.println("是否包含Pet组件:"+getPet);
int beanDefinitionCount = run.getBeanDefinitionCount();
System.out.println("数量是:"+beanDefinitionCount);
boolean helloController = run.containsBeanDefinition("helloController");
System.out.println("是否包含helloController:"+helloController);
}
/**
* 是否包含Pet组件:true
* 数量是:139
* 是否包含helloController:true
*/
}
2.3、@ComponentScan
见名知意:指定扫描哪些,Spring注解
@Repeatable(ComponentScans.class)
public @interface ComponentScan
@Repeatable 注解是用于声明其它类型注解的元注解,来表示这个声明的注解是可重复的。@Repeatable的值是另一个注解,其可以通过这个另一个注解的值来包含这个可重复的注解。
public @interface ComponentScans {
ComponentScan[] value();
}
//其中,@ComponentScan注解上的元注解@Repeatable中的值,使用了@ComponentScans注解,@ComponentScans注解中包含的值类型是一个@ComponentScan注解的数组!这就解释了官方文档中@Repeatable中值的使用。
关于@Repeatable的详细内容请看:https://blog.csdn.net/weixin_42245133/article/details/99678509
2.4、@Import
用于导入组件
有上述可知一些准备工作都由@SpringBootConfiguration的父注解做好了,所以:
@SpringBootApplication
也可以有下面这三个注解代替:
* @SpringBootConfiguration
* @EnableAutoConfiguration
* @ComponentScan("com.boot")
package com.boot.config;
import com.boot.pojo.People;
import com.boot.pojo.Pet;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Import(Pet.class)
@Configuration(proxyBeanMethods = false)
public class MyConfig {
@Bean("tom")
public Pet cat(){
return new Pet("Tom");
}
@Bean("mike")
public People people(){
People mike = new People("mike");
mike.setPet(cat());
return mike;
}
}
package com.boot;
import com.boot.config.MyConfig;
import com.boot.pojo.People;
import com.boot.pojo.Pet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
/*
* @SpringBootApplication:表示这是一个springboot应用
* 也可以有下面这三个注解代替:
* @SpringBootConfiguration
* @EnableAutoConfiguration
* @ComponentScan("com.boot")
* */
//@SpringBootConfiguration
//@EnableAutoConfiguration
//@ComponentScan("com.boot")
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
//返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
String[] names = run.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
boolean tom = run.containsBean("tom");
boolean pet = run.containsBean("com.boot.pojo.Pet");//必须是全限定名,如果是通过import导入的
System.out.println("是否存在(tom):"+tom);
System.out.println("是否存在(pet):"+pet);
}
/**
* 两者是否一样:true
* MyConfig: com.boot.config.MyConfig@757194dc
* 两者是否一样:false
* 是/否: false
*/
}
@Import 高级用法: https://www.bilibili.com/video/BV1gW411W7wy?p=8
3、组件
1、@Configuration
指定是否应代理@Bean方法以强制执行Bean生命周期行为,例如,即使在用户代码中直接调用@Bean方法的情况下也返回共享的单例Bean实例。此功能需要方法拦截,通过运行时生成的CGLIB子类实现,该子类具有一些限制,例如不允许配置类及其方法声明final。
默认值为true,允许通过配置类内的直接方法调用进行“bean间引用”,以及外部调用此配置的@bean方法,例如从另一个配置类进行调用。如果由于此特定配置的@Bean方法都是自包含的,并且设计为容器使用的普通工厂方法,因此不需要这样做,请将此标志切换为false,以避免CGLIB子类处理。
关闭bean方法拦截可以有效地单独处理@bean方法,就像在非@Configuration类上声明时一样,也称为“@bean-Lite模式”(参见@bean的javadoc)。因此,它在行为上等同于删除@Configuration原型。
-
基本使用
-
Full模式与Lite模式
-
- 示例
- 最佳实战
-
-
- 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
- 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
-
1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
2、配置类本身也是组件
3、proxyBeanMethods:代理bean的方法
Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】
组件依赖必须使用Full模式默认。其他默认是否Lite模式
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
//默认是true
boolean proxyBeanMethods() default true;
}
测试一下
1、proxyBeanMethods = true
package com.boot;
import com.boot.pojo.Pet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
/*
* @SpringBootApplication:表示这是一个springboot应用
* */
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
//返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
//当我们一次请求两个比较他们是否一样
Pet pet1 = run.getBean("tom", Pet.class);
Pet pet2 = run.getBean("tom", Pet.class);
System.out.println("两者是否一样:"+(pet1==pet2));
MyConfig bean = run.getBean(MyConfig.class);
System.out.println("MyConfig: "+bean);
People people = bean.people();
People people1 = bean.people();
System.out.println("两者是否一样:"+(people==people1));
Pet cat = run.getBean("cat", Pet.class);
People people2 = run.getBean("mike", People.class);
System.out.println("是/否: "+(people2.getPet()==cat));
}
/**
* 两者是否一样:true
* MyConfig: com.boot.config.MyConfig$$EnhancerBySpringCGLIB$$8c7ff105@9f6e406
* 两者是否一样:true
* 是/否: true
*
* 说明是单例,spring容器中只存在一个实例。
*/
}
2、proxyBeanMethods = false
package com.boot;
import com.boot.config.MyConfig;
import com.boot.pojo.People;
import com.boot.pojo.Pet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
/*
* @SpringBootApplication:表示这是一个springboot应用
* 也可以有下面这三个注解代替:
* @SpringBootConfiguration
* @EnableAutoConfiguration
* @ComponentScan("com.boot")
* */
//@SpringBootConfiguration
//@EnableAutoConfiguration
//@ComponentScan("com.boot")
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
//返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
//当我们一次请求两个比较他们是否一样
Pet pet1 = run.getBean("cat", Pet.class);
Pet pet2 = run.getBean("cat", Pet.class);
System.out.println("两者是否一样:"+(pet1==pet2));
MyConfig bean = run.getBean(MyConfig.class);
System.out.println("MyConfig: "+bean);
People people = bean.people();
People people1 = bean.people();
System.out.println("两者是否一样:"+(people==people1));
Pet cat = run.getBean("cat", Pet.class);
People people2 = run.getBean("mike", People.class);
System.out.println("是/否: "+(people2.getPet()==cat));
}
/**
* 两者是否一样:true
* MyConfig: com.boot.config.MyConfig@757194dc
* 两者是否一样:false
* 是/否: false
*/
}
2、@Bean、@Component、@Controller、@Service、@Repository
3、@ComponentScan、@Import
4、@Conditional
条件装配:满足Conditional指定的条件,则进行组件注入
5、@ImportResource
原生配置文件引入
//如果想引入咱们自己创建的spring配置文件,则需要此注解
@ImportResource("classpath:beans.xml")
public class MyConfig {}
6、配置绑定
pet.name="Tom"
@ConfigurationProperties
package com.boot.pojo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "pet")//这个东西好像有种规范,没仔细研究
public class Pet {
private String name;
public Pet() {
}
public Pet(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
'}';
}
}
package com.boot.config;
import com.boot.pojo.People;
import com.boot.pojo.Pet;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration()
@EnableConfigurationProperties(Pet.class)
public class MyConfig {
@Bean
public Pet cat(){
return new Pet();
}
}
测试
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
//返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
System.out.println(run.getBean("cat"));
}
/**
* Pet{name='"Tom"'}
*/
}
下面是几种搭配:
- @EnableConfigurationProperties + @ConfigurationProperties
- @Component + @ConfigurationProperties