Spring中的后置處理器BeanPostProcessor講解


Spring中提供了很多PostProcessor供開發者進行拓展,例如:BeanPostProcessor、BeanFactoryPostProcessor、BeanValidationPostProcessor等一系列后處理器。他們的使用方式大多類似,了解其中一個並掌握他的使用方式,其他的可以觸類旁通。

BeanPostProcessor接口作用:

     如果我們想在Spring容器中完成bean實例化、配置以及其他初始化方法前后要添加一些自己邏輯處理。我們需要定義一個或多個BeanPostProcessor接口實現類,然后注冊到Spring IoC容器中。

BeanPostProcessor API:

public interface BeanPostProcessor {  
  
    /** 
     * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean 
     * initialization callbacks (like InitializingBean's {@code afterPropertiesSet} 
     * or a custom init-method). The bean will already be populated with property values.    
     */  
    //實例化、依賴注入完畢,在調用顯示的初始化之前完成一些定制的初始化任務  
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;  
  
      
    /** 
     * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean 
     * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}   
     * or a custom init-method). The bean will already be populated with property values.       
     */  
    //實例化、依賴注入、初始化完畢時執行  
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;  
  
}

BeanPostProcessor接口提供了兩個供開發者自定義的方法:postProcessBeforeInitialization、postProcessAfterInitialization。

postProcessBeforeInitialization:該方法主要針對spring在bean初始化時調用初始化方法前進行自定義處理。

postProcessAfterInitialization:該方法主要針對spring在bean初始化時調用初始化方法后進行自定義處理。

 

測試代碼:

com.test.model.Cat:

package com.test.model;

/**
 * 測試bean
 */
public class Cat {
  private String name;
  private int age;
  
  public void say() {
    System.out.println("name:" + name);
    System.out.println("age:" + age);
  }
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public int getAge() {
    return age;
  }
 
  public void setAge(int age) {
    this.age = age;
  }
}
View Code

spring容器中配置cat,和cat的beanPostProcessor:

<!--配置bean並初始化-->
    <bean id="cat" class="com.test.model.Cat" >
      <property name="name" value="HelloKitty" />
      <property name="age" value="1" />
    </bean>
    <bean id="catBeanPostProcessor" class="com.test.postprocessor.CatBeanPostProcessor" />

com.test.postprocessor.CatBeanPostProcessor:

package com.test.postprocessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import com.test.model.Cat;

/**
 * 自定義后處理器
 */
public class CatBeanPostProcessor implements BeanPostProcessor{

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof Cat) {
              //輸出原始屬性
              Cat cat = (Cat) bean;
              cat.say();
              return bean;
            }
         return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof Cat) {
              //修改屬性值,並返回
              Cat cat = (Cat) bean;
              cat.setName("hello maomi");
              cat.setAge(3);
              return cat;
            }
         return bean;
    }
    
}

IndexController:

package com.cy.controller;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.test.model.Cat;

@Controller
public class IndexController {
    
    //到index首頁
    @RequestMapping(value="index")
    public String index(HttpServletRequest request){
        /**
         * 訪問index同時,從容器中獲取已經被初始化之后處理過的cat,打印信息
         */
        ServletContext servletContext = request.getSession().getServletContext();
        ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        Cat c = (Cat) ac.getBean("cat");
        c.say();
        
        return "index";
    }
}

觀察結果:

容器啟動時,輸出:

name:HelloKitty
age:1
訪問項目http://localhost:8080/demo/index,index鏈接時,輸出:
name:hello maomi
age:3
 
--------------------------------------------------------------------------------------------------------------------------
可以看到通過后處理器處理過后的bean信息已經改變。最后,看看源碼中如何調用自定義實現的。
在初始化bean方法中:AbstractAutowireCapableBeanFactory.java
/**
 * 初始化bean
 */
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
  //省略部分無關代碼
  Object wrappedBean = bean;
  //初始化前
  if (mbd == null || !mbd.isSynthetic()) {
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  }
 
  try {
    //調用初始化方法初始化bean
    invokeInitMethods(beanName, wrappedBean, mbd);
  }
  catch (Throwable ex) {
    throw new BeanCreationException(
        (mbd != null ? mbd.getResourceDescription() : null),
        beanName, "Invocation of init method failed", ex);
  }
  //初始化后
  if (mbd == null || !mbd.isSynthetic()) {
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  }
  return wrappedBean;
}
//postProcessBeforeInitialization方法調用
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
    throws BeansException {
 
  Object result = existingBean;
  for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
    //調用自定義postProcessBeforeInitialization方法
    Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
    if (current == null) {
      return result;
    }
    result = current;
  }
  return result;
}
//postProcessAfterInitialization方法調用
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    throws BeansException {
 
  Object result = existingBean;
  for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
    //自定義postProcessAfterInitialization方法調用
    Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
    if (current == null) {
      return result;
    }
    result = current;
  }
  return result;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM