Bean部分知识

在spring启动时,会默认构建所有的bean并交给IOC容器管理。
获取IOC容器对象
依赖注入的形式获得IOC容器对象,进而获得bean。

private ApplicationContext applicationContext;

获取bean

以类
public class Test{
}
为例
applicationContext.getBean("bean名称-test")
applicationContext.getBean("bean的类型-Test.class")
applicationContext.getBean("bean名称-test","bean类型-Test.class")

bean的作用域

singleton:启动只会创建一个bean(默认),单例bean的初始化以及依赖注入一般都在容器初始化阶段进行。
prototype:每次启动都创建一个新的bean,多例bean 在容器启动时不实例化,即使设置 lazy-init 为 false 也没用,只有调用了getBean()才进行实例化。可以在bean上加@Scope注解来控制bean的作用域,如@Scope(“prototype”)
request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
session:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP session内有效。
global-session:全局session作用域。

第三方bean

  //声明第三方bean
  @Bean 
  //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean
  //通过@Bean注解的name/value属性指定bean名称,如果没指定,默认是方法名
    public SAXReader saxReader(){
        return new SAXReader();
    }

@Bean和@Component有什么区别?
@Component 注解用在类上,表明一个类会作为组件类,并告知Spring要为这个类创建bean,每个类对应一个 Bean。

@Component
public class Student {
	private String name = "lkm";
	public String getName() {
		return name;
	}
}
@Configuration
public class WebSocketConfig {
	@Bean
	public Student student(){
		return new Student();
	}
}

@Bean 注解用在方法上,表示这个方法会返回一个 Bean。@Bean 需要在配置类中使用,即类上需要加上@Configuration注解。
@Bean 注解可将第三方类装配到 Spring 容器中。

bean的起步依赖

传统的创建或者引用项目要导入大量的包和依赖,并且还要避免导入的资源的版本不兼容问题。所以springboot实现了起步依赖,导入一个打包好的资源,而这个资源里面会配置好需要的全部相关配置,从而避免上述问题。
自动装配可以简单理解为:通过注解或者一些简单的配置就能在 Spring Boot 的帮助下实现某块功能

bean自动装配原理

@ComponentScan
@Import
@Import({Person.class})//导入普通类
@Import({Config.class})//导入配置类
//创建一个注解EnableXXXX 这个注解封装了需要的Import注解

 @ComponentScan
/*把用到的资源导入到当前容器中*/
@Import({Person.class})//导入普通类
//@Import({Config.class})//导入配置类
//创建一个注解EnableXXXX 这个注解封装了需要的Import注解
public class App {
	public static void main(String[] args) throws Exception {
		ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
		System.out.println(context.getBean(Person.class));
		context.close();
	}
}
@Configuration
public class Config{
	@Bean
	public Test1 test1(){
		return new Test1();
	}
	@Bean
	public Test2 test2(){
		return new Test2();
	}
}

SpringBootApplication

实现了三个注解

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

@ComponentScan:组件扫描,默认扫描当前引导类所在包及其子包
SpringBootConfiguration注解声明当前也是一个配置类,可以导入第三方Bean

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

EnableAutoConfiguration注解
这个注解实现了import注释
springboot->EnableAutoconfiguration->AutoConfigurationImportSelector.class->重写selectImports方法(加载两个文件,封装到ArrayList当中,最后转成String[])

@Import({AutoConfigurationImportSelector.class})

AutoConfigurationImportSelector类重写了了selectImports方法用以加载合法的Bean,这些类需要被加载到 IOC 容器中

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

为什么说合法的bean,因为bean并不总是同时加载的。可能会被推迟也有可能需要根据某些条件(Conditional注解)才能构建出对应的bean。

@Conditional注解

@ConditionalOnClass(name="类的全类名") 环境中存在这个类才会注册到IOC容器
@Bean
	public Test1 test1(){
		return new Test1();
	}
@ConditionalOnMissingBean
//判断环境中是否有对应的bean,没有才注册到IOC容器 默认代表当前方法的bean,否则要指定参数
@Bean
	public Test1 test1(){
		return new Test1();
	}
@ConditionalOnProperty(name="XXX",havingValue="XXX")
//判断配置文件中是否有对应的属性和值,有才注册bean到IOC
@Bean
	public Test1 test1(){
		return new Test1();
	}

Bean 是线程安全的吗?
Spring 框架中的 Bean 是否线程安全,取决于其作用域和状态。
几乎所有场景的 Bean 作用域都是使用默认的 singleton ,重点关注 singleton 作用域即可。

  • prototype 作用域下,每次获取都会创建一个新的 bean 实例,不存在资源竞争问题,所以不存在线程安全问题。
  • singleton 作用域下,IoC 容器中只有唯一的 bean 实例,可能会存在资源竞争问题(取决于 Bean 是否有状态)。如果这个
    bean 是有状态的话,那就存在线程安全问题(有状态 Bean 是指包含可变的成员变量的对象)。不过,大部分 Bean
    实际都是无状态(没有定义可变的成员变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。
  • 对于有状态单例 Bean 的线程安全问题,常见的有两种解决办法:在 Bean 中尽量避免定义可变的成员变量。在类中定义一个
    ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。

自定义starter

  • 创建starter模块
  • 创建autoconfigure模块,在starter中引入该模块
  • 在autoconfigure模块中定义自动配置功能,实现XXXAutoConfigure配置类将需要自动配置的Bean都配置在这个文件之中
  • 定义自动配置文件META-INF/spring,里面写XXXAutoConfigure配置类的全类名
  • 当其他模块导入这个starter起步依赖的时候,就会扫描META-INF/spring 文件,扫描自动配置类
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值