Spring一些基础知识点

1.BeanFactory与ApplicationContext区别

先看下接口继承/实现关系
在这里插入图片描述
这里可以清楚看到ApplicationContext是BeanFactory接口的一个子接口,当然ApplicationContext下也有很多子接口与实现类,这里我列举了一个配置的子接口(ConfigurableApplicationContext)。

在spring中BeanFactory是IoC容器的顶层接⼝,它只是⽤来定义⼀些基础功能,定义⼀些基础规范,ApplicationContext是它的⼀个⼦接⼝,所以ApplicationContext是具备BeanFactory提供的全部功能的。
通常,我们称BeanFactory为SpringIOC的基础容器,ApplicationContext是容器的⾼级接⼝,⽐BeanFactory要拥有更多的功能,⽐如说国际化⽀持和资源访问(xml,java配置类)等等。

2.BeanFactory与FactoryBean的区别

在上面问题简述了BeanFactory,我们这里主要看下FactoryBean。

Spring中Bean有两种,⼀种是普通Bean,⼀种是⼯⼚Bean(FactoryBean),FactoryBean可以⽣成某⼀个类型的Bean实例(返回给我们),也就是说我们可以借助于它⾃定义Bean的创建过程。

Bean创建的三种⽅式中的静态⽅法和实例化⽅法和FactoryBean作⽤类似,FactoryBean使⽤较多,尤其在Spring框架⼀些组件中会使⽤,还有其他框架和Spring框架整合时使⽤。

FactoryBean


 // 可以让我们⾃定义Bean的创建过程(完成复杂Bean的定义)
public interface FactoryBean<T> {

// 返回FactoryBean创建的Bean实例,如果isSingleton返回true,则该实例会放到Spring容器的单例对象缓存池中Map
	@Nullable
	T getObject() throws Exception;

 // 返回FactoryBean创建的Bean类型
	@Nullable
	Class<?> getObjectType();
	
  // 返回作⽤域是否单例
	default boolean isSingleton() {
		return true;
	}

}

FactoryBeanTest (用于生产自定义Bean)

@Component
public class FactoryBeanTest implements FactoryBean<BeanInfo> {

    @Override
    public Class<?> getObjectType() {
        return BeanInfo.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public BeanInfo getObject() throws Exception {
        return new BeanInfo();
    }
}


测试

    @Test
	public void test() {
		FactoryBeanTest bean1 = applicationContext.getBean(FactoryBeanTest.class);
		try {
		    // 这里产生的就是BeanInfo对象(自定义bean)
			BeanInfo object = bean1.getObject();
		} catch (Exception e) {
			e.printStackTrace();
		}
    }

BeanFactory接⼝是容器的顶级接⼝,定义了容器的⼀些基础⾏为,负责⽣产和管理Bean的⼀个⼯⼚,具体使⽤它下⾯的⼦接⼝类型,⽐如ApplicationContext

FactoryBean是个bean,在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,是一个可以生产对象和装饰对象的工厂bean,由spring管理后,生产的对象是由getObject()方法决定的(返回自定义bean)。

3.后置处理器

Spring提供了两种后处理bean的扩展接⼝,分别为 BeanPostProcessor 和
BeanFactoryPostProcessor

BeanPostProcessor

BeanPostProcessor是针对Bean级别的处理,可以针对某个具体的Bean
接口主要有以下两个方法:

     /**
     * Bean初始化前执行
     * @param bean 第一个参数是每个bean的实例
     * @param beanName 第二个参数是每个bean的name或者id属性的值
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return null;
    }

    /**
     * Bean初始化后执行
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return null;
    }

该接⼝提供了两个⽅法,分别在Bean的初始化⽅法前和初始化⽅法后执⾏
初始化定义:

  1. bean实现了InitializingBean接口,对应的方法为afterPropertiesSet
  2. 在bean定义的时候,通过init-method设置的方法

定义⼀个类实现了BeanPostProcessor,默认是会对整个Spring容器中所有的bean进⾏处理。如果要对具体的某个bean处理,可以通过⽅法参数判断,两个类型参数分别为Object和String。

这里需要注意:BeanPostProcessor是在spring容器加载了bean的定义文件并且实例化bean之后执行的。BeanPostProcessor的执行顺序是在BeanFactoryPostProcessor之后。

BeanFactoryPostProcessor

接口只有一个方法:

public interface BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean factory after its standard
	 * initialization. All bean definitions will have been loaded, but no beans
	 * will have been instantiated yet. This allows for overriding or adding
	 * properties even to eager-initializing beans.
	 * @param beanFactory the bean factory used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

实现该接口,可以在spring的bean创建之前,修改bean的定义属性。也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置’order’属性来控制各个BeanFactoryPostProcessor的执行次序。

注意:
BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息。

4.Bean初始化流程

在这里插入图片描述
1)根据配置情况调⽤ Bean 构造⽅法或⼯⼚⽅法实例化 Bean。
2)利⽤依赖注⼊完成 Bean 中所有属性值的配置注⼊。
3)如果 Bean 实现了 BeanNameAware 接⼝,则 Spring 调⽤ Bean 的 setBeanName() ⽅法传⼊当前 Bean 的 id 值。
4)如果 Bean 实现了 BeanFactoryAware 接⼝,则 Spring 调⽤ setBeanFactory() ⽅法传⼊当前⼯⼚实例的引⽤。
5)如果 Bean 实现了 ApplicationContextAware 接⼝,则 Spring 调⽤ setApplicationContext() ⽅法传⼊
当前 ApplicationContext 实例的引⽤。
6)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调⽤该接⼝的预初始化⽅法
postProcessBeforeInitialzation() 对 Bean 进⾏加⼯操作,此处⾮常重要,Spring 的 AOP 就是利⽤它实现的。
7)如果 Bean 实现了 InitializingBean 接⼝,则 Spring 将调⽤ afterPropertiesSet() ⽅法。
8)如果在配置⽂件中通过 init-method 属性指定了初始化⽅法,则调⽤该初始化⽅法。
9)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调⽤该接⼝的初始化⽅法 postProcessAfterInitialization()。此时,Bean 已经可以被应⽤系统使⽤了。
10)如果在 中指定了该 Bean 的作⽤范围为 scope=“singleton”,则将该 Bean 放⼊ Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的⽣命周期管理;如果在 中指定了该 Bean 的作⽤范围为 scope=“prototype”,则将该 Bean 交给调⽤者,调⽤者管理该 Bean 的⽣命周期,Spring 不再管理该 Bean。
11)如果 Bean 实现了 DisposableBean 接⼝,则 Spring 会调⽤ destory() ⽅法将 Spring 中的 Bean 销毁;如果在配置⽂件中通过 destory-method 属性指定了 Bean 的销毁⽅法,则 Spring 将调⽤该⽅法对 Bean 进⾏销毁。

注意:Spring 为 Bean 提供了细致全⾯的⽣命周期过程,通过实现特定的接⼝或 的属性设置,都可以对 Bean 的⽣命周期过程产⽣影响。
虽然可以随意配置 的属性,但是建议不要过多地使⽤ Bean 实现接⼝,因为这样会导致代码和 Spring 的聚合过于紧密

5.AOP相关

  • Spring 实现AOP思想使⽤的是动态代理技术
  • 默认情况下,Spring会根据被代理对象是否实现接⼝来选择使⽤JDK还是CGLIB。当被代理对象没有实现任何接⼝时,Spring会选择CGLIB。当被代理对象实现了接⼝,Spring会选择JDK官⽅的代理技术。
  • 大致流程
  1. @EnableAspectJAutoProxy 开启AOP功能
  2. @EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
  3. AnnotationAwareAspectJAutoProxyCreator是一个后置处理器;
  4. 容器的创建流程:
    4.1. registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
    4.2 finishBeanFactoryInitialization()初始化剩下的单实例bean
    4.2.1 创建业务逻辑组件和切面组件
    4.2.2 AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
    4.2.3 组件创建完之后,判断组件是否需要增强是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib);
  5. 执行目标方法:
    5.1 代理对象执行目标方法
    5.2 CglibAopProxy.intercept();
    5.2.1 得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
    5.2.2 利用拦截器的链式机制,依次进入每一个拦截器进行执行;
    5.2.3 效果:
    正常执行:前置通知-》目标方法-》后置通知-》返回通知
    出现异常:前置通知-》目标方法-》后置通知-》异常通知

6.@AutoWired注解自动装配的过程是怎样的?

使用@ Autowired注解来自动装配指定的bean。在使用@ Autowired注解之前需要在 Spring配置文件进行配置,< context:annotation-config/>在启动 spring IOC时,容器自动装载了一个 AutowiredAnnotation Bean PostProcessor后置处理器,当容器扫描到
@ Autowied、@ Resource或@Inject时,就会在loC容器自动查找需要的bean,并装配给该对象的属性。在使用@ Autowired时,首先在容器中查询对应类型的bean:

  • 如果查询结果刚好为一个,就将该bean装配给@Autowired指定数据
  • 如果查询结果不止一个,那么@Autowired会根据名称查找
  • 如果上述查找结果为空,那么就会抛出异常

7. Spring 是如何解决循环依赖的?

Spring 循环依赖的场景有:

  • 构造器循环依赖
  • Field属性循环依赖

其中构造器循环依赖问题比较难解决,会抛出BeanCurrentlyInCreationException,在解决属性循环依赖时,spring采用的是提前暴露对象的方法(使用三级缓存)
假设BeanA 与 BeanB 互相依赖
在这里插入图片描述

  • singletonObjects:第一级缓存,里面放置的是实例化好的单例对象;
  • earlySingletonObjects:第二级缓存,里面存放的是提前曝光的单例对象;
  • singletonFactories:第三级缓存,里面存放的是要被实例化的对象的对象工厂。

8. @Bean 和 @Component的区别

  • @Component注解表明一个类会作为组件类,并告知Spring要为这个类创建bean。
  • @Bean注解告诉Spring这个方法将会返回一个对象,这个对象要注册为Spring应用上下文中的bean。通常方法体中包含了最终产生bean实例的逻辑。

两者对比:
相同点:
两者的结果都是为spring容器注册Bean.
不同点:
@Component 通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中。
@Bean 注解通常是我们在标有该注解的方法中定义产生这个bean的逻辑。

@Bean 需要在配置类中使用,即类上需要加上@Configuration注解

@Configuration
public class WebSocketConfig {
    @Bean
    public Student student(){
        return new Student();
    }
}

那为什么有了@Compent,还需要@Bean呢?
如果你想要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添加@Component注解的,因此就不能使用自动化装配的方案了,但是我们可以使用@Bean,当然也可以使用XML配置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值