spring中BeanPostProcessor之一:InstantiationAwareBeanPostProcessor

https://www.cnblogs.com/teach/p/12639363.html

spring中BeanPostProcessor之一:InstantiationAwareBeanPostProcessor(01)

在spring中beanPostProcessor絕對是開天闢地的產物,給了程序員很多自主權,beanPostProcessor即常說的bean後置處理器。

一、概覽

先來說下InstantiationAwareBeanPostProcessor,這個後置處理器是BeanPostProcessor的子接口,繼承自BeanPostProcessor,先看下BeanPostProcessor中的方法,

再看下InstantiationAwareBeanPostProcessor中的方法,

可見InstantiationAwareBeanPostProcessor擴展了BeanPostProcessor接口,並且新增了4個方法,今天先看postProcessAfterInstantiation方法,

default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }

改方法有默認的返回值爲true。

二、詳述

InstantiationAwareBeanPostProcessor中的postProcessAfterInstantiation方法的作用是什麼那,用在什麼地方。在看spring源碼的時候看到屬性注入這段代碼,其中屬性注入是在populateBean方法中完成,在此方法中便出現了postProcessAfterInstatiation方法的調用,這裏只貼出populateBean方法中和這塊有關係的代碼,

複製代碼

boolean continueWithPropertyPopulation = true;
 //調用beanFactory中已註冊的beanPostProcessors即bean後置處理器,判斷是否爲InstantiationAwareBeanPostProcessor的類型,如果是執行postProcessAfterInstantiation
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    //如果返回值爲false纔會進到下面的賦值操作,從而下方的1處纔會爲true,則屬性注入纔會中斷
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }
        //1 
        if (!continueWithPropertyPopulation) {
            return;
        }

複製代碼

上面這段邏輯就是來循環已經註冊的beanPostProcessor,找到是InstantiationAwareBeanPostProcessor的類型,並執行其postProcessAfterInstantiation方法,通過查看已註冊的beanPostProcessor發現其返回值均爲true,通過上面的分析,只有postProcessAfterInstantiation方法返回false,populateBean方法纔會返回,屬性注入纔會中斷,即不會注入值。

怎麼才能保證postProcessAfterInstantiation方法返回false那,這裏只有自己向spring註冊一個InstantiationAwareBeanPostProcessor的後置處理器,下面是我的一個後置處理器,

複製代碼

package cn.com.my.test;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("beanName:"+beanName);
        if("userService".equals(beanName)) {
            return false;
        }
        return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
    }
}

複製代碼

自定義的beanPostProcessor僅實現了postProcessAfterInstantiation方法,上面的代碼邏輯中,可以看到只有beanName爲userService的時候,改方法纔會返回false,其他情況下調用的接口方法,返回默認值true。

下面看我的測試類,

複製代碼

package cn.com.my.test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext(Config.class);
        
        UserService us=ac.getBean(UserService.class);
        System.out.println("us.roleService:"+us.getRoleService());
    }

}

複製代碼

下面是我的UserService類,

複製代碼

package cn.com.my.test;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class UserService {

    @Autowired
    private RoleService roleService;
    
    

    public RoleService getRoleService() {
        return roleService;
    }

    public void setRoleService(RoleService roleService) {
        this.roleService = roleService;
    }
}

複製代碼

從UserService類中,可以看出有一個加了註解的roleService屬性,正常情況下會自動注入改屬性,但在我自定義的beanPostProcessor之後,看下面的結果

神奇的事情,發生了us.roleService的屬性返回的null。

這是爲什麼那,我們再看populateBean中的這段代碼,

複製代碼

boolean continueWithPropertyPopulation = true;
        //調用beanPostProcessors即bean後置處理器,
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }

        if (!continueWithPropertyPopulation) {
            return;
        }

複製代碼

由於,我們向beanFactory中註冊了一個beanPostProcessor,所以這裏循環的時候肯定會執行我的postProcessAfterInstantiation後置處理器,而我在後置處理器中進行了判斷,即在給beanName爲userService進行屬性注入的時候postProcessAfterInstantiation方法會返回false,那麼上面的continueWithPropertyPopulation便爲false,導致會進入到下面的if,方法直接返回,屬性注入便會中止,所以UserService類中的roleService的值爲null。

三、適用場合

什麼時候需要實現InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法那,如果不想使用spring的自動注入(前提是已經使用了@Autowired註解),則對於特殊的bean則可以註冊一個beanPostProcessor使其不進行注入,使用自己的方式進行注入。

 

spring中BeanPostProcessor之一:InstantiationAwareBeanPostProcessor(02)

在上篇博客中寫道了bean後置處理器InstantiationAwareBeanPostProcessor,只介紹了其中一個方法的作用及用法,現在來看postProcessBeforeInstantiation方法。

一、概述

postProcessBeforeInstantiation方法定義在InstantiationAwareBeanPostProcessor接口中,方法的定義如下,

@Nullable
    default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

從上面的代碼中可以看到該方法默認返回null。

二、詳述

postProcessBeforeInstantiation方法是用來做什麼的,在看源碼的過程中,在createBean方法中找到了該方法的調用,下面只貼出相關代碼,

複製代碼

try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            //1、調用beanPostProcessor即bean的後置處理器,這裏會調用2次後置處理器
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

複製代碼

在resolveBeforeInstantiation方法中進行了調用,resolveBeforeInstantiation方法返回值如果不爲null,則該方法直接返回bean,也就是說resolveBeforeInstantiation方法至關重要,下面是resolveBeforeInstantiation方法,

複製代碼

@Nullable
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            // Make sure bean class is actually resolved at this point.
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                Class<?> targetType = determineTargetType(beanName, mbd);
                if (targetType != null) {
                    //如果是InstantiationAwareBeanPostProcessor的實例,則執行其postProcessBeforeInstantiation方法
                    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    //如果上面的postProcessBeforeInstantiation方法返回值不爲null,則執行所有beanPostProcessor的postProcessAfterInitialization方法
                    //bean不爲null,則說明postProcesBeforeInstantiation方法中的返回值是一個不爲null的對象
                    if (bean != null) {
                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
            }
            mbd.beforeInstantiationResolved = (bean != null);
        }
        return bean;
    }

複製代碼

在resolveBeforeInstantiation方法中首先調用了applyBeanPostProcessorsBeforeInstantiation方法,該方法中便會調用InstantiationAwareBeanPostProcessor接口中的postProcessBeforeInstantiation方法,且如果applyBeanPostPorcessorsBeforeInstantiation方法返回值不爲null,纔會調用applyBeanPostProcessAfterIntialization方法,下面先看applyBeanPostProcessorsBeforeInstantiation方法

複製代碼

@Nullable
    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }

複製代碼

從上面方法的定義看到,該方法會遍歷benaFactory中的beanPostProcessor,並且判斷是否爲InstantiationAwareBeanPostPrecessor的類型,如果是執行其postProcessBeforeInstantiation方法,這裏默認註冊的beanPostProcessor該方法的返回值均爲null。稍後自定義一個BeanPostProcessor實現InstantiationAwareBeanPostProcessor接口。

下面看applyBeanPostProcessAfterIntializtion方法,

複製代碼

@Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

複製代碼

改方法的邏輯是遍歷beanFactory中的所有的beanPostProcessor,執行其postProcessAfterInitialization方法,該方法定義在BeanPostProcessor接口中,默認返回bean,如下,

@Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

從上面可以看出默認返回的是bean參數的值,也就是如果該方法未實現則默認返回參數中的bean。

再次回到resolveBeforeInstantiation方法,再看其邏輯有以下幾種方法返回值的組合,

1、applyBeanPostProcessBeforeInstantiation返回值爲null,則resolveBeforeInstantiation方法返回null;

2、applyBeanPostProcessBeforeInstantiation返回值bean不爲null,applyBeanPostProcessAfterInitialization方法返回值爲null,則resolveBeforeInstantiationf方法返回值爲bean;

3、applyBeanPostProcessBeforeInstantiation返回值bean不爲null,applyBeanPostProcessAfterInitialization方法返回值bean1不爲爲null,則resolveBeforeInstantiationf方法返回值爲bean1;

從resolveBeforeInstantiation方法分析,該方法的返回值,直接決定了createBean方法的返回值,也就是說applyBeanPostProcessBeforeInstantiation方法返回的bean不爲null,下面的方法不會執行。

再來看調用resolveBeforeInstantiation方法時的註釋

// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

大體意思時給BeanPostProcessor一個機會返回代理對象而不是目標對象的實例,所以這裏resolveBeforeInstantiation方法返回的必然時一個代理對象(JDK和CGLib)。看下面的例子

自定義的BeanPostProcessor實現了InstantiationAwareBeanPostProcessor

複製代碼

package cn.com.my.test;

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

import net.sf.cglib.proxy.Enhancer;
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        
        if("userService".equals(beanName)) {
            
            UserService us=(UserService)bean;
            
            Enhancer enhancer = new Enhancer();
            //設置目標類的字節碼文件
            enhancer.setSuperclass(UserService.class);
            //設置回調函數
            enhancer.setCallback(new MyMethodInterceptor());
            
            //這裏的creat方法就是正式創建代理類
            UserService proxyUs = (UserService)enhancer.create();
            return proxyUs;
        }
        return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }
}

複製代碼

當beanName等於userUservice時返回的是經過cglib代理後的對象。在MyInstantiationAwareBeanPostProcessor類中僅實現了postProcessBeforeInitialization方法,未實現postProcessAfterInitialization方法,所以resolveBeforeInstantiation方法的返回值即未postProcessBeforeInitialization方法的返回值,在上面的類中就是使用cglib代理後的UserService實例。

代理類MyMethodInterceptor,實現cglib的MethodInterceptor接口

複製代碼

package cn.com.my.test;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.MethodProxy;

import net.sf.cglib.proxy.MethodInterceptor;

public class MyMethodInterceptor implements MethodInterceptor{

   
    @Override
    public Object intercept(Object arg0, Method arg1, Object[] arg2, net.sf.cglib.proxy.MethodProxy arg3)
            throws Throwable {
        // TODO Auto-generated method stub
         Object object = arg3.invokeSuper(arg0, arg2);
         return object;
    }  
}

複製代碼

下面是測試類

複製代碼

package cn.com.my.test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext(Config.class);
        
        UserService us=ac.getBean(UserService.class);
        System.out.println("us:"+us);
        
    }

}

複製代碼

看下面的結果,

us:cn.com.my.test.UserService$$EnhancerByCGLIB$$ffa582b4@5fe94a96

返回的是UserService的一個經過cglib代理後的對象。到這裏發現真好強大,返回的一個代理對象。

三、適用場合

實現InstantiationAwareBeanPostProcessor接口的postProcessBeforeInitialization方法,通過返回一個代理對象的方式,達到改變目標類類型的目的。在不想改變現有類的邏輯而又想借助現有類實現其他功能,就可以使用這種方式。像AOP就是這種實現,AnnotationAwareAspectJAutoProxyCreator類便是InstantiationAwareBeanPostProcessor的一個實現。

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