文章目录
- 一、Spring注入Bean的方式
- 二、Bean的生命周期
- 三、BeanFactory和ApplicationContext
- 四、Spring中的Bean是线程安全的吗
- 五、Spring是如何解决循环依赖的
- 六、Spring启动的加载过程
- 七、Spring容器中的Bean什么时候被实例化
- 八、BeanFactory和FactoryBean的区别
- 总结
一、Spring注入Bean的方式
1、通过@Configuration+@Bean的方式注入
@Configuration
public class MyConfig {
@Bean
public Student getStudent(){
return new Student();
}
}
2、@Import快速给容器导入bean
@Import(value = {PersonA.class})
3、通过实现ImportBeanDefinitionRegistrar接口可以往容器中注入BeanDefinition,从而注入bean,重写registerBeanDefinitions方法。
@Configuration
@Import(value = {MyImportBeanDefinitionRegistrar.class})
public class MyConfig {}
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param importingClassMetadata 当前类的注解信息
* @param registry 完成BeanDefinition的注册
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean company = registry.containsBeanDefinition("com.xinyu.major.Company");
boolean member = registry.containsBeanDefinition("com.xinyu.major.Member");
if(company && member){
BeanDefinition beanDefinition = new RootBeanDefinition(User.class);
registry.registerBeanDefinition("user",beanDefinition);
}
}
}
4、通过实现ImportSelector接口,往Spring容器中批量注入Bean。
@Configuration
@Import(value = {MyImportSelector.class})
public class MyConfig {}
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.xinyu.major.Company",
"com.xinyu.major.Member"};
}
}
5、通过实现FactoryBean接口往Spring容器中注入自定义Bean。
@Configuration
public class MyConfig {
@Bean
public MyFactoryBean getMyFactoryBean() {
return new MyFactoryBean();
}
}
public class MyFactoryBean implements FactoryBean<Monkey> {
@Nullable
@Override
public Monkey getObject() throws Exception {
return new Monkey();
}
@Nullable
@Override
public Class<?> getObjectType() {
return Monkey.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
调用
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfig.class);
Object monkey = app.getBean("getMyFactoryBean");
System.out.println(monkey);
Object monkey1 = app.getBean("&getMyFactoryBean");
System.out.println(monkey1);
Class<?> aClass = app.getBean("&getMyFactoryBean").getClass();
System.out.println(aClass);
6、@Componet+@ComponentScan,@ComponentScan会默认扫描该类所在包下的所有配置类,添加过Spring相关注解的类,@Controller、@Service、@Component等。
@Configuration
@ComponentScan(value = "com.xinyu.major")
public class MyConfig {
}
二、Bean的生命周期
Bean的生命周期主要是创建bean的过程,一个bean的生命周期主要是4个步骤,==实例化、属性注入、初始化、销毁。==但是对于一些复杂的bean的创建,spring会在bean的生命周期中开发很多的接口,可以让你加载bean的时候对bean做一些改变,因此Spring的bean的生命周期总共有以下几步:
- 实现了BeanFactoryPostProcessor接口的bean,在加载其他的bean的时候,会调用这个bean的postProcessBeanFactory方法,可以在这个步骤对bean中的属性去赋值。
- 实现了InstantiationAwareBeanPostProcessor接口的bean,会在实例化bean之前调用postProcessBeforeInstantiation方法。
- 然后再对bean进行实例化。
- 对bean进行属性注入。
- 对bean进行初始化,在初始化中包含了以下几个步骤实现了BeanFactoryAware接口会先调用setBeanFactory方法。实现了BeanNameAware接口,会先调用setBeanName方法。实现了BeanPostProcessor接口,会先调用 postProcessBeforeInitialization方法。实现了InitializingBean接口,会调用afterPropertiesSet方法。然后在进行aop后置处理,通过实现BeanPostProcessor接口,在postProcessAfterInitialization方法中进行动态代理。
- 销毁
三、BeanFactory和ApplicationContext
ApplicationContext包含BeanFactory所有的功能,BeanFactory是ApplicationContext的父接口。
ApplicationContext还提供了以下功能:
- MessageSource,提供国际化的消息访问。
- 资源访问,如URL何文件。
- 事件传播。
- 载入多个上下文,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
BeanFactory采用的是延迟加载形式来注入bean的,只有在使用到某个bean时才对该bean进行加载实例化。ApplicationContext是在容器启动时,一次性创建了所有bean。
相对于BeanFactory,ApplicationContext唯一的不足是占用内存空间,当应用程序配置了较多的bean时,程序启动较慢。
BeanFactory通常以编程的方式被创建,ApplicationContext还能声明的方式创建,如ContextLoader。
ApplicationContext和BeanFactory都支持BeanPostPorcessor、BeanFactoryPostProcessor的使用,但是两者的区别是BeanFactory需要手动注册,ApplicationContext是自动注册。
四、Spring中的Bean是线程安全的吗
Spring中的Bean默认是单例的,单例是被所有线程共享的,所以会存在安全问题。如果想要线程安全,可以设置为多例的bean,一般来说线程不安全是说共享的资源不安全,但是有些bean其实没有资源的概念,并没有可变的状态,比如dao接口,service接口,所以在某种程度上来说spring的单例bean是线程安全的。
五、Spring是如何解决循环依赖的
- 构造函数循环依赖,是无法被解决的,因为不能被实例化。
- setter方式的多例的循环依赖,也是无法被解决的,如果是多例的,在容器初始化的时候,不会去创建,所以早期没有放入到三级缓存中暴露出来,所以无法解决循环依赖,会报错。
- setter方式的单例循环依赖(A依赖B,B依赖A),A实例化->放入三级缓存->依赖注入B->B实例化->B放入三级缓存->依赖注入A->去三级缓存拿A的代理->把代理A放入二级缓存->返回A的代理注入到B->B初始化->走后置通知获得代理B->B的代理放入一级缓存->原生A依赖注入B->A初始化->后置通知,不走代理返回原生A->将原生A放入一级缓存。
六、Spring启动的加载过程
- 读取配置文件。
- 扫描配置文件配置的路径,把路径中的类都封装成BeanDefinition。
- 把BeanDefinition封装成BeanDefinitionMap,key是类名,value是BeanDefinition。
- 通过for循环实例化对象,完成属性注入并放入到容器中通过getBean()得到BeanDefinition通过BeanDefinition通过反射实例化对象放入到factoryBeanObjectCache封装成BeanWrapper属性注入,把对象中加了@Autowired注解的成员变量赋值把对象保存到容器
七、Spring容器中的Bean什么时候被实例化
如果使用BeanFactory作为spring bean的工厂类,则所有的bean都是在第一次使用该bean的时候才被实例化。
如果使用ApplicationContext作为spring bean的工厂类,则分为以下几种情况:
- 如果bean的scope是singleton的,并且lazy-init=false,则Application启动的时候就实例化了所有的bean,并且将实例化的bean放在一个map结构的缓存中,下次再使用该bean的时候直接从这个缓存中取。
- 如果bean的scope是singleton,lazy-init=true,则所有的bean都是在第一次使用该bean的时候才被实例化。
- 如果bean的scope是prototype,则所有的bean都是在第一次使用该bean的时候才被实例化。
八、BeanFactory和FactoryBean的区别
BeanFactory是一个Bean工厂,使用简单工厂模式,是所有spring Bean容器的顶级接口,它为spring 的容器定义了一套规范,并提供像getBean这样的方法从容器中获取肯定的Bean实例。BeanFactory在产生Bean的同时,还提供了解决Bean之间的依赖注入能力,也就是DI。
FactoryBean是一个工厂的Bean,使用工厂方法模式,就是一个接口,主要的功能是动态生成某一个类型的Bean实例,我们可以自定义一个Bean并且加载到IOC容器里面,它提供了一个重要的方法getObject(),这个方法里面就是用来实现动态构造Bean的过程,SpringCloud里面的openFeign组件,客户端的代理类就是使用了FactoryBean来实现的。
总结
把汗水变成珍珠,把梦想变成现实
本文暂时没有评论,来添加一个吧(●'◡'●)