Spring原理分析

一、核心概念

1、什么是BeanDefinition

定义

BeanDefinition表示Bean定义,Spring根据BeanDefinition来创建Bean对象,BeanDefinition有很多属性用来描述Bean。

BeanDefinition重要属性

  • beanClass:表示bean的类型,比如UserService.class、OrderService.class,Spring在创建Bean的过程中会根据此属性来实例化得到对象。

  • scope:表示一个bean的作用域,scope为singleton表示单例,prototype表示原型bean;

  • isLazy:表示一个bean是不是需要懒加载,原型bean的isLazy属性不起作用,懒加载的单例bean,会在第一次getBean的时候生成该bean,非懒加载的单例bean则会在Spring启动过程中直接生成好。

  • dependsOn:表示一个bean在创建之前所依赖的其他bean,在bean创建之前,它所依赖的这些bean得全部创建好。

  • primary:表示一个bean是主bean,在Spring中的一个类型可以多个bean对象,在进行依赖注入时,如果根据类型找到了多个bean。此时会判断这些bean中是否存在一个主bean,如果存在,则直接将这个bean注入给属性。

  • initMethodName:表示一个bean的初始化方法,一个bean的生命周期过程中有一个步骤叫初始化,Spring会在这个步骤中去调用bean的初始化方法,初始化逻辑由程序员自己控制,表示程序员可以自定义逻辑对bean进行加工。

我们平时用到的@Component、@Bean、<bean/>这些都会解析为BeanDefinition。

2、什么是BeanFactory

定义

BeanFactory是一种Spring容器,也叫Bean工厂,它可以来创建Bean、获取Bean,BeanFactory是Spring中非常核心的组件。

BeanDefinition、BeanFactory、Bean关系

BeanFactory将利用BeanDefinition来生成Bean对象,BeanDefinition相当于BeanFactory的原材料,Bean对象就相当于BeanFactory所生产出来的产品。

BeanFactory的核心子接口和实现类

  • ListableBeanFactory:

  • ConfigurableBeanFactory:

  • AutowireCapableBeanFactory:

  • AbstractBeanFactory:

  • DefaultzListableBeanFactory:最重要的,支持单例Bean、支持Bean别名、支持父子 BeanFactory、支持Bean类型转化、支持Bean后置处理、支持FactoryBean、支持自动装配,等待。

3、什么是Bean生命周期

定义

Bean生命周期描述的是Spring中一个Bean创建过程和销毁过程中所经历的步骤,其中Bean创建过程是重点。程序员可以利用Bean生命周期机制对Bean进行自定义加工。

Bean生命周期核心步骤

  1. BeanDefinition对象创建
  2. 构造方法推断选出一个构造方法
  3. 实例化(构造方法反射得到对象)
  4. 属性填充(依赖注入)
  5. 初始化(对其他属性赋值、校验)
  6. 初始化后(AOP、生成代理对象)通过BeanPostProcessor机制实现

4、@Autowired是什么

  • @Autowired表示某个属性是否需要进行依赖注入,可以写在属性和方法上。注解中的required属性默认为ture,表示如果没有对象可以注入给属性则抛异常。

  • @Autowired加在某个属性上,Spring在进行Bean的生命周期过程中,在属性填充这一步,会基于实例化出来的对象,对该对象中加了@Autowired的属性自动给属性赋值。

  • Spring会先根据属性的类型去Spring容器中找出该类型所有的Bean对象,如果找出来多个,则再根据属性的名字从多个中再确定一个。如果required属性为true,并且根据属性信息找不到对象,则直接抛异常。

  • 当@Autowired注解写在某个方法上时,Spring在Bean生命周期的属性填充阶段,会根据方法的参数类型、参数名字从Spring容器找到对象当做方法入参,自动反射调用该方法。

  • @Autowired加在构造方法上时,Spring会在推断构造方法阶段,选择该构造方法来进行实例化,在反射调用构造方法之前,会先跟你构造参数类型、参数名从Spring容器中找到Bean对象,当做构造方法入参。

5、@Resource是什么

  • @Resource注解与@Autowired类似,也是用来进行依赖注入的,@Resource是Java层面所提供的注解,@Autowired是Spring所提供的注解,它们依赖注入的底层实现逻辑也不相同。

  • @Resource注解中有一个name属性,针对name属性是否有值,@Resource的依赖注入底层流程是不同的。

  • @Resource如果那么属性有值,那么Spring会直接根据指定的name值去Spring容器找到Bean对象,如果找到了则成功,如果没找到则报错。

  • 如果@Resource中name属性没有值,则:

    先判断该属性名字在Spring容器中是否存在Bean对象,如果存在则成功找到Bean对象进行注入,如果不存在,则根据属性类型去Spring容器找到Bean对象,知道了一个则进行注入。

6、@Value是什么

  • @Value注解和@Resource、@Autowired类似,也是用来对属性进行依赖注入的,只不过@Value是用来从Properties文件中获取值的,并且@Value可以解析SpEL(Spring表达式)

  • @Value("heyj") 直接将字符串“heyj”赋值给属性,如果属性类型不是String,或无法进行类型转化则报错。

  • @Value(" { heyj } ") 将会把{}中的字符串当做key,从Properties文件中找到对应的value赋值给属性,如果没有找到,则会把"${heyj}"当做普通字符串注入给属性。

  • @Value("#{heyj}") 会将#{}中的字符串当做Spring表达式进行解析,Spring会把“heyj”当做beanName,并从Spring容器中找到对应bean,如果找到则进行属性注入,没找到则报错。

7、FactoryBean是什么

定义

FactoryBean是Spring所提供的一种较灵活的创建Bean的方式,可以通过实现FactoryBean接口中的getObject()方法来返回一个对象,这个对象就是最终的Bean对象。

FactoryBean接口中的方法

Object getObject(): 返回的是Bean对象

boolean isSingleton(): 返回的是否是单例Bean对象

Class getObjectType(): 返回的是Bean对象的类型

@Component("heyj")
public class HeyjFactoryBean implements FactoryBean {
  
  // Bean对象
  @Override
  public Object getObject() throws Exception {
        return new User();
  }
  
  // Bean对象类型
  @Override
  public Class<?> getObjectType() {
    return User.class;
  }
  
  // 所定义的Bean是否是单例
  public boolean isSingleton() {
    return true;
  }
}

FactoryBean 的特殊点:

上述代码,实际上对应来两个Bean对象:

beanName为“heyj”,bean对象为getObject方法返回的User对象;

beanName为“&heyj”,bean对象为HeyjFactoryBean类的实例对象。

  • FactoryBean对象本身也是一个Bean,同时它相当于一个小型工厂,可以生产出另外的Bean。

  • BeanFactory是一个Spring容器,是一个大型工厂,它可以生产出各种各样的Bean。

  • FactoryBean机制被广泛的应用在Spring内部和Spring第三方框架或组件的整合过程中。

8、ApplicatonContext是什么

定义

ApplicatonContext是比BeanFactory更加强大的Spring容器,它既可以创建bean,获取bean,还支持国际化、事件广播、获取资源等BeanFactory不具备的功能。

ApplicatonContext所继承的接口

  • EnvironmentCapable:ApplicatonContext继承了这个接口,表示拥有了获取环境变量的功能,可以通过ApplicationContext获取操作系统环境变量和JVM环境变量。

  • ListableBeanFactory:ApplicatonContext继承了这个接口,就拥有了获取所有beanNames、判断某个beanName是否存在beanDefinition对象、统计BeanDefinition个数,获取某个类型对应的所有beanNames等功能。

  • HierarchicalBeanFactory:ApplicatonContext继承了这个接口,就拥有了获取父BeanFactory、判断某个name是否存在bean对象功能。

  • MessageSource:ApplicatonContext继承了这个接口,就拥有国际化功能,比如可以直接利用MessageSource对象获取某个国际化资源。

  • ApplicationEventPublisher:ApplicatonContext继承了这个接口,就拥有了事件发布功能,可以发布事件,这是ApplicationContext相对于BeanFactory比较突出、常用的功能。

  • ResourcePatternResolver:ApplicatonContext继承了这个接口,就拥有了加载并获取资源的功能,这里的资源可以是文件,图片等某个URL资源都可以。

9、BeanPostProcessor是什么

定义

BeanPostProcessor是Spring所提供的一种扩展机制,可以利用该机制对Bean进行定制加工,在Spring底层源码实现中,也广泛的用到该机制,BeanPostProcessor通常也叫做Bean后置处理器。

BeanPostProcessor在Spring中是一个接口,我们定义一个后置处理器,就是提供一个类实现该接口,在Spring中还存在一些接口继承了BeanPostProcessor,这些子接口是在BeanPostProcessor的基础上增加一些其他的功能。

BeanPostProcessor中的方法

  • postProcessBeforeInitilzation() : 初始化前方法,表示可以利用这个方法来对Bean在初始化前进行自定义加工。

  • postProcess AfterInitilzation() : 初始化后方法,表示可以利用这个方法来对Bean在初始化后进行自定义加工。

InstantiationAwareBeanPostProcessor

是BeanPostProcessor的一个接口,有3个方法:

  • postProcessBeforeInstantiation(): 实例化前

  • postProcessAfterInstantiation():实例化后

  • postProcessProperties():属性注入后

10、AOP是什么

定义

AOP就是面向切面编程,是一种非常适合在无需修改业务代码的前提下,对某个或某些业务增加统一的功能,比如日志记录、权限控制、事务管理等,能很好的是的代码解藕,提高开发效率。

AOP中的核心概念

Advice:可以理解为通知、建议,在Spring中通过定义Advice来定义代理逻辑。

Pointcut:是切点,表示Advice对应的代理逻辑应用在哪个类、哪个方法上。

Advisor:等于Advisor+Pointcut,表示代理逻辑和切点的一个整体,程序员可以定义或者封装一个Advisor,来定义切点和代理逻辑。

Weaving:表示织入,将Advice代理逻辑在源代码级别嵌入到切点的过程。

Target:表示目标对象,也就是被代理对象,在AOP生成的代理对象中会持有目标对象。

Join Point:表示连接点,在Spring AOP中,就是方法的执行点。

AOP的工作原理:

AOP是发生在Bean的生命周期过程中的:

  1. Spring生成bean对象时,先实例化出来一个对象,也就是target对象
  2. 再对target对象进行属性填充
  3. 在初始化后步骤中,会判断target对象有没有对应的切面
  4. 如果有切面,就表示当前target对象需要进行AOP
  5. 通过Cglib或者JDK动态代理机制生成一个代理对象,作为最终的bean对象。
  6. 代理对象中有一个target属性指向来target对象

二、 Bean的创建

bean的创建方式

  • �bean标签xml (不做介绍)

  • @Bean

  • @Component

  • BeanDefinition

  • FactoryBean

@Bean方式

public class Config {
    @Bean
    public User user() {
        return new User();
    }
}
public class User {
}

测试:

    public static void main(String[] args) {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        User user = context.getBean("user", User.class);
        System.out.println(user);
    }

AnnotationConfigApplicationContext的构造方法入参是配置类。

@Component方式

@ComponentScan("com.heyj")
public class Config {
}
@Component
public class User {
}

测试方式同上。配置类上使用注解@ComponentScan指定扫描包路径,然后Spring会扫描该包下带有@Component注解的所有类,并解析为Bean。

同类注解还有@Service,@Rersistory,@Controller等。

BeanDefinition定义Bean

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(User.class);

        context.registerBeanDefinition("user", beanDefinition);
        context.refresh();

        User user = context.getBean("user", User.class);
        System.out.println(user);
    }

使用BeanDefinition,需要制定bean的类型,并且注册到spring容器中。

FactoryBean机制

@Component
public class HeyjFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        Person person = new Person();
        System.out.println(person);
        return person;
    }

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

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

HeyjFactoryBean这个bean也要纳入spring管理。

测试:

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(HeyjFactoryBean.class);

        context.registerBeanDefinition("person", beanDefinition);
        context.refresh();

        Person person = context.getBean("person", Person.class);
        HeyjFactoryBean heyjFactoryBean = context.getBean("&person", HeyjFactoryBean.class);
        System.out.println(person);
        System.out.println(heyjFactoryBean);
    }

其中:

Object getObject(): 返回的是Bean对象

Class getObjectType(): 返回的是Bean对象的类型

如果使用beanName获取bean对象,这个bean对象是getObject的那个对象,&beanName返回是HeyjFactoryBean类型bean。

三、Spring容器

  • 单例池

  • BeanFactory

  • ApplicationContext

  • AnnotationConfigApplicationContext (不可刷新)

  • ClassPathXmlApplicationContext (可刷新)

  • FileSystemXmlApplicationContext

单例池

对于作用域scope为singleton的bean,spring会在启动时就把这些bean准备好放在一个单例池中,ConcurrentHashMap<String, Bean对象>,单例bean不代表spring容器中这个类型bean只有一个。

BeanFactory

BeanFactory就是Bean工厂,生产Bean的,它是一个接口,实现类有DefaultListableBeanFactory.

把普通对象直接注册类单例bean

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.registerSingleton("user", new User());

        User user = beanFactory.getBean("user", User.class);
        System.out.println(user);
    }

也可以注册BeanDefinition

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(User.class);
        beanFactory.registerBeanDefinition("user", beanDefinition);

        User user = beanFactory.getBean("user", User.class);
        System.out.println(user);
    }

ApplicationContext

继承了很多接口,可参考上一章节8小节。

四、Bean创建的生命周期

重要的阶段:

  • 生成BeanDefinition

  • 实例化(实例化前、推断构造方法、实例化后)

  • BeanDefinition的后置处理

  • 填充属性

  • 初始化 (初始化前、初始化、初始化后)

1、Bean后置处理器

通过BeanPostProcessor接口实现

配置类,制定扫描包路径

@ComponentScan("com.heyj")
public class Config {

}

业务类,@Component注解纳入spring容器管理

@Component("userService")
public class UserService {

}

实现BeanPostProcessor接口,并交给Spring容器管理,那么,会在创建bean生命周期的初始化前后调用相应方法。

@Component
public class HeyjBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("调用了postProcessBeforeInitialization    "  +  beanName);
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("调用了postProcessAfterInitialization    "  +  beanName);
        return new Person();
    }
}

测试代码:

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

        UserService userService = context.getBean("userService", UserService.class);
        System.out.println(userService);
    }
}

打印结果

/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/bin/java ...
调用了postProcessBeforeInitialization    config
调用了postProcessAfterInitialization    config
调用了postProcessBeforeInitialization    userService
调用了postProcessAfterInitialization    userService
Exception in thread "main" org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'userService' is expected to be of type 'com.heyj.UserService' but was actually of type 'com.heyj.Person'

说明spring每生产一个bean对象都会调用BeanPostProcessor里的相应方法,并且在创建bean生命周期的最后把一个Person对象返回,导致最后上面日志中的报错现象。postProcessAfterInitialization返回null时spring会做特殊处理。

2、实例化前

通过实现InstantiationAwareBeanPostProcessor接口,重写postProcessBeforeInstantiation方法。

@Component("userService")
public class UserService {
    public UserService() {
        System.out.println("调用构造方法");
    }
}

实现InstantiationAwareBeanPostProcessor接口,重新相应方法。

@Component
public class HeyjBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("userService")) {
            System.out.println("实例化前。。。");
        }
        return null;
    }
}

测试代码

@Component
public class HeyjBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("userService")) {
            System.out.println("实例化前。。。");
        }
        return null;
    }
}

打印结果

实例化前。。。
调用构造方法
com.heyj.UserService@aecb35a

3、实例化--构造方法推断

  • 当有多个构造方法时,会优先选择默认无参数构造方法,如果没有无参构造方法就会报错;

  • 通过@Autowired指定构造方法某一个构造方法,则就使用这个构造方法,如果多个构造方法上都有@Autowired也会报错;

  • 当多个构造方法都有@Autowired(requried=false),则会选择参数多的那一个构造方法。

  • 同等条件多个构造方法,顺序也会有影响,优先前面的。

4、实例化后

实现InstantiationAwareBeanPostProcessor接口重写postProcessAfterInstantiation方法,注意后初始化的接口方法区分。

@Component
public class HeyjBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("userService")) {
            System.out.println("实例化前。。。");
        }
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (beanName.equals("userService")) {
            System.out.println("实例化后");
        }
        return true;
//        return false; // 默认返回true,当返回false时初始化后的所有流程就不走了。
    }
}

验证初始化后 的 属性赋值流程。

@Component("userService")
public class UserService {
    private User user;

    public UserService() {
        System.out.println("调用构造方法");
    }

    @Autowired
    public void setUser(User user) { // 验证初始化后 的 属性赋值流程。
        this.user = user;
        System.out.println("setUser 方法");
    }
}
@Component
public class User {
}

打印结果

实例化前。。。
调用构造方法
实例化后
setUser 方法 //实例化后的 属性赋值,
com.heyj.UserService@5e955596

因为postProcessAfterInstantiation方法返回true,初始化后的属性赋值也执行了。

如果postProcessAfterInstantiation方法返回false,则初始化后的属性赋值不会执行,将打印如下:

实例化前。。。
调用构造方法
实例化后
com.heyj.UserService@5e955596

5、属性赋值

6、初始化

对应的bean的类实现InitializingBean接口,重写afterPropertiesSet方法。

@Component("userService")
public class UserService implements InitializingBean {
    private User user;

    public UserService() {
        System.out.println("调用构造方法");
    }

    @Autowired
    public void setUser(User user) {
        this.user = user;
        System.out.println("setUser 方法");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        //
        System.out.println("初始化,做一些验证的工作");
    }
}

main方法打印如下:

实例化前。。。
调用构造方法
实例化后
setUser 方法
初始化,做一些验证的工作

7、初始化前

可以用@PostConstrut实现,此文不讲这种方式。

实现InstantiationAwareBeanPostProcessor接口的postProcessBeforeInitialization方法

@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("userService")) {
            System.out.println("初始化前。。");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return InstantiationAwareBeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

8、初始化后

同上

实现InstantiationAwareBeanPostProcessor接口的postProcessAfterInitialization方法

@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("userService")) {
            System.out.println("初始化前。。");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("userService")) {
            System.out.println("初始化后--");
        }
        return InstantiationAwareBeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

打印:

实例化前。。。
调用构造方法
实例化后
setUser 方法
初始化前。。
初始化,做一些验证的工作
初始化后--

其实,InstantiationAwareBeanPostProcessor接口也继承了BeanPostProcessor接口。

9、初始化后--AOP

实现BeanPostProcessor接口,重写postProcessAfterInitialization方法:

@Component
public class MyAopBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("userService")) {
            Object proxyInstance = Proxy.newProxyInstance(MyAopBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("AOP 代理逻辑1");
                    method.invoke(bean, args);
                    System.out.println("AOP 代理逻辑2");
                    return null;
                }
            });
            return proxyInstance;
        }
        return bean;
    }
}

注意上述后置处理器需要纳入spring容器管理。

因为jdk动态代理需要接口,所以:

public interface UserServiceInterface {
    public void test();
}

实现上述接口

@Component("userService")
public class UserService implements InitializingBean, UserServiceInterface {
    private User user;

    public UserService() {
        System.out.println("调用构造方法");
    }

    @Autowired
    public void setUser(User user) {
        this.user = user;
        System.out.println("setUser 方法");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        //
        System.out.println("初始化,做一些验证的工作");
    }

    @Override
    public void test() {
        System.out.println("业务逻辑");
    }
}

验证:

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

        UserServiceInterface userServiceInterface = (UserServiceInterface) context.getBean("userService");
        userServiceInterface.test();
    }
}

打印:

实例化前。。。
调用构造方法
实例化后
setUser 方法
初始化前。。
初始化,做一些验证的工作
初始化后--
AOP 代理逻辑1
业务逻辑
AOP 代理逻辑2

五、Spring整合MyBaties原理

Spring整合MyBaties后有如下代码比较常见:

@Mapper
public interface UserMapper {
    
    @Query("select 'helloworld'")
    String getUserById(String id);
}
@Component("userService")
public class UserService {

    @Autowired
    private UserMapper userMapper;
}

因为UserMapper是接口,无法实例化变成spring的bean对象。怎么办?

MyBaties会通过Mapper接口使用动态代理生成一个代理对象,然后交给Spring管理。

实际上,利用FactoryBean接口机制,通过getObject返回代理对象,通过编程的方式自定义BeanDefinition,然后注册到Spring容器中。

如果此时再有多个Mapper接口,是不是还要实现FactoryBean接口弄多个实现类呢?显然不合理。

可以在上述实现类中弄一个mapper接口类型的属性,通过构造方法注入进去。

但是,每个Mapper接口还是定义BeanDefinition,然后注册到spring,还是有大量的重复代码?

此时,可以通过@Mapperscan注解指定mapper接口的包路径,进行文件扫描,遍历class文件生成代理对象,然后注册到spring。

六、循环依赖

循环依赖现象:

@Component("aService")
public class AService {
    @Autowired
    private BService bService;
  
    @Autowired
    private CService cService;
}
@Component("bService")
public class BService {
    @Autowired
    private AService aService;
}

@Component("cService")
public class CService {
    @Autowired
    private AService aService;
}

以上,AService依赖注入BService,而BService又依赖注入AService,这就导致循环依赖的现象。

更严重性的还有 AService依赖了CService,CService又依赖了AService。

以下分析过程:

竖向时间线

AService的Bean生命周期:

  1. creatingSet.add("aService") 表示AService正在创建bean的生命周期中。。。

  2. 实例化(new AService()), AService原始对象 ----> 存入三级缓存

  3. 填充bService属性 ----> 从单例池中找 ----> 找不到 ----> 创建BService的Bean

BService的Bean生命周期:

2.1 实例化(new BService()),BService 原始对象

2.2 填充aService属性 ----> 从代理池中找 |二级缓存----> 找不到 ----> creatingSet中有 ----> 发生循环依赖 ---->用三级缓存中的AService原始对象----> AOP ---->AService 代理对象 ----> 放入二级缓存。

2.3 填充其他属性

2.4 做其他重要事情(AOP)

2.5 放入单例池 Bean对象

    同样的,填充cService属性 ----> 从单例池中找 ----> 找不到 ----> 创建CService的Bean

    CService的bean生命周期:

    2.1 实例化(new CService()),CService 原始对象

    2.2 填充aService属性 ----> 从代理池中找 ----> 找不到 ----> 二级缓存找 ----> 找到AService代理对象

    2.3 填充其他属性

    2.4 做其他重要事情(AOP,此处要判断AService是否已经做了AOP?)

     可以先从二级缓存中取代理对象

    2.5 放入单例池 Bean对象
  1. 填充其他属性

  2. 做其他重要事情(AOP)

  3. 放入单例池 Bean对象

三级缓存

第一级缓存:单例池singletonObjects Map<beanName, Bean对象> 完整的bean

第二级缓存:earlySingletonObjects Map<beanName, Bean对象> 不完整的bean 作用:存放代理对象

第三级缓存:singletonFactories。 Map<beanName, lambda(()->{getEarlyBeanReference(beanName,mbd, bean)})> 作用:AOP

如果使用构造方法进行属性注入时,并且发生循环依赖时,上述三级缓存方案无法解决,因为相当于在实例化之前就要拿到依赖属性的bean,上述不适合了。可以使用@Lazy注解解决,懒加载依赖。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容