蓄力--Spring IoC源码分析

目录

Spring整体架构

IoC容器的设计理念

IOC的应用

1.bean的装配方式

xml

@ImportResource

实现FactoryBean

@Component +@ComponentScan 

@Bean+ @Configuration

@Import 

@Conditional

2.bean的依赖注入

查找方式

自动装配注解:

注入方式及原理:

IOC工作原理

Spring源码编译

bean的注册原理

BeanDefinition

BeanDefinitionRegistry 

BeanFactory

DefaultListableBeanFactory 

动态注册bean

IoC启动流程

Bean的生命周期


Spring整体架构

官网地址: https://spring.io/projects/spring-framework

IoC容器的设计理念


IoC(Inverion of Controller)也称为依赖注入(dependency injection,DI)。它是一个对象定义依赖关系的过程,也就是说,对象只通过构造函数参数,工厂方法的参数或对象实例构造或工厂方法返回后在对象实例上设置的属性来定义它们所使用其他对象。然后容器在创建bean时注入这些依赖项。这个过程基本上时bean的逆过程,因此称为控制反转(Ioc)。

在Spring中,构成应用程序主干并由Spring IOC容器管理的对象称为bean。bean是由Spring IOC容器实例化、组装和管理的对象。

IoC容器设计理念:通过容器统一对象的构建方式,并且自动维护对象的依赖关系。

IoC流程图

IOC的应用

1.bean的装配方式

xml

<?xml version="1.0" encoding="UTF-8"?> <beans 
 xmlns="http://www.springframework.org/schema/beans"       
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       
 xsi:schemaLocation="http://www.springframework.org/schema/beans                 
  https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user"  class="bat.ke.qq.com.bean.User"/>
</beans

容器加载xml

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

@ImportResource

@ImportResource("spring.xml") 
public class AppConfig {

}

容器加载

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

实现FactoryBean

public class MyFactroyBean  implements FactoryBean {  
 
   @Override  
   public Object getObject() throws Exception {  
    return new User();  
   }
    
   @Override   
   public Class<?> getObjectType() { 
     return User.class;  
   }
}

思考:FactoryBean和BeanFactory的区别?

AbstractBeanFactory#getObjectForBeanInstance 
!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)

factoryBeanObjectCache : 缓存getObject()获取的单例

@Component +@ComponentScan 

@ComponentScan默认扫描: @Component, @Repository,@Service, @Controller
 

@ComponentScan("org.zhaya.com") 
public class AppConfig { 

}

容器加载

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

@CompentScan 注解扩展用法:

  1. 排除用法 excludedFilters
@ComponentScan(basePackages = "org.zhaya.com",excludeFilters = {  
  @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Service.class}),       
  @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {
    User.class}) 
})

      2.包含用法includeFilters

@ComponentScan(basePackages = "org.zhaya.com",includeFilters = {     
  @ComponentScan.Filter(type = FilterType.CUSTOM,value = {CustomTypeFilter.class}) 
 },useDefaultFilters = false)

FilterType.CUSTOM实现自定义过滤规则
 

public class CustomTypeFilter implements TypeFilter { 
   @Override  
   public boolean match(MetadataReader metadataReader, MetadataReaderFactory     
         metadataReaderFactory) throws IOException {       
         ClassMetadata classMetadata = metadataReader.getClassMetadata();  
          if (classMetadata.getClassName().contains("Service")) {       
                 return true;        }    
            return false;  
  }
 }

@Bean+ @Configuration

@Configuration 
public class AppConfig {
    @Bean 
    public User user(){     
        return new User();   
     }
    @Bean  
    public UserService userService(){  
      // 调用其他@Bean方法 
       return new UserService(user());
    } 
}

思考:配置 @Configuration和不配置的区别? 

不配置@Configuration: 当内部method bean发生彼此依赖的时候会导致多例
@Configuration的作用:

1.表明当前类是一个配置类,是方法bean的源
2.将@Configuration配置的AppConfig的BeanDefinitioin属性赋值为full类型,保证AppConfig类型可 以转变为cglib类型

3.将@Configuration配置的AppConfig由普通类型转变为cglib代理类型,最后会生成cglib代理对象,通过代理对象的方法拦截器,可以解决AppConfig内部方法bean之间发生依赖调用的时候从容器中去获取,避免了多例的出现。 

@Import 

@Import(value = MyImportBeanDefinitionRegistrar.class) 
public class AppConfig { 
}
  • Configuration

导入一个或多个配置类

 @Configuration
 public class ConfigA {
    @Bean    
    public A a() { 
       return new A();   
     } 
}
 @Configuration
 @Import(ConfigA.class) 
 public class ConfigB {
    @Bean    
    public B b() {  
      return new B();
    } 
}
  • ImportSelector
public class MyImportSelector implements ImportSelector { 
  @Override   
  public String[] selectImports(AnnotationMetadata importingClassMetadata) { 
     return new String[]{Fox.class.getName()}; 
   }
 }
  • ImportBeanDefinitionRegister
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {       
    @Override   
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {      
    //创建BeanDefinition    
    RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Zhaya.class);
    // 注册到容器      
    registry.registerBeanDefinition("zhaya",rootBeanDefinition);
   }
 }

@Conditional

@Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册 bean。
 

@Configuration
public class AppConfig {

    @Bean
    private Cat cat() {
        return new Cat();
    }

    @Bean
    @Conditional(value = MyConditional.class)
    public Zhaya zhaya() {
        return new Zhaya();
    }
}

public class MyConditional implements Condition {

    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        if (conditionContext.getBeanFactory().containsBean("cat")) {
            return true;
        }

        return false;
    }
}

2.bean的依赖注入

查找方式

  • byType
  • byName

自动装配注解:

@Autowired

  • @Autowired是spring自带的注解,通过 AutowiredAnnotationBeanPostProcessor 类实现的依 赖注入;
  • @Autowired是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Qualifier;
  • @Autowired有个属性为required,可以配置为false,如果配置为false之后,当没有找到相应 bean的时候,系统不会抛错;
  • @Autowired可以作用在变量、setter方法、构造函数上。

@Resource

  • @Resource是JSR250规范的实现,需要导入javax.annotation实现注入;
  • @Resource是根据名称进行自动装配的,一般会指定一个name属性,当找不到与名称匹配的 bean时才按照类型进行装配
  • @Resource可以作用在变量、setter方法上。

@Inject

  • @Inject是JSR330 (Dependency Injection for Java)中的规范,需要导入javax.inject.Inject;实现注 入。
  • @Inject是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named;
  • @Inject可以作用在变量、setter方法、构造函数上。
<dependency>    
    <groupId>javax.inject</groupId>  
    <artifactId>javax.inject</artifactId> 
    <version>1</version> 
</dependency>

注入方式及原理:

field

注入原理:属性反射

 AbstractAutowireCapableBeanFactory#populateBean 
 AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
 >value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter) 
 >field.set(bean, value)

constructor

不配置@Autowired情况下

  • 当只有一个构造器时,如果构造器入参都是bean,则会执行此构造器(参数会自动注入),如果出 现非bean的入参,则会抛出NoSuchBeanDefinitionException
  • 当显示定义多个构造器时,会默认调用无参构造器,如果没有无参构造器,则会抛出 No default constructor found
  • 当该bean的beanDefinition设置了AutowireMode为3后,则会选择构造器贪婪模式,选择合适的 构造器列表(前提:构造器入参都是bean) 构造bean对象
@Component
public class MyBeanFactoryProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanFactory.getBeanDefinition("userService");
        //构造器贪婪模式  
        beanDefinition.setAutowireMode(3);
    }
}

多构造器筛选时会先排序,构造器排序会先比较方法修饰符(Modifier),然后比较方法参数。同为 public情况下,会选择参数多的构造器构造bean对象。

 AbstractAutowireCapableBeanFactory#createBeanInstance
 ConstructorResolver#autowireConstructor 
 > AutowireUtils.sortConstructors(candidates) 
 >> ConstructorResolver#createArgumentArray     
 >bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse))

setter

不配置@autowired情况下

通过设置AutowireMode为1或者2,会调用setter方法,通过setter方法注入bean
 

 // AutowireCapableBeanFactory 
 int AUTOWIRE_NO = 0;
 int AUTOWIRE_BY_NAME = 1;
 int AUTOWIRE_BY_TYPE = 2;
 int AUTOWIRE_CONSTRUCTOR = 3

注入原理:方法反射

    AbstractAutowireCapableBeanFactory#populateBean
    AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#inject
    > arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter)
    > method.invoke(bean, arguments)

IOC工作原理

https://www.processon.com/view/link/5cd10507e4b085d010929d02

Spring源码编译

环境: idea 2018.2 gradle: 4.10.2 spring framework: 5.2.0

#下载
 git clone https://github.com/spring-projects/spring-framework.git 
cd spring-framework/ 
#编译
 gradlew spring-oxm:compileTestJava

bean的注册原理

思考:bean的属性是什么对象承载的? bean是如何注册到容器中的?

BeanDefinition

容器中的每一个bean都会有一个对应的beanDefinition实例,该实例负责保存bean对象的所有必要信息,包括bean对象的class类型,是否抽象类、构造方法和参数、其他属性等等。

BeanDefinitionRegistry 

BeanDefinition的注册器,抽象了bean的注册逻辑,包含registerBeanDefinition、removeBeanDefinition、getBeanDefinition等注册管理的BeanDefinition的方法。

BeanFactory

bean工厂,抽象了bean的管理逻辑,主要包含getBean、containBean、getType、getAliases等管理bean的方法。

DefaultListableBeanFactory 

Spring IoC的核心类, 即实现了BeanFactory ,也实现了BeanDefinitionRegistry

 #注册BeanDefinition对象 
 public void registerBeanDefinition (String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
            
 } 
 #注册bean对象
 public void registerSingleton (String beanName, Object singletonObject) throws IllegalStateException {

 }

xml Configuration demo
 

        //创建一个简单注册器
        BeanDefinitionRegistry register = new SimpleBeanDefinitionRegistry();
        // 创建一个实现了注册器的工厂
        BeanDefinitionRegistry registry = new DefaultListableBeanFactory();
        //创建bean定义读取器
        BeanDefinitionReader reader = new XmlBeanDefinitionReader(register);
        // 创建资源读取器 
        DefaultResourceLoader resourceLoader = new DefaultResourceLoader(); 
        // 获取资源 //
        Resource xmlResource = resourceLoader.getResource("spring.xml"); 
        // 装载Bean的定义 
        reader.loadBeanDefinitions(xmlResource); 
        reader.loadBeanDefinitions("spring.xml"); 
        // 打印构建的Bean 名称 
        System.out.println(Arrays.toString(register.getBeanDefinitionNames());
        // 工厂调用getBean方法 
        System.out.println(registry.getBean("user"));

java Configuration demo

 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 通过容器获取到beanFactory  即是工厂,又是注册器
 DefaultListableBeanFactory factory = context.getDefaultListableBeanFactory();
  RootBeanDefinition beanDefinition = new RootBeanDefinition(Zhaya.class);
factory.registerBeanDefinition("zhaya", beanDefinition);
 //beanDefinition.setAutowireMode(2);
 // 填充属性
   beanDefinition.getPropertyValues().add("name","zhaya");

动态注册bean

思考:如何动态的将一个普通对象交给Spring管理?

BeanDefinitionRegistryPostProcessor

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

ImportBeanDefinitionRegistrar

利用@Import注解实现

public interface ImportBeanDefinitionRegistrar {
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}

BeanFactoryPostProcessor

public interface BeanFactoryPostProcessor {
 

    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

IoC启动流程

AbstractApplicationContext#refresh

BeanFactoryPostProcessor

  • BeanFactoryPostProcessor
  • BeanDefinitionRegistryPostProcessor
  • ConfigurationClassPostProcessor 

Bean的生命周期

Bean的构建流程 

 

循环依赖

BeanPostProcessor 
Spring后置处理器贯穿整个bean的生命周期: 创建 初始化 销毁
生产bean实例过程中涉及9次调用

销毁bean实例过程中调用bean的销毁后置处理器

  • InstantiationAwareBeanPostProcessor
  • SmartInstantiationAwareBeanPostProcessor
  • MergedBeanDefinitionPostProcessor BeanPostProcessor
  • DestructionAwareBeanPostProcessor

  自动注入@Autowired:
AutowiredAnnotationBeanPostProcessor 

一不小心,肝了一天。蓄力!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值