Spring 源码中的扩展点分析

本文深入探讨了Spring框架的IOC容器,从基本概念到依赖注入方式,再到自动装配模式及其优缺点。文章还介绍了Spring中的重要类、扩展点如BeanPostProcessor和BeanFactoryPostProcessor,以及它们在处理注解和对象生命周期中的作用。此外,作者还讨论了Spring源码中的设计模式应用,如简单工厂、单例、代理模式等。
摘要由CSDN通过智能技术生成

     Spring作为开源的框架目前正被互联网行业广泛的使用,在我们在面试的过程中也经常会被问到。这篇博客记录了我在学习spring的IOC容器中遇到的一些琐碎的知识点,并对相关文档进行参考,把它记录下来,巩固和学习,如有错误,欢迎指正。我们经常会被问 什么是spring? 其实很多人都认为spring就是IOC和AOP,其实不然,spring是产品,里面包含很多技术,包括springcloud,springdata,springfremwork等等,IOC和AOP只是spring中核心技术的一部分。

目录

一、spring IOC容器

1、基本内容

1.1、什么是Spring IOC?

1.2、什么是DI(依赖注入)

1.3、为什么要使用spring IOC

1.4、spring有几种编程风格

1.5、Spring依赖注入方式有哪些

1.6、spring的自动装配模式有哪些

1.7、自动装配方式有哪些

1.8、自动装配的优缺点

1.9、ApplicationContext 创建并初始化spring容器

2、spring的beans

2.1、单例和原型

2.2、Singleton的bean中引用了一个Prototype的bean的时候会出现Prototype失效的情况

2.3、spring生命周期回调有哪几种方式,执行顺序是什么

2.4、当spring容器完成初始化之后,想执行某个方法,怎么做

2.5、在spring源码中生命周期初始化回调方法initializeBean做了哪些事情

3、spring注解的一些知识点

3.1、@Autowired注解和自动注入模式的关系

3.2、@Autowired和@Resource的区别

3.3、属性是如何注入的

二、spring中的AOP

三、spring中的重要类

FactoryBean

beanDefintion

四、spring中的扩展点

4.1、BeanPostProcessor

4.2、AutowiredAnnotationBeanPostProcessor

4.3、CommonAnnotationBeanPostProcessor

4.4、BeanFactoryPostProcessor

4.5、BeanDefinitionRegistryPostProcessor

4.6、ConfigurationClassPostProcessor

五、解读spring源码中的知识点

5.1、jdk动态代理实现原理

5.2、cglib代理如何实现

5.3、spring中在哪些地方用到了动态代理

5.4、spring源码中使用了哪些设计模式

5.5、spring中有哪些不能被代理的bean

5.6、FactoryBean和普通bean的区别?

5.7、如何把自己自定义的对象放到spring容器中

5.8、为什么Appconfig类是通过register(Appconfig.class);手动put到map当中呢?为什么不是扫描出来的呢?

5.9、为什么spring当中默认支持循环依赖?或者spring在哪里体现了默认支持循环依赖?

5.10、spring事务不生效有哪些原因

5.11、推断构造方法


一、spring IOC容器

1、基本内容

1.1、什么是Spring IOC?

     首先IOC(Inversion of Control)就是控制反转,官网说法是,IOC也被称为DI(依赖注入)。官网截图如下:

Spring IOC是指:将对象的实例化反转给spring容器,在传统的开发模式中,当我们创建一个对象时,需要new或者newInstance等直接或者间接的方式调用构造方法创建这个对象,这样对象的实例化控制权是由应用程序控制的。而反转就是将这种权利反转给spring容器,spring容器通过工厂模式为程序员创建了所需的对象,程序员无需创建对象(只需要提供对象的类型即可),直接调用spring容器提供的对象就行了,这就是控制反转。

1.2、什么是DI(依赖注入)

依赖注入(DI)是指:spring 使用 java 对象的 set 方法或者带参数的构造方法为我们在创建所需对象时将其属性自动设置所需要的值的过程,就是依赖注入的思想。

1.3、为什么要使用spring IOC

第一:对象的实例化不是一件简单的事情,比如对象的关系比较复杂,依赖关系往往需要程序员去维护,这是一件非常头疼的事;

第二:解耦,由容器去维护具体的对象;

第三:托管了类的产生过程,比如我们需要在类的产生过程中做一些处理,最直接的例子就是代理,如果有容器程序可以把这部分过程交给容器,应用程序则无需去关心类是如何完成代理的。

1.4、spring有几种编程风格

     官网上说spring在1.0 使用xml配置方式,在2.5引入了注解 annotation(注解)配置方式,在3.0引入了javaconfig配置方式。官网说明如下:

1.5、Spring依赖注入方式有哪些

      查看spring官方文档可知,注入方式有两种:

      1、Constructor-based Dependency Injection(构造方法注入)

      官方文档详见:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-constructor-injection

      2、Setter-based Dependency Injection(基于setter的注入方式)

      官方文档详见:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-setter-injection

1.6、spring的自动装配模式有哪些

Spring的自动注入模型有四种:

no(默认)无自动装配。

byName:按照名称进行装配,<bean id="dao" name="dao" class="">   spring会根据name的名字进行装配(默认 id 和name相同),在类中,name的值要与set方法一致  :例如: name="zlu"    setter的方法应该为setZlu()  才能进行自动装配。

byType:按类型进行装配,spring会找 依赖的属性的接口或者父类下的实现类或者子类,进行注入,例如: private IndexDao dao;    spring会找实现了IndexDao接口的类进行注入。

Constructor类似于byType,但适用于构造函数参数。如果容器中没有一个构造函数参数类型的bean,则会引发致命错误,使用Constructor的方式,系统会推断构造方法,选择参数最多的构造方法,解析构造方法的参数(每个参数表示一个依赖项)去找bean。

1.7、自动装配方式有哪些

  有两种方式:在XML中有如下两种配置方式,按照setter的名字对应:

spring也提供了相应的api:

1.8、自动装配的优缺点

    优点:

   (1) 自动装配可以显著减少指定属性或构造函数参数的需要(减少依赖的注入的配置)

   (2) 当对象发生改变会自动更新配置。例如,如果需要向类添加依赖项,在容器中添加bean即可。

详细信息查看官方文档:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-autowire

    缺点:(但是这些缺点对于我来说不能算作缺点)

(1) property和constructor-arg设置中的显式依赖项能够覆盖自动装配(xml中配置的依赖能够使自动装配无效)。

(2)自动装配不如显式注入精确,无法明确记录Spring管理对象之间的关系。

(3) 可能无法为可能从Spring容器生成文档的工具提供连线信息。

(4)容器中的多个bean定义可以匹配setter方法或构造函数参数指定的类型以进行自动装配。对于数组,集合或Map实例,这不

一定是个问题。但是,对于期望单个值的依赖关系,这种模糊性不是任意解决的。如果没有可用的唯一bean定义,则抛出异常。

详细信息查看官方文档:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-autowired-exceptions

1.9、ApplicationContext 创建并初始化spring容器

ApplicationContext可以通过ClassPathXmlApplicationContext和AnnotationConfigApplicationContext创建并初始化容器。

代码如图:

//java config的方式
ApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class);
//xml的方式
ApplicationContext context1 = new ClassPathXmlApplicationContext("spring.xml");

2、spring的beans

2.1、单例和原型

  官方参考文档;https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-scope。我们用的最多的是: singleton:单例(默认),每次获取的hashcode相同; prototype:原型:每次获取的hashcode不同。单例的对象在spring创建和初始化的时候实例化的,spring会将对象放入到一个单例池中(源码中的singletonMap中)缓存起来,在使用时直接去map中获取即可,原型的对象是在getBean的时候实例化的。

2.2、Singleton的bean中引用了一个Prototype的bean的时候会出现Prototype失效的情况

原因是:假设A是单例的,B是原型的,A依赖了B,那么虽然被依赖的对象B是prototype的,但是A对象是singleton的,在运行的过程中 这个A对象只是实例化了一次,因此只有一次机会设置B,每次需要时,容器不能为A提供B的实例。

解决方案:就是放弃控制反转,每次调用B时,为B创建新的实例。

     1、在service类中新写一个方法,在方法上添加@Lookup  ,代码如下:

@Service
@Scope(value = "singleton")
public class IndexServiceImpl  {

    @Autowired
    private IndexDao dao;

    public void query(){
        System.out.println("service:"+this.hashCode());
        getDao().test();
    }

    @Lookup()
    public IndexDao getDao() {
        return null;
    }
}

 (注意:Spring提供了一个名为@Lookup的注解,这是一个作用在方法上的注解,被其标注的方法会被重写,然后根据其返回值的类型,容器调用BeanFactory的getBean()方法来返回一个bean。源码中  在实例化的过程中,会将加了@LookUp的方法放到MethodOverrides set中,beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);生成实例策略时会判断,如果set里面有值,则return instantiateWithMethodInjection(bd, beanName, owner);进入这个方法,cglib代理)

     2、实现接口ApplicationContextAware

     官方参考:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-method-injection

代码如下:

@Service
@Scope(value = "singleton")
public class IndexServiceImpl1 implements ApplicationContextAware {

    ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }

    public void query(){
        System.out.println("service:"+this.hashCode());
        ((IndexDao)applicationContext.getBean("indexDaoImpl")).test();
    }
}

2.3、spring生命周期回调有哪几种方式,执行顺序是什么

  参考文档:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-lifecycle

Spring中实现生命周期的回调有三种方式,一种是注解@PostConstruct和 @PreDestroy,一种是实现接口,InitializingBean,重写afterPropertiesSet()方法,实现接口DisposableBean,重写destroy()方法,还有一种是通过spring提供的xml里面配置一个default-init-method="init"或者      default-destroy-method=“destory”标签,指明方法。这三种方式都能实现spring生命周期的回调,但是他们有一个执行顺序,是注解最先,接口第二,xml指定是第三,为什么呢?因为spring处理生命周期回调是基于spring的生命周期来的,有源码得知,spring先通过一个后置处理器(InitDestroyAnnotationBeanPostProcessor)拿到这个注解解析执行,然后再执行invokeInitMethods方法,在invokeInitMethods方法里面依次执行接口方法(判断bean是否实现了InitializingBean接口)和xml方法

2.4、当spring容器完成初始化之后,想执行某个方法,怎么做

采用生命周期回调。(spring源码)在bea

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值