目錄
1.Bean 的建立生命週期
2.Spring AOP 大致流程
3.Spring 事務
4.Spring 原始碼閱讀前戲
BeanDefinition
BeanDefinitionReader
#AnnotatedBeanDefinitionReader
XmlBeanDefinitionReader
ClassPathBeanDefinitionScanner
BeanFactory
ClassPathXmlApplicationContext
资源加载
事件发布
类型转化
PropertyEditor
ConversionService
TypeConverter
OrderComparator
BeanPostProcessor
BeanFactoryPostProcessor
FactoryBean
ExcludeFilter 和 IncludeFilter
MetadataReader、ClassMetadata、AnnotationMetadata
5.Spring之Bean生命周期源码解析
生成BeanDefinition
合并BeanDefinition
加载类
首頁 Java java教程 java Spring創建Bean的生命週期詳析

java Spring創建Bean的生命週期詳析

Oct 06, 2022 am 09:00 AM
java

本篇文章為大家帶來了關於java的相關知識,其中主要介紹了關於Spring創建Bean的生命週期的相關問題,下面一起來看一下,希望對大家有幫助。

java Spring創建Bean的生命週期詳析

推薦學習:《java影片教學

1.Bean 的建立生命週期

UserService. class —> 無參構造方法(推斷構造方法) —> 普通物件—> 依賴注入(為具有@Autowired的屬性賦值) —> 初始化前(執行帶有@PostConstruct的方法) —> 初始化(執行實作了InitializingBean介面的afterPropertiesSet方法) —> 初始化後(執行AOP相關邏輯) —> 代理物件—> Bean

類似:男生—> 依賴注入—> 男人

##大致過程如下:

    利用該類別的建構方法來實例化得到一個物件(但是如何一個類別中有多個建構方法,Spring 則會進行選擇,這個叫做
  • 推斷建構方法
  • 得到一個物件後,Spring 會判斷該物件中是否存在被
  • @Autowired註解了的屬性,把這些屬性找出來並由Spring進行賦值(依賴注入
  • 依賴注入後,Spring 會判斷該物件是否實作了
  • BeanNameAware 介面、BeanClassLoaderAware介面、BeanFactoryAware 接口,如果實作了,就表示目前物件必須實作該介面中所定義的setBeanName()setBeanClassLoader()setBeanFactory()方法,那麼Spring 就會呼叫這些方法並傳入對應的參數(Aware回呼
  • Aware 回呼後,Spring 會判斷該物件中是否存在某個方法被
  • @PostConstruct註解了,如果存在,Spring 會呼叫當前物件的此方法(初始化前
  • 緊接著,Spring 會判斷該物件是否實現了
  • InitializingBean接口,如果實作了,就表示目前物件必須實作該介面中的afterPropertiesSet()方法,那麼Spring 就會呼叫目前物件中的afterPropertiesSet()方法(初始化
  • 最後,Spring 會判斷當前物件需不需要進行
  • AOP,如果不需要那麼Bean就創建完了,如果需要進行AOP,則會進行動態代理並產生一個代理物件作為Bean(初始化後

#當Spring根據UserService類別來建立一個Bean時:

    如果不用進行AOP,那麼Bean就是UserService類別的建構方法所得到的物件。
  • 如果需要進行AOP,那麼Bean就是UserService的代理類別所實例化得到的對象,而不是UserService本身所得到的對象。

Bean物件建立出來後:

    如果目前Bean是
  • 單例Bean,那麼就會把該Bean對象存入一個Map,Map的key為beanName,value為Bean物件。這樣下次getBean時就可以直接從Map拿到對應的Bean物件了。 (實際上,在Spring原始碼中,這個Map就是單例池
  • 如果當前Bean是原型Bean,那麼後續沒有其他動作,不會存入一個Map,下次getBean時會再執行上述建立過程,得到一個新的Bean物件。

推斷建構方法:

    如果一個類別裡面有無參的建構方法,那麼Spring預設就會用這個無參的構造方法。
  • 如果一個類別裡面只有一個有參的建構方法,那麼Spring就會用這個有參的建構方法。
  • 如果一個類別裡面有多個有參的構造方法,並且沒有無參的構造方法,那麼Spring會報錯。
  • 如果想要指定Spring用哪個建構方法,可以在該建構方法上加上
  • @Autowired

@Bean會覆寫@Compoment

#注意:

如果Spring選擇了一個有參的構造方法,Spring在呼叫這個有參構造方法時,需要傳入參數,那這個參數是怎麼來的呢?

Spring會根據入參的類型和入參的名字去Spring容器中找Bean物件(以單例Bean為例,Spring會從單例池的那個Map中去找):

  • 先根據入參類型找,如果只找到一個,那就直接用來作為入參
  • 如果根據類型找到多個,則再根據入參名字來確定唯一一個
  • 如果最後沒有找到,會報錯,無法建立目前Bean物件

決定用哪個建構方法,決定入參的Bean對象,這個過程就叫做推論建構方法

2.Spring AOP 大致流程

AOP就是進行動態代理,在創建一個Bean的過程中,Spring在最後一步會去判斷目前正在創建的這個Bean是不是需要進行AOP,如果需要則會進行動態代理。

如何判斷目前Bean物件需不需要進行 AOP 操作:

  • #先從Spring容器裡面找出所有的切面Bean。
  • 遍歷每一個切面Bean,再遍歷每個切面Bean中的每一個方法,看看是否寫了@Before@After 等註解。
  • 如果寫了,則判斷該方法所對應的Pointcut是否和當前Bean物件的類別相匹配
  • 如果匹配,則表示當前Bean物件是需要進行AOP 操作的。

上面第三步驟找到匹配的之後,會將匹配的所有方法快取起來,後面在執行切面方法的時候,可以快速從快取中拿出來,提高執行效率。

利用cglib進行AOP的大致流程:

  • #產生代理程式UserServiceProxy,代理類別繼承UserService
  • #代理類別中重寫了父類別的方法,例如UserService中的test()方法代理類別中還會有一個target屬性,該屬性的值為被代理的物件(也就是透過UserService類推斷建構方法實例化出來的對象,進行了依賴注入、初始化等步驟的對象)
  • 代理類別中的test()方法被執行時的邏輯如下:
    • 執行切面邏輯(@Before)
    • 呼叫target.test()

當我們從Spring容器得到UserService的Bean物件時,拿到的就是UserServiceProxy產生的對象,也就是代理對象。

呼叫UserService代理物件.test( ) —> 執行切面邏輯 —> target.test( ),注意target物件不是代理對象,而是被代理的物件。

UserServiceProxy(代理类) ---> 代理对象 ---> 代理对象.target = 普通对象
代理对象.test();

class UserServiceProxy extends UserService {
  
  UserService target;
  
  public void test() {
    // 执行切面逻辑 @Before --> 从匹配的切面方法的缓存中拿出来
    
    target.test(); // 调用普通对象的test方法
    
  }
  
}
登入後複製

3.Spring 事務

當我們在某個方法上加了@Transactional註解後,就表示該方法在呼叫時會開啟Spring事務,而這個方法所在的類別所對應的Bean物件會是該類別的代理物件

Spring交易的代理物件執行某個方法時的步驟:

  • #判斷目前執行的方法是否存在@Transactional註解
  • 如果存在,則利用事務管理器(TransactionMananger)建立一個資料庫連接
  • 修改資料庫連接的autocommit 為false
  • 執行 target.test(),執行程式設計師所寫的業務邏輯程式碼,也就是執行sql
  • 執行完了之後如果沒有出現異常,則提交,否則回滾

Spring事務是否會失效的判斷標準:某個加了@Transactional註解的方法被呼叫時,要判斷到底是不是直接被代理對象調用的,如果是則事務會生效,如果不是則會失效。

UserServiceProxy(代理类) ---> 代理对象 ---> 代理对象.target = 普通对象
代理对象.test();

class UserServiceProxy extends UserService {
  
  UserService target;
  
  public void test() {
    // 1.先看看方法上面有没有加@Transactional
    // 2.通过事务管理器dataSource,创建一个数据库连接conn
    // 3.设置conn.autocommit = false,表示不自动提交事务
    
    target.test(); // 调用普通对象的test方法
    
    conn.commit(); // 如果方法都执行成功,那就手动提交事务
    conn.rollback(); // 如果某个方法执行失败,那就会回滚事务
    
  }
  
}
登入後複製

java Spring創建Bean的生命週期詳析

4.Spring 原始碼閱讀前戲

BeanDefinition

BeanDefinition表示Bean定義,BeanDefinition中存在著許多屬性用來描述一個Bean的特徵。

例如:

  • class,表示Bean類型
  • scope,表示Bean的作用域,單例或原型等
  • lazyInit:表示Bean是否是懶載入
  • initMethodName:表示Bean初始化時要執行的方法
  • destroyMethodName:表示Bean銷毀時要執行的方法還有很多…

宣告式定義Bean:

#可以透過以下幾種方式來定義Bean:

  • #<bean/>
  • @Bean
  • @Component(@Service、@Controller)

也可以透過程式定義Bean

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

// 生成一个BeanDefinition对象,并设置beanClass为User.class,并注册到ApplicationContext中
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
context.registerBeanDefinition("user", beanDefinition);

System.out.println(context.getBean("user"));
登入後複製

也可以透過BeanDefinition設定一個Bean的其他屬性

beanDefinition.setScope("prototype"); // 设置作用域
beanDefinition.setInitMethodName("init"); // 设置初始化方法
beanDefinition.setLazyInit(true); // 设置懒加载
登入後複製

聲明式定義和編程式定義的Bean,最後都會被Spring解析為對應的BeanDefinition對象,並放入Spring容器中。

BeanDefinitionReader

接下來介紹幾個在Spring原始碼中常見的BeanDefinition讀取器(BeanDefinitionReader

#AnnotatedBeanDefinitionReader

#可以直接把某個類別轉換為BeanDefinition,並且會解析該類別上的註解,例如:

#
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);

// 将User.class解析为BeanDefinition
annotatedBeanDefinitionReader.register(User.class);

System.out.println(context.getBean("user"));
登入後複製

它能解析的注解有:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description

XmlBeanDefinitionReader

可以解析<bean/>标签

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
        int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");

        System.out.println(context.getBean("user"));
登入後複製

ClassPathBeanDefinitionScanner

ClassPathBeanDefinitionScanner是扫描器,它的作用和BeanDefinitionReader类似,可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类上如果存在 @Component 注解,那么就会把这个类解析成为一个BeanDefinition

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.refresh();

        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
        scanner.scan("cn.xx");

        System.out.println(context.getBean("user"));
登入後複製

BeanFactory

BeanFactory表示Bean工厂,所以很明显,BeanFactory会负责创建Bean,并且提供获取Bean的API。

而ApplicationContext是BeanFactory的一种,在Spring源码中,是这么定义的:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
  MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
            ...
}
登入後複製

首先,在Java中,接口是可以多继承的,我们发现ApplicationContext继承了ListableBeanFactoryHierarchicalBeanFactory,而 ListableBeanFactory 和HierarchicalBeanFactory 都继承至 BeanFactory,所以我们可以认为 ApplicationContext 继承了BeanFactory,相当于苹果继承水果,宝马继承汽车一样,ApplicationContext 也是 BeanFactory 的一种,拥有 BeanFactory 支持的所有功能,不过 ApplicationContext 比 BeanFactory 更加强大,ApplicationContext 还继承了其他接口,也就表示 ApplicationContext 还拥有其他功能,比如MessageSource 表示国际化,ApplicationEventPublisher 表示事件发布,EnvironmentCapable 表示获取环境变量等等,关于 ApplicationContext 后面再详细讨论。

在Spring的源码中,当我们new一个ApplicationContext时,其底层会new一个BeanFactory,当使用ApplicationContext的某些方法时,比如getBean(),底层调用的就是BeanFactory的getBean()方法。

在Spring源码中,BeanFactory接口存在一个非常重要的实现类是:DefaultListableBeanFactory,也是非常核心的。

所以,我们可以直接使用DefaultListableBeanFactory,而不需要使用 ApplicationContext 的某个实现类,比如:

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(User.class);
        beanFactory.registerBeanDefinition("user", beanDefinition);
        System.out.println(beanFactory.getBean("user"));
登入後複製

DefaultListableBeanFactory是非常强大的,支持很多功能,可以通过查看DefaultListableBeanFactory 的类继承结构图:

java Spring創建Bean的生命週期詳析

  • AliasRegistry:支援別名功能,一個名字可以對應多個別名
  • BeanDefinitionRegistry:可以註冊、儲存、移除、取得某個
  • BeanDefinitionBeanFactory:Bean工廠,可以根據某個bean的名字、或類型、或別名取得某個Bean物件
  • SingletonBeanRegistry:可以直接註冊、取得某個單例Bean
  • SimpleAliasRegistry:它是一個類,實作了AliasRegistry介面中所定義的功能,支援別名功能
  • ListableBeanFactory:在BeanFactory的基礎上,增加了其他功能,可以取得所有BeanDefinition的beanNames,可以根據某個類型取得對應的beanNames,可以根據某個類型取得{類型:對應的Bean}的映射關係
  • HierarchicalBeanFactory:在BeanFactory的基礎上,加入了取得父BeanFactory的功能
  • DefaultSingletonBeanRegistry:它是一個類別,實作了SingletonBeanRegistry接口,擁有了直接註冊、取得某個單例Bean的功能
  • ConfigurableBeanFactory:在HierarchicalBeanFactory和SingletonBeanRegistry的基礎上,新增了設定父BeanFactory、類別載入器(表示可以指定某個類別載入器進行類別的載入)、設定Spring EL表達式解析器(表示該BeanFactory可以解析EL表達式)、設定類型轉換服務(表示該BeanFactory可以進行類型轉換)、可以加入BeanPostProcessor(表示該BeanFactory支援Bean的後置處理器),可以合併BeanDefinition,可以銷毀某個Bean等等功能
  • FactoryBeanRegistrySupport:支援了FactoryBean的功能
  • AutowireCapableBeanFactory:是直接繼承了BeanFactory,在BeanFactory的基礎上,支持在創建Bean的過程中能對Bean進行自動裝配
  • AbstractBeanFactory:實現了ConfigurableBeanFactory接口,繼承了FactoryBeanRegistrySupport,這個BeanFactory的功能已經很全面了,但是不能自動裝配和獲取beanNames
  • ConfigurableListableBeanFactory:繼承了ListableBeanFactory、AutowireCapableBeanFactory、ConfigurFactory、ConfigurFactor
  • AutowireCapableBeanFactory:
  • 繼承了AbstractBeanFactory,實現了AutowireCapableBeanFactory,擁有了自動裝配的功能##DefaultListableBeanFactory:
  • 繼承了AbstractAutowireCapableBeanFactory,實作了BeanListy:
  • 繼承了AbstractAutowireCapableBean約翰功能很強大
  • ApplicationContext

ApplicationContext 是個接口,實際上也是一個BeanFactory,不過比BeanFactory更強大,例如:

    #HierarchicalBeanFactory:
  • 擁有取得父BeanFactory的功能
  • ListableBeanFactory:
  • 擁有取得beanNames的功能
  • #ResourcePatternResolver:
  • 資源載入器,可以一次取得多個資源(檔案資源等等)
  • EnvironmentCapable:
  • 可以取得執行階段環境(沒有設定執行階段環境的功能)
  • ApplicationEventPublisher:
  • 擁有廣播事件的功能(沒有新增事件監聽器的功能)
  • MessageSource:
  • 擁有國際化功能
#ApplicationContext 有兩個比較重要的實現類:

AnnotationConfigApplicationContext
  • ClassPathXmlApplicationContext
  • AnnotationConfigApplicationContext

  • ConfigurableApplicationContext:继承了ApplicationContext接口,增加了 添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能
  • AbstractApplicationContext:实现了ConfigurableApplicationContext接口
  • GenericApplicationContext:继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)
  • AnnotationConfigRegistry:可以单独注册某个为类为BeanDefinition(可以处理该类上的**@Configuration注解**,已经可以处理**@Bean注解**),同时可以扫描
  • AnnotationConfigApplicationContext:继承了GenericApplicationContext,实现了AnnotationConfigRegistry接口,拥有了以上所有的功能

ClassPathXmlApplicationContext

java Spring創建Bean的生命週期詳析

它也是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition

资源加载

ApplicationContext还拥有资源加载的功能,比如,可以直接利用ApplicationContext获取某个文件的内容:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        Resource resource = context.getResource("file:/Users/xiexu/Library/Mobile Documents/com~apple~CloudDocs/SSM/day01/src/main/java/cn/xx/domain/User.java");
        System.out.println(resource.contentLength());

        Resource resource1 = context.getResource("https://www.baidu.com");
        System.out.println(resource1.contentLength());
        System.out.println(resource1.getURL());

        Resource resource2 = context.getResource("classpath:spring.xml");
        System.out.println(resource2.contentLength());
        System.out.println(resource2.getURL());

				// 可以一次性获取多个
        Resource[] resources = context.getResources("classpath:cn/xx/domain/*.class");
        for (Resource resource3 : resources) {
            System.out.println(resource3.contentLength());
            System.out.println(resource3.getFilename());
        }
登入後複製

事件发布

先定义一个事件监听器:

		@Bean
    public ApplicationListener applicationListener() {
        return new ApplicationListener() {
            @Override
            public void onApplicationEvent(ApplicationEvent event) {
                System.out.println("接收到了一个事件");
            }
        };
    }
登入後複製

然后发布一个事件:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        context.publishEvent("kkk");
登入後複製

类型转化

在Spring源码中,有可能需要把String转成其他类型,所以在Spring源码中提供了一些技术来更方便的做对象的类型转化,关于类型转化的应用场景, 后续看源码的过程中会遇到很多。

PropertyEditor

这其实是JDK中提供的类型转化工具

public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        User user = new User();
        user.setName(text);
        this.setValue(user);
    }

}
登入後複製
StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
propertyEditor.setAsText("1");
User value = (User) propertyEditor.getValue();
System.out.println(value);
登入後複製

在Spring容器中注册 PropertyEditor:

		@Bean
    public CustomEditorConfigurer customEditorConfigurer() {
        CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
        Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>();

        /**
         * 表示StringToUserPropertyEditor可以将String转化成User类型,
         * 在Spring源码中,如果发现当前对象是String,而需要的类型是User,
         * 就会使用该PropertyEditor来做类型转化
         */
        propertyEditorMap.put(User.class, StringToUserPropertyEditor.class);
        customEditorConfigurer.setCustomEditors(propertyEditorMap);
        return customEditorConfigurer;
    }
登入後複製

假设现在有如下 Bean:

@Component
public class Test {

    @Value("xiaoming")
    private User user;

    public void test() {
        System.out.println(user);
        System.out.println(user.getName());
    }
}
登入後複製

java Spring創建Bean的生命週期詳析-20220906213724892

ConversionService

Spring中提供的类型转化服务,它比PropertyEditor更强大

public class StringToUserConverter implements ConditionalGenericConverter {

    @Override
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);
    }

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Collections.singleton(new ConvertiblePair(String.class, User.class));
    }

    @Override
    public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        User user = new User();
        user.setName((String) source);
        return user;
    }

}
登入後複製
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToUserConverter());
User value = conversionService.convert("1", User.class);
System.out.println(value);
登入後複製

在Spring中注册ConversionService:

		@Bean
    public ConversionServiceFactoryBean conversionService() {
        ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
        conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));

        return conversionServiceFactoryBean;
    }
登入後複製

TypeConverter

整合了PropertyEditor和ConversionService的功能,是Spring内部用的:

SimpleTypeConverter typeConverter = new SimpleTypeConverter();
        typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());
        User value = typeConverter.convertIfNecessary("xxx", User.class);
        System.out.println(value);
        System.out.println(value.getName());
登入後複製
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
        DefaultConversionService conversionService = new DefaultConversionService();
        conversionService.addConverter(new StringToUserConverter());
        typeConverter.setConversionService(conversionService);
        User value = typeConverter.convertIfNecessary("xxx", User.class);
        System.out.println(value);
        System.out.println(value.getName());
登入後複製

OrderComparator

OrderComparator是Spring所提供的一种比较器,可以根据@Order注解或实现Ordered接口来进行值的比较,从而可以进行排序。

public class A implements Ordered {

    @Override
    public int getOrder() {
        return 3;
    }

    @Override
    public String toString() {
        return this.getClass().getSimpleName();
    }
}
登入後複製
public class B implements Ordered {

    @Override
    public int getOrder() {
        return 2;
    }

    @Override
    public String toString() {
        return this.getClass().getSimpleName();
    }
}
登入後複製
public class Main {

    public static void main(String[] args) {
        A a = new A(); // order=3
        B b = new B(); // order=2

        OrderComparator comparator = new OrderComparator();
        System.out.println(comparator.compare(a, b));  // 1

        List list = new ArrayList<>();
        list.add(a);
        list.add(b);

        // 按order值升序排序
        list.sort(comparator);

        System.out.println(list);  // B,A
    }

}
登入後複製

另外,Spring中还提供了一个OrderComparator的子类:AnnotationAwareOrderComparator,它支持用@Order来指定order值。

比如:

@Order(3)
public class A {

    @Override
    public String toString() {
        return this.getClass().getSimpleName();
    }

}
登入後複製
@Order(2)
public class B {

    @Override
    public String toString() {
        return this.getClass().getSimpleName();
    }

}
登入後複製
public class Main {

    public static void main(String[] args) {
        A a = new A(); // order=3
        B b = new B(); // order=2

        AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
        System.out.println(comparator.compare(a, b)); // 1

        List list = new ArrayList<>();
        list.add(a);
        list.add(b);

        // 按order值升序排序
        list.sort(comparator);

        System.out.println(list); // B,A
    }

}
登入後複製

BeanPostProcessor

BeanPostProcess 表示Bean的后置处理器,我们可以定义一个或多个BeanPostProcessor

@Component
public class XiexuBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println("初始化前");
        }
        return bean;
    }

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

}
登入後複製

一个BeanPostProcessor可以在任意一个Bean初始化前以及初始化后去额外的做一些用户自定义的逻辑,当然,我们可以通过判断beanName来进行针对性处理(针对某个Bean,或某部分Bean)。

我们可以通过定义BeanPostProcessor来干涉Spring创建Bean的过程。

BeanFactoryPostProcessor

BeanFactoryPostProcessor表示Bean工厂的后置处理器,其实和BeanPostProcessor类似,BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程。

比如,我们可以这样定义一个BeanFactoryPostProcessor:

@Component
public class XiexuBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("加工beanFactory");
    }
}
登入後複製

可以在postProcessBeanFactory()方法中对BeanFactory进行加工。

FactoryBean

上面提到,我们可以通过BeanPostPorcessor来干涉Spring创建Bean的过程,但是如果我们想一个Bean完完全全由我们自己来创造,也是可以的,比如通过FactoryBean:

@Component
public class XiexuFactoryBean implements FactoryBean {

    @Override
    public Object getObject() throws Exception {
        User user = new User();

        return user;
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}
登入後複製

通过上面这段代码,我们自己创造了一个User对象,并且它将成为Bean。但是通过这种方式创造出来的User的Bean,只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入。

注意:单例池里面还是原来的xiexuFactoryBean,而通过getObject()方法返回的userBean是存放在factoryBeanObjectCache里面(缓存)。

java Spring創建Bean的生命週期詳析-20220907162114007

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        // 如果beanName加上&,表示获取的是单例池里面的XiexuFactoryBean
        Object bean1 = context.getBean("&xiexuFactoryBean");
        System.out.println(bean1); // cn.xx.domain.XiexuFactoryBean@2de8284b

        // 如果beanName没有加上&,表示获取的是factoryBeanObjectCache缓存里面的userBean
        Object bean2 = context.getBean("xiexuFactoryBean");
        System.out.println(bean2); // cn.xx.domain.User@396e2f39
登入後複製

有同学可能会想到,通过@Bean也可以自己生成一个对象作为Bean,那么和FactoryBean的区别是什么呢?其实在很多场景下他俩是可以替换的,但是站在原理层面来说,区别也很明显,@Bean定义的Bean是会经过完整的Bean生命周期的。

ExcludeFilter 和 IncludeFilter

这两个Filter是Spring扫描过程中用来过滤的。ExcludeFilter 表示排除过滤器IncludeFilter 表示包含过滤器

比如以下配置,表示扫描cn.xx这个包下面的所有类,但是排除UserService类,

就算UserService类上面有@Component注解也不会成为Bean。

@ComponentScan(value = "cn.xx", 
        excludeFilters = {@ComponentScan.Filter(
                type = FilterType.ASSIGNABLE_TYPE, 
                classes = UserService.class)})
public class AppConfig {
}
登入後複製

再比如以下配置,就算UserService类上没有@Component注解,它也会被扫描成为一个Bean。

@ComponentScan(value = "cn.xx",
        includeFilters = {@ComponentScan.Filter(
                type = FilterType.ASSIGNABLE_TYPE,
                classes = UserService.class)})
public class AppConfig {
}
登入後複製

FilterType分为:

  • ANNOTATION:表示是否包含某个注解
  • ASSIGNABLE_TYPE:表示是否是某个类
  • ASPECTJ:表示是否符合某个Aspectj表达式
  • REGEX:表示是否符合某个正则表达式
  • CUSTOM:自定义

在Spring的扫描逻辑中,默认会添加一个AnnotationTypeFilterincludeFilters,表示默认情况下在Spring扫描过程中会认为类上有@Component注解的就是Bean。

MetadataReader、ClassMetadata、AnnotationMetadata

在Spring中需要去解析类的信息,比如类名、类中的方法、类上的注解,这些都可以称之为类的元数据,所以Spring中对类的元数据做了抽象,并提供了一些工具类。

MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader。比如:

public class Test {

    public static void main(String[] args) throws IOException {
        SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();

        // 构造一个MetadataReader
        MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("cn.xx.service.impl.UserServiceImpl");

        // 得到一个ClassMetadata,并获取了类名
        ClassMetadata classMetadata = metadataReader.getClassMetadata();

        System.out.println(classMetadata.getClassName());

        // 获取一个AnnotationMetadata,并获取类上的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        for (String annotationType : annotationMetadata.getAnnotationTypes()) {
            System.out.println(annotationType);
        }
    }
}
登入後複製

5.Spring之Bean生命周期源码解析

Spring 扫描底层流程(doScan方法)

  • 扫描包路径,得到包路径下的所有class文件对象(注意,这里不是指Class对象,而是文件对象,可以理解为File对象)
  • 利用ASM技术解析每个class文件对象,得到class元数据信息
  • 如果当前类和某个excludeFilter匹配,那就排除这个类;如果当前类和某个includeFilter匹配,那就获取这个类(默认情况下,Spring会有一个@Component注解的includeFilter)
  • 进一步进行条件注解@Conditional的匹配筛选
  • 都匹配成功后,根据当前类生成一个ScannedGenericBeanDefinition
  • 然后判断如果该类不是顶级类或者静态内部类,则不通过;如果该类是抽象类或者接口类,则不通过;如果该类是抽象类并且该类中有@Lookup注解的方法,则通过。
  • 最终扫描到某些BeanDefinition
  • 遍历每个BeanDefinition,解析每个类的@Scope内容并设置到对应的BeanDefinition中
  • 设置AnnotationBeanNameGenerator生成beanName(解析@Component注解所指定的beanName,如果没有指定则默认生成「该类名字的第一个字母小写」;如果该类的前两个字母都是大写,则beanName就是该类的名字)
  • 给BeanDefinition对象中的属性赋默认值
  • 解析@Lazy@Primary@DependsOn@Role@Description 等注解并赋值给BeanDefinition对应的属性
  • 判断当前beanName是否存在Spring容器中,如果不存在则把beanName和BeanDefinition注册到Spring容器中(也就是存入beanDefinitionMap);如果存在则会有两种方案:
    • 如果已经存在的BeanDefinition对应的类型和扫描到的BeanDefinition对应的类型相同的话(兼容),则直接返回false而不会抛出异常。
    • 如果已经存在的BeanDefinition对应的类型和扫描到的BeanDefinition对应的类型不相同的话(不兼容),则会报错并抛出异常。
  • 扫描结束。

生成BeanDefinition

  • 首先通过ResourcePatternResolver获得指定包路径下的所有.class文件(Spring源码中将此文件包装成了Resource对象)
  • 遍历每个Resource对象利用MetadataReaderFactory解析Resource对象得到MetadataReader(在Spring源码中MetadataReaderFactory具体的实现类为CachingMetadataReaderFactory,MetadataReader的具体实现类为SimpleMetadataReader)
  • 利用MetadataReader进行excludeFiltersincludeFilters,以及条件注解@Conditional的筛选(某个类上是否存在@Conditional注解,如果存在则调用注解中所指定的类的match方法进行匹配,匹配成功则通过筛选,匹配失败则pass掉)
  • 筛选通过后,基于metadataReader生成ScannedGenericBeanDefinition再基于metadataReader判断对应的类是不是接口或抽象类
  • 如果筛选通过,就表示扫描到了一个Bean,将ScannedGenericBeanDefinition加入结果集

注意:

上面说的是通过扫描得到BeanDefinition对象,我们还可以通过直接定义BeanDefinition,或解析spring.xml文件的<bean>,或者@Bean注解得到BeanDefinition对象。

MetadataReader 表示类的元数据读取器,主要包含了一个AnnotationMetadata,功能有

  • 获取类的名字
  • 获取父类的名字
  • 获取所实现的所有接口名
  • 获取所有内部类的名字
  • 判断是不是抽象类
  • 判断是不是接口
  • 判断是不是一个注解
  • 获取拥有某个注解的方法集合
  • 获取类上添加的所有注解信息
  • 获取类上添加的所有注解类型集合

注意:

CachingMetadataReaderFactory解析某个.class文件得到MetadataReader对象是利用 ASM 技术,并没有加载这个类到JVM中。并且最终得到的ScannedGenericBeanDefinition对象,它的 beanClass 属性存储的是当前类的名字,而不是class对象。(beanClass属性的类型是Object,它即可以存储类的名字,也可以存储类对象)

合并BeanDefinition

通过扫描得到所有的BeanDefinition之后,就可以根据BeanDefinition创建Bean对象了。在Spring中支持父子BeanDefinition,和Java子父类类似。

父子BeanDefinition实际上用得比较少,例如:这么定义的情况下,child是单例Bean。

<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child"/>
登入後複製

但如果是下面这样,child就是原型Bean了。

<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child" parent="parent"/>
登入後複製

因为child的父BeanDefinition是parent,所以会继承parent上所定义的scope属性。

所以在根据child来生成Bean对象之前,需要进行BeanDefinition的合并,才能得到完整的child的BeanDefinition。

加载类

BeanDefinition合并之后,就可以去创建Bean对象了,而创建Bean就必须实例化对象,而实例化就必须先加载当前BeanDefinition所对应的class,在AbstractAutowireCapableBeanFactory类的createBean()方法中,一开始就会调用:

java Spring創建Bean的生命週期詳析-20220926221933600

java Spring創建Bean的生命週期詳析-20220926222050533

public boolean hasBeanClass() {
		// 判断当前BeanDefinition的beanClass属性,是不是Class类型
		return (this.beanClass instanceof Class);
	}
登入後複製

如果beanClass属性的类型是Class,那么就直接返回;如果不是,则会根据类名进行加载(doResolveBeanClass方法所做的事情)

java Spring創建Bean的生命週期詳析-20220926223604150

	@Override
	@Nullable
	public ClassLoader getBeanClassLoader() {
		return this.beanClassLoader;
	}

	@Nullable
	private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
登入後複製

先利用BeanFactory所设置的类加载器来加载类,如果没有设置,则默认使用ClassUtils.getDefaultClassLoader()所返回的类加载器来进行加载。

/** * 获取默认的类加载器 */@Nullablepublic static ClassLoader getDefaultClassLoader() {ClassLoader cl = null;/** * 优先获取线程中的类加载器 * 一开始,tomcat会将自定义的类加载器设置到线程上下文中, * 然后当你走到这一步的时候,就可以获取到线程中的tomcat自定义类加载器 */try {cl = Thread.currentThread().getContextClassLoader();} catch (Throwable ex) {}// 如果线程上下文中的类加载器为空,那就获取ClassUtils类所对应的类加载器if (cl == null) {cl = ClassUtils.class.getClassLoader();if (cl == null) { // 如果类加载器等于null,就说明是引导类加载器// ClassUtils类是被Bootstrap类加载器加载的,则获取系统类加载器try {cl = ClassLoader.getSystemClassLoader();} catch (Throwable ex) {}}}// 返回类加载器return cl;}
登入後複製

ClassUtils.getDefaultClassLoader()

优先返回当前线程中的类加载器如果当前线程中的类加载器为空,则返回ClassUtils类的类加载器如果ClassUtils类的类加载器为空,那么表示是Bootstrap类加载器加载的ClassUtils类,那么则返回系统类加载器 4.实例化前

当前BeanDefinition对应的类加载成功后,就可以实例化对象了,但是…

在实例化对象之前,Spring提供了一个扩展点,允许用户来控制是否在某些Bean实例化之前做一些启动动作。

java Spring創建Bean的生命週期詳析-20220926231603057

java Spring創建Bean的生命週期詳析-20220926232155295

java Spring創建Bean的生命週期詳析-20220926232420898

这个扩展点叫InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation( )。比如:

@Componentpublic class ZhouyuBeanPostProcessor implements InstantiationAwareBeanPostProcessor { @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {    if ("userService".equals(beanName)) {     System.out.println("实例化前");    }    return null;  }  }
登入後複製

以上代码会导致,在userService这个Bean实例化前,会进行打印。

注意:postProcessBeforeInstantiation()是有返回值的,如果这么实现:

@Componentpublic class ZhouyuBeanPostProcessor implements InstantiationAwareBeanPostProcessor { @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {    if ("userService".equals(beanName)) {     System.out.println("实例化前");     return new UserService();    }  return null; }  }
登入後複製

userService这个Bean在实例化前会直接返回一个由我们所定义的UserService对象。如果是这样,表示不需要Spring来实例化了,并且后续的Spring依赖注入也不会进行了,会跳过一些步骤,直接执行初始化后这一步。

5.实例化

在这个步骤中就会根据BeanDefinition去创建一个对象了。

6.BeanDefinition的后置处理

java Spring創建Bean的生命週期詳析-20220926234536686

Bean对象实例化之后,接下来就应该给对象的属性赋值了。在真正给属性赋值之前,Spring又提供了一个扩展点MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition( ),可以对此时的BeanDefinition进行加工,比如:

@Componentpublic class ZhouyuMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor { @Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {  if ("userService".equals(beanName)) {   beanDefinition.getPropertyValues().add("orderService", new OrderService()); // 注入属性  } }  }
登入後複製

在Spring源码中,AutowiredAnnotationBeanPostProcessor 就是一个MergedBeanDefinitionPostProcessor,它的postProcessMergedBeanDefinition()方法中会去查找注入点,并缓存在AutowiredAnnotationBeanPostProcessor对象的一个Map中(injectionMetadataCache)。

7.实例化后

java Spring創建Bean的生命週期詳析-20220927001402231

java Spring創建Bean的生命週期詳析-20220927001432634

在处理完BeanDefinition后,Spring又设计了一个扩展点:InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation( ),比如:

@Componentpublic class ZhouyuInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor { @Override public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {  if ("userService".equals(beanName)) {   UserService userService = (UserService) bean;   userService.test();  }  return true; }}
登入後複製

上述代码就是对userService所实例化出来的对象进行处理。

注意:这个扩展点在Spring源码中基本没有怎么使用。

8.自动注入 9.处理属性

java Spring創建Bean的生命週期詳析-20220927002120020

/** * 这里会调用AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法,会直接给对象中的属性赋值 * AutowiredAnnotationBeanPostProcessor内部并不会处理pvs,直接返回了 * 并不会处理pvs指的是: * 如果当前bean的某些属性已经通过postProcessMergedBeanDefinition方法注入了,那么该属性上面的@Autowired注解应该是无效的, * 因为程序员已经将自定义的值设置到属性里面去了 */
登入後複製

这个步骤中,就会处理@Autowired@Resource@Value等注解,也是通过**InstantiationAwareBeanPostProcessor.postProcessProperties( )**扩展点来实现的。

比如:我们甚至可以实现一个自己的自动注入功能

@Componentpublic class ZhouyuInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {if ("userService".equals(beanName)) {for (Field field : bean.getClass().getFields()) {if (field.isAnnotationPresent(ZhouyuInject.class)) {field.setAccessible(true);try {field.set(bean, "123");} catch (IllegalAccessException e) {e.printStackTrace();}}}}return pvs;}}
登入後複製

10.执行Aware

java Spring創建Bean的生命週期詳析-20220927003155088

java Spring創建Bean的生命週期詳析-20220927003137255

完成了属性赋值之后,Spring会执行一些回调,包括:

BeanNameAware:回传beanName给bean对象BeanClassLoaderAware:回传classLoader给bean对象BeanFactoryAware:回传beanFactory给对象 11.初始化前

java Spring創建Bean的生命週期詳析-20220927003420161

java Spring創建Bean的生命週期詳析-20220927003447488

初始化前,也是Spring提供的一个扩展点:BeanPostProcessor.postProcessBeforeInitialization( ),比如:

@Componentpublic class ZhouyuBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  if ("userService".equals(beanName)) {   System.out.println("初始化前");  }  return bean; }}
登入後複製

利用初始化前,可以对已经进行了依赖注入的Bean进行处理。

在Spring源码中:

InitDestroyAnnotationBeanPostProcessor 会在初始化前这个步骤中执行@PostConstruct的方法,ApplicationContextAwareProcessor 会在初始化前这个步骤中进行其他Aware的回调: EnvironmentAware:回传环境变量EmbeddedValueResolverAware:回传占位符解析器ResourceLoaderAware:回传资源加载器ApplicationEventPublisherAware:回传事件发布器MessageSourceAware:回传国际化资源ApplicationStartupAware:回传应用其他监听对象,可忽略ApplicationContextAware:回传Spring容器ApplicationContext 12.初始化

java Spring創建Bean的生命週期詳析-20220927003759721

java Spring創建Bean的生命週期詳析-20220927003907501

查看当前Bean对象是否实现了InitializingBean接口,如果实现了就调用其afterPropertiesSet()方法执行BeanDefinition中指定的初始化方法 13.初始化后

java Spring創建Bean的生命週期詳析-20220927004002073

java Spring創建Bean的生命週期詳析-20220927004022427

这是Bean创建生命周期中的最后一个步骤,也是Spring提供的一个扩展点:BeanPostProcessor.postProcessAfterInitialization( ),比如:

@Componentpublic class ZhouyuBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  if ("userService".equals(beanName)) {   System.out.println("初始化后");  }  return bean; }}
登入後複製

可以在这个步骤中,对Bean进行最终处理,Spring中的AOP就是基于初始化后实现的,初始化后返回的对象才是最终的Bean对象

14.总结BeanPostProcessor

实例化前:

InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()

实例化

MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()

实例化后:

InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()

自动注入

InstantiationAwareBeanPostProcessor.postProcessProperties()

Aware对象

初始化前:

BeanPostProcessor.postProcessBeforeInitialization()

初始化

初始化后:

BeanPostProcessor.postProcessAfterInitialization()

java Spring創建Bean的生命週期詳析-20220927004746839

推荐学习:《java视频教程

以上是java Spring創建Bean的生命週期詳析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前 By 尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Java 中的平方根 Java 中的平方根 Aug 30, 2024 pm 04:26 PM

Java 中的平方根

Java 中的完美數 Java 中的完美數 Aug 30, 2024 pm 04:28 PM

Java 中的完美數

Java 中的隨機數產生器 Java 中的隨機數產生器 Aug 30, 2024 pm 04:27 PM

Java 中的隨機數產生器

Java中的Weka Java中的Weka Aug 30, 2024 pm 04:28 PM

Java中的Weka

Java 中的阿姆斯壯數 Java 中的阿姆斯壯數 Aug 30, 2024 pm 04:26 PM

Java 中的阿姆斯壯數

Java 中的史密斯數 Java 中的史密斯數 Aug 30, 2024 pm 04:28 PM

Java 中的史密斯數

Java Spring 面試題 Java Spring 面試題 Aug 30, 2024 pm 04:29 PM

Java Spring 面試題

突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

突破或從Java 8流返回?

See all articles