BeanPostProcessor後置處理器是Spring提供的一個擴展點,可以在Bean初始化前後做一些事情,註意這裡是bean的初始化,不是實例化,BeanPostProcessor是一個介面,裡面提供了兩個方法,分別為postProcessBeforeInitialization(初始化之前) ...
BeanPostProcessor後置處理器是Spring提供的一個擴展點,可以在Bean初始化前後做一些事情,註意這裡是bean的初始化,不是實例化,BeanPostProcessor是一個介面,裡面提供了兩個方法,分別為postProcessBeforeInitialization(初始化之前)和postProcessAfterInitialization(初始化之後),在方法入參中有兩個參數,一個bean對象,一個bean名稱,這裡也可以看出,在初始化之前應該已經完成了bean的實例化,這裡把實例化的bean對象作為參數傳了進來:
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
來看一個例子,首先創建一個Bean,使用@Component將該bean交給Spring容器管理:
// 使用@Component將該bean交給Spring管理
@Component
public class User {
private String name;
public User() {
System.out.println("調用User構造函數");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
接下來創建一個自定義的Bean後置處理器,實現BeanPostProcessor介面,並實現postProcessBeforeInitialization和postProcessAfterInitialization方法,使用@Component將該bean交給Spring管理,Spring會獲取後置處理器,在bean進行初始化前後觸發對應的方法。
為了列印便於觀察輸出結果,這裡對Bean類型進行了判斷,只有User類型才列印日誌:
// 使用@Component將該bean交給Spring管理
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 只處理User類型
if (bean instanceof User) {
System.out.println("【後置處理器】postProcessBeforeInitialization");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 只處理User類型
if (bean instanceof User) {
System.out.println("【後置處理器】postProcessBeforeInitialization");
}
return bean;
}
}
進行測試,從容器中獲取user對象:
// 註意這裡要掃描包
@ComponentScan(basePackages = {"com.example.demo"})
@SpringBootTest
class SpringbootWebApplicationTests {
@Test
void contextLoads() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringbootWebApplicationTests.class);
User User = (User) applicationContext.getBean("user", User.class);
System.out.println("userName:" + User.getName());
}
}
列印結果:
調用User構造函數
【後置處理器】postProcessBeforeInitialization
【後置處理器】postProcessBeforeInitialization
userName:null
從結果中也可以看出,後置處理器中的方法,是在bean已經完成了實例化之後觸發的,所以通過後置處理器可以對bean的屬性進行設置,甚至可以更改bean對象本身。
比如在postProcessBeforeInitialization方法中,為User設置名稱:
// 使用@Component將該bean交給Spring管理
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 只處理User類型
if (bean instanceof User) {
User user = (User) bean;
user.setName("zhangsm");
System.out.println("【後置處理器】postProcessBeforeInitialization");
return user;
}
return bean;
}
}
再次運行將會輸出以下內容:
調用User構造函數
【後置處理器】postProcessBeforeInitialization
【後置處理器】postProcessBeforeInitialization
userName:zhangsm
再看一下對bean本身進行更改的例子,再新增一個AdminUser類,繼承User,註意AdminUser沒有使用註解,也就是沒有交給Spring進行管理,之後我們通過手動實例化的方式,將Spring容器中User改成AdminUser類型:
public class AdminUser extends User {
}
修改MyBeanPostProcessor中的postProcessAfterInitialization方法,方法的返回值是Object類型,在這裡更改bean對象並返回進行替換:
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof User) {
// 這裡手動創建了一個AdminUser並返回
AdminUser user = new AdminUser();
user.setName("administator");
System.out.println("【後置處理器】postProcessBeforeInitialization");
return user;
}
return bean;
}
}
修改測試類,這次把class信息也列印:
@ComponentScan(basePackages = {"com.example.demo"})
@SpringBootTest
class SpringbootWebApplicationTests {
@Test
void contextLoads() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringbootWebApplicationTests.class);
User User = (User) applicationContext.getBean("user", User.class);
System.out.println("userClass:" + User.getClass());
System.out.println("userName:" + User.getName());
}
}
運行結果,可以看到拿到的bean已經是更改後的AdminUser
調用User構造函數 // 這裡是User實例化時輸出的
【後置處理器】postProcessBeforeInitialization
調用User構造函數 // 這裡是AdminUser實例化時輸出的
【後置處理器】postProcessBeforeInitialization
userClass:class com.example.demo.model.AdminUser
userName:administator