一張圖搞懂Spring bean的完整生命週期

圖形介紹

Spring Bean的完整生命週期從創建Spring容器開始,直到最終Spring容器銷燬Bean,生命週期時序圖如下:
1
在這裏插入圖片描述

生命週期接口分類

Bean的生命週期經歷了多個接口方法的調用,這些接口和方法可分爲以下四類:
1、Bean自身方法
  通過的init-method和destroy-method或註解@PostConstruct與@PreDestroy 指定的方法
2、Bean級生命週期接口
  包括BeanNameAware、BeanFactoryAware、InitializingBean、DiposableBean

// 獲取bean名稱
public interface BeanNameAware extends Aware {
    void setBeanName(String name);
}
// 獲取BeanFactory對象
public interface BeanFactoryAware extends Aware {
    void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
// 對象初始化,與init-method屬性作用相同
public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}
// 對象銷燬,與destroy-method屬性作用相同
public interface DisposableBean {
    void destroy() throws Exception;
}

3、容器級生命週期接口
  包括InstantiationAwareBeanPostProcessor 、BeanPostProcessor,注意:InstantiationAwareBeanPostProcessor繼承自BeanPostProcessor,實際中使用InstantiationAwareBeanPostProcessorAdapter提供空實現,從而方便使用

// 對象實例化生命週期接口
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
    Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
    boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
    PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
            throws BeansException;
}
// 對象初始化生命週期接口
public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

4、BeanFactory後處理器接口
  包括BeanFactoryPostProcessor

// 工廠後處理接口,用於修改bean配置(BeanDefinition)
public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

生命週期示例演示

Spring 依賴注入時,什麼時候會創建代理類
Bean

@Component
public class Person implements BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean {    
    private String name;    
    @Value("shanghai")
    private String address;    
    @Value("123")
    private int phone;
    private BeanFactory beanFactory;
    private String beanName;
    public Person() {
        System.out.println("【構造器】調用Person的構造器實例化");
    }
    public String getName() {
        return name; 
    }
    @Autowired
    public void setName(@Value("matt") String name) {
        System.out.println("【注入屬性】注入屬性name");
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        System.out.println("【注入屬性】注入屬性address");
        this.address = address;
    }
    public int getPhone() {
        return phone;
    }
    public void setPhone(int phone) {
        System.out.println("【注入屬性】注入屬性phone");
        this.phone = phone;
    }
    @Override
    public String toString() {
        return "Person [address=" + address + ", name=" + name + ", phone="
                + phone + "]";
    }

    // 這是BeanFactoryAware接口方法
    @Override
    public void setBeanFactory(BeanFactory arg0) throws BeansException {
        System.out
                .println("【BeanFactoryAware接口】調用BeanFactoryAware.setBeanFactory()");
        this.beanFactory = arg0;
    }
    // 這是BeanNameAware接口方法
    @Override
    public void setBeanName(String arg0) {
        System.out.println("【BeanNameAware接口】調用BeanNameAware.setBeanName()");
        this.beanName = arg0;
    }
    // 這是InitializingBean接口方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out
                .println("【InitializingBean接口】調用InitializingBean.afterPropertiesSet()");
    }
    // 這是DiposibleBean接口方法
    @Override
    public void destroy() throws Exception {
        System.out.println("【DiposibleBean接口】調用DiposibleBean.destory()");
    }
    // 通過<bean>的init-method屬性指定的初始化方法
    @PostConstruct
    public void myInit() {
        System.out.println("【init-method】調用<bean>的init-method屬性指定的初始化方法");
    }
    // 通過<bean>的destroy-method屬性指定的初始化方法
    @PreDestroy
    public void myDestory() {
        System.out.println("【destroy-method】調用<bean>的destroy-method屬性指定的初始化方法");
    }
}

BeanFactoryPostProcessor

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    public MyBeanFactoryPostProcessor() {
        super();
        System.out.println("這是BeanFactoryPostProcessor實現類構造器!!");
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
            throws BeansException {
        System.out
                .println("BeanFactoryPostProcessor調用postProcessBeanFactory方法");
        BeanDefinition bd = arg0.getBeanDefinition("person");
        bd.getPropertyValues().addPropertyValue("phone", "110");
    }
}

InstantiationAwareBeanPostProcessor

@Component
public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    public MyInstantiationAwareBeanPostProcessor() {
        super();
        System.out.println("這是InstantiationAwareBeanPostProcessorAdapter實現類構造器!!");
    }
    // 接口方法、實例化Bean之前調用
    @Override
    public Object postProcessBeforeInstantiation(Class beanClass,
            String beanName) throws BeansException {
        System.out.println("InstantiationAwareBeanPostProcessor調用postProcessBeforeInstantiation方法");
        return null;
    }    
    // 接口方法、實例化Bean之後調用
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("InstantiationAwareBeanPostProcessor調用postProcessAfterInstantiation方法");
        return true;
    }
    // 接口方法、設置某個屬性時調用
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
        System.out.println("InstantiationAwareBeanPostProcessor調用postProcessPropertyValues方法");
        return pvs;
    }
}

BeanPostProcessor

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    public MyBeanPostProcessor() {
        super();
        System.out.println("這是BeanPostProcessor實現類構造器!!");
    }
    @Override
    public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeansException {
        System.out.println("BeanPostProcessor接口方法postProcessAfterInitialization對屬性進行更改!");
        return arg0;
    }
    @Override
    public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException {
        System.out.println("BeanPostProcessor接口方法postProcessBeforeInitialization對屬性進行更改!");
        return arg0;
    }
}

配置

<context:component-scan base-package="cn.matt.lifecircle"/>

測試

public class BeanLifeTest {

    @Test
    public void test() {
        System.out.println("現在開始初始化容器");
        
        ApplicationContext factory = new ClassPathXmlApplicationContext("spring-context-lifecircle.xml");
        System.out.println("容器初始化成功");    
        //得到Preson,並使用
        Person person = factory.getBean("person",Person.class);
        System.out.println(person);
        
        System.out.println("現在開始關閉容器!");
        ((ClassPathXmlApplicationContext)factory).registerShutdownHook();
    }
}

運行結果

現在開始初始化容器
這是BeanFactoryPostProcessor實現類構造器!!
BeanFactoryPostProcessor調用postProcessBeanFactory方法
這是BeanPostProcessor實現類構造器!!
這是InstantiationAwareBeanPostProcessorAdapter實現類構造器!!
InstantiationAwareBeanPostProcessor調用postProcessBeforeInstantiation方法
【構造器】調用Person的構造器實例化
InstantiationAwareBeanPostProcessor調用postProcessAfterInstantiation方法
InstantiationAwareBeanPostProcessor調用postProcessPropertyValues方法
【注入屬性】注入屬性name
【注入屬性】注入屬性phone
【BeanNameAware接口】調用BeanNameAware.setBeanName()
【BeanFactoryAware接口】調用BeanFactoryAware.setBeanFactory()
BeanPostProcessor接口方法postProcessBeforeInitialization對屬性進行更改!
【init-method】調用<bean>的init-method屬性指定的初始化方法
【InitializingBean接口】調用InitializingBean.afterPropertiesSet()
BeanPostProcessor接口方法postProcessAfterInitialization對屬性進行更改!
InstantiationAwareBeanPostProcessor調用postProcessAfterInitialization方法
容器初始化成功
Person [address=shanghai, name=matt, phone=110]
現在開始關閉容器!
【destroy-method】調用<bean>的destroy-method屬性指定的初始化方法
【DiposibleBean接口】調用DiposibleBean.destory()

一個應用示例

後臺服務以方法調用的形式向外提供服務,在服務啓動時須註冊向外暴露的方法,該註冊功能可利用bean的生命週期的BeanPostProcessor接口,在bean加載完畢後自動註冊,代碼如下:

業務類註解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ExpoService {
    String value() default "";
}

業務接口與實現

public interface UserService {
    void doSomething();
}
@ExpoService
public class UserServiceImpl implements UserService {
//    @Async
    @Override
    public void doSomething() {
        System.out.println("doSomething invoked!");
    }
}

請求管理類

@Component
public class RequestManager {

    private Map<String, MethodAndInstance> methodMap = new HashMap<String, MethodAndInstance>();
    
    public void addExpoMethod(Method rawMethod, Object rawInstance, Method proxyMethod, Object proxyInstance) {
        methodMap.put(rawMethod.getName(), new MethodAndInstance(rawMethod, rawInstance, proxyMethod, proxyInstance));
        System.out.println(String.format("****** 添加expo對外暴露方法: %s", rawMethod.getName()));
    }
    
    public static class MethodAndInstance {
        private Method rawMethod;
        private Object rawInstance;
        private Method proxyMethod;
        private Object proxyInstance;
        
        public MethodAndInstance(Method rawMethod, Object rawInstance, Method proxyMethod, Object proxyInstance) {
            this.rawMethod = rawMethod;
            this.rawInstance = rawInstance;
            this.proxyMethod = proxyMethod;
            this.proxyInstance = proxyInstance;
        }

        public Object getRawInstance() {
            return rawInstance;
        }

        public Object getProxyInstance() {
            return proxyInstance;
        }

        public Method getRawMethod() {
            return rawMethod;
        }

        public Method getProxyMethod() {
            return proxyMethod;
        }
    }
}

使用BeanPostProcessor,註冊接口

@Component
public class ExpoBeanPostProcessor implements BeanPostProcessor {
    private Map<String, Object> beanMap = new HashMap<String, Object>();
    
    @Autowired
    private RequestManager requestManager;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        
        Class<?> cls = bean.getClass();
        if (cls.isAnnotationPresent(ExpoService.class)) {
            beanMap.put(beanName, bean);
            System.out.println(String.format("======> 業務類原始bean: %s", bean.getClass().getName()));
        }
        
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object proxyBean, String beanName) throws BeansException {
        
        try {
            if (beanMap.containsKey(beanName)) {
                System.out.println(String.format("======> 業務類代理bean: %s", proxyBean.getClass().getName()));
                Object rawBean = beanMap.remove(beanName);
                for (Class<?> cls : rawBean.getClass().getInterfaces()) {
                    for (Method rowMethod : cls.getDeclaredMethods()) {
                        Method proxyMethod = proxyBean.getClass().getMethod(rowMethod.getName(), rowMethod.getParameterTypes());
                        this.requestManager.addExpoMethod(rowMethod, rawBean, proxyMethod, proxyBean);
                    }
                }
            }
        } 
        catch (Exception e) { }
        
        return proxyBean;
    }

}

配置

<context:component-scan base-package="cn.matt.lifecircle"/>
<task:annotation-driven executor="myExecutor1"/>
<task:executor id="myExecutor1" pool-size="10" /> 

測試
運行結果

======> 業務類原始bean: cn.matt.lifecircle.UserServiceImpl
======> 業務類代理bean: cn.matt.lifecircle.UserServiceImpl
****** 添加expo對外暴露方法: doSomething
doSomething invoked!

當業務方法添加@Async時,運行結果:

======> 業務類原始bean: cn.matt.lifecircle.UserServiceImpl
======> 業務類代理bean: com.sun.proxy.$Proxy9
****** 添加expo對外暴露方法: doSomething
doSomething invoked!

補充:不存在需要aop功能時,spring bean爲原始類;當存在需要aop功能時,spring bean爲代理類
上述實例存在一個bug:當業務類存在循環引用時,spring會將引用鏈中的某個類提前構造,此時,ExpoBeanPostProcessor在該類的postProcessAfterInitialization方法中獲取的是原始類,而非代理類,由於方法在原始類上調用,導致所有基於aop的功能(如事務,多數據源切換等)失效
解決方法:通過對spring初始化bean的源碼的分析可知(參考Spring 依賴注入時,什麼時候會創建代理類),利用SmartInstantiationAwareBeanPostProcessor接口的getEarlyBeanReference方法獲取到代理類,該方法在BeanPostProcessor接口相關方法之前調用
具體修改如下:

@Component
public class ExpoBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    
    private Map<String, Object> beanMap = new HashMap<String, Object>();
    
    /**
     * @Fields proxyBeanMap : 記錄bean循環引用時的代理bean
     */
    private Map<String, Object> proxyBeanMap = new HashMap<String, Object>();
    
    @Autowired
    private RequestManager requestManager;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        
        Class<?> cls = bean.getClass();
        if (cls.isAnnotationPresent(ExpoService.class)) {
            beanMap.put(beanName, bean);
            System.out.println(String.format("======> 業務類原始bean: %s", bean.getClass().getName()));
        }
        
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object proxyBean, String beanName) throws BeansException {
        
        Object originalProxyBean = proxyBean;
        
        try {
            if (beanMap.containsKey(beanName)) {
                // bean循環引用時, postProcessAfterInitialization獲取不到代理類,須特殊處理
                if (proxyBeanMap.containsKey(beanName)) {
                    proxyBean = proxyBeanMap.get(beanName);
                }
                
                System.out.println(String.format("======> 業務類代理bean: %s", proxyBean.getClass().getName()));
                Object rawBean = beanMap.remove(beanName);
                for (Class<?> cls : rawBean.getClass().getInterfaces()) {
                    for (Method rowMethod : cls.getDeclaredMethods()) {
                        Method proxyMethod = proxyBean.getClass().getMethod(rowMethod.getName(), rowMethod.getParameterTypes());
                        this.requestManager.addExpoMethod(rowMethod, rawBean, proxyMethod, proxyBean);
                    }
                }
            }
        } 
        catch (Exception e) { }
        
        return originalProxyBean;
    }
    
    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        
        if (!proxyBeanMap.containsKey(beanName)) {
            proxyBeanMap.put(beanName, bean);
        }
        
        return bean;
    }
}

`

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章