1. 程式人生 > >003-Spring4 擴展分析BeanPostProcessor、BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor

003-Spring4 擴展分析BeanPostProcessor、BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor

code interface ceo override add 每一個 tex per body

一、依賴註入ApplicationContext

方法一、@Autowired

創建一個User,內部使用ApplicationContext

技術分享圖片
@Component
public class User {
    @Autowired
    private ApplicationContext applicationContext;
    public void show() {
        System.out.println("User:"+applicationContext.getClass());
    }
}
View Code

使用

技術分享圖片
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.lhx.spring.kuozhan");
        System.out.println(context.getBean("user"));
//        System.out.println(context.getBean("createUser"));
        User bean = (User) context.getBean("user");
        bean.show();
        context.close();
    }
View Code

方法二、實現ApplicationContextAware接口

技術分享圖片
@Component
public class Book implements ApplicationContextAware{
    private ApplicationContext ApplicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            
this.ApplicationContext=applicationContext; } public void show() { System.out.println("book:"+ApplicationContext.getClass()); } }
View Code

1)內部原理

接口BeanPostProcessor,內部方法,每一個bean初始化都會被執行

  bean初始化屬性完畢後,即依賴裝配完成之後,postProcessBeforeInitialization

  bean初始化在屬性設置之後,Bean init之後觸發的,postProcessAfterInitialization

  作用:回調,返回代理對象等

  如在postProcessBeforeInitialization中返回其他代理對象。

構建一個默認實現【兩個方法不能返回null】

技術分享圖片
package com.lhx.spring.kuozhan;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class EchoBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("--------------postProcessBeforeInitialization-------------" + "bean" + bean.getClass());
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("--------------postProcessBeforeInitialization-------------" + "bean" + bean.getClass());
        return bean;
    }

}
View Code

2)示例

User類

技術分享圖片
@Component
public class User {
    private ApplicationContext applicationContext;

    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    public void init() {
        System.out.println("User init");

    }

    public void show() {
        System.out.println("User:" + applicationContext.getClass());
    }
}
View Code

UserConfig類

技術分享圖片
@Configuration
public class MyConfig {
    @Bean(initMethod = "init")
    public User createUser() {
        return new User();
    }
}
View Code

調用

System.out.println(context.getBean("user"));

查看日誌

User Set屬性
--------------postProcessBeforeInitialization-------------beanclass com.lhx.spring.kuozhan.User
User init
--------------postProcessAfterInitialization-------------beanclass com.lhx.spring.kuozhan.User

3)自行實現ApplicationContextAware,這裏起名為SpringContextAware,邏輯參考ApplicationContextAwareProcessor

技術分享圖片
public interface SpringContextAware {
    public void setApplicationContext(ApplicationContext applicationContext);
}
View Code

編寫ContextBeanPostProcessor

技術分享圖片
package com.lhx.spring.kuozhan;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class ContextBeanPostProcessor implements BeanPostProcessor {
    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof SpringContextAware) {
            SpringContextAware sca = (SpringContextAware) bean;
            sca.setApplicationContext(applicationContext);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        return bean;
    }

}
View Code

實際類使用

技術分享圖片
package com.lhx.spring.kuozhan;

import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class Dog implements SpringContextAware {

    private ApplicationContext applicationContext;

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }


    public void show() {
        System.out.println("Dog:" + applicationContext.getClass());
    }
}
View Code

使用:

context.getBean(Dog.class).show();

4)查看ApplicationContextAware內部實現:

AnnotationConfigApplicationContext→GenericApplicationContext→AbstractApplicationContext

找打refresh方法,prepareBeanFactory,

// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

ApplicationContextAwareProcessor內部

class ApplicationContextAwareProcessor implements BeanPostProcessor

技術分享圖片

方法三、Spring 4.3 新特性,構造方法直接添加,有局限性,與構造方法直接相關

技術分享圖片
@Component
public class Bank {
    private ApplicationContext applicationContext;
    //spring 4.3 提供,與構造方法調用有關
    public Bank(ApplicationContext applicationContext) {
        this.applicationContext=applicationContext;
    }
    public void show() {
        System.out.println("book:"+applicationContext.getClass());
    }
}
View Code

二、容器擴展

2.1、BeanFactoryPostProcessor

在beanFactory之後,BeanFactoryPostProcessor容器初始化之後,只初始化一次,先於所有容器以及BeanPostProcessor

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

示例代碼擴展2

源碼:

AnnotationConfigApplicationContext→GenericApplicationContext→AbstractApplicationContext

找打refresh方法

技術分享圖片
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset ‘active‘ flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring‘s core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }
View Code

2.2、BeanDefinitionRegistryPostProcessor

BeanFactoryPostProcessor的子類BeanDefinitionRegistryPostProcessor

void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

註冊一個Bean到Spring容器中,類似標註了@Componment

示例

新建一個Person類

技術分享圖片
public class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + "]";
    }

}
View Code

MyBeanDefinitionRegistryPostProcessor實現

技術分享圖片
package com.lhx.spring.kuozhan2;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // TODO Auto-generated method stub

    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        for (int i = 0; i < 10; i++) {
            BeanDefinitionBuilder rootBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Person.class);
            rootBeanDefinition.addPropertyValue("name", "admin" + i);
            registry.registerBeanDefinition("person" + i, rootBeanDefinition.getBeanDefinition());
        }

    }

}
View Code

使用

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.lhx.spring.kuozhan2");
        System.out.println(context.getBean("person1"));
        context.getBeansOfType(Person.class).values().forEach(System.out::println);
        context.close();
    }

當然在使用

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.lhx.spring.kuozhan2");

使用context也可以註入

context.registerBeanDefinition(beanName, beanDefinition);
beanDefinition定義可以使用:BeanDefinitionBuilder rootBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Person.class);

代碼地址:https://github.com/bjlhx15/spring-boot.git

003-Spring4 擴展分析BeanPostProcessor、BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor