一、SpringBean的生命週期
二、後置處理器postProcessor
一個是針對BeanDefinition的容器級別的後處理器 - BeanFactoryPostProcessor
一個是針對getBean操作獲得的對象的後處理器 - BeanPostProcessor
兩者的不同:
觸發時機不同,前者BeanFactoryPostProcessor是在容器refresh方法中調用,而後者實際調用時機是在getBean方法獲取對象時調用;
1.因觸發時機不同導致二者處理的對象不同。
BeanFactoryPostProcessor處理的是解析完配置文件後註冊在容器中的BeanDefinition,
而BeanPostProcessor處理的是通過反射生成的實例Bean;
2.接口樣式不同,
BeanFactoryPostProcessor只有一個後處理方法,
而BeanPostProcessor有一個前置處理方法一個後置處理方法。
三、BeanPostProcessor
Spring主要提供了兩類擴展點BeanPostProcessor和BeanFactoryPostProcessor。前者是操作bean的實例,後者使對bean的元數據定義進行擴展。
BeanPostProcessor提供對bean實例的操作擴展,在spring容器對bean實例化和設置依賴之後,其回調開始執行。BeanPostProcessor接口定義的兩個方法,分別在bean的初始化方法(InitializingBean接口,或者init-method定義)執行的前後執行:
如果你想在Spring容器完成實例化,配置和初始化bean之後實現一些自定義邏輯,則可以插入一個或多個自定義BeanPostProcessor實現。這些實現成爲後置處理器。
BeanPostProcessor接口包含兩個回調方法。
當實現此接口類通過容器註冊爲後處理器時,由Spring容器實例的Bean,Spring容器會在bean 的init方法執行前回調postProcessBeforeInitialization方法,
然後會在bean初始化之後回調postProcessAfterInitialization方法。
後置處理器可以對這些Bean做任何自定義操作。一些Spring Aop 的基礎實現類就是通過實現BeanPostProcessor從而提供代理包裝邏輯 。
Spring容器能夠自動檢測任何實現了BeanPostProcessor接口的Bean。容器會自動將這些bean註冊成後置處理器以便後續調用。
另外我們可以定義多個BeanPostProcessor,他們執行的順序可以通過實現PriorityOrdered、Ordered接口來控制。
我們定義一個類實現了BeanPostProcessor,默認會對整個Spring容器中所有的bean進行處理,方法的參數:
1.每個Bean的實例
2.每個Bean的name 或者 id屬性
實現 PriorityOrdered、Ordered,可以定義順序
下面的示例演示如何在ApplicationContext中編寫,註冊和使用BeanPostProcessor實例(Spring AOP)的實現方式就是如下。
@Component public interface Person { void sayHello(); }
@Component("student") public class StudentImpl implements Person { private String name; @Override public void sayHello() { System.out.println("Hello World, " + this.name); } @PostConstruct public void init() { this.name = "student"; } @Override public String toString() { return "HelloWorldImpl{" + "name='" + name + '\'' + '}'; } }
@Component("teacher") public class TeacherImpl implements Person { private String name; @Override public void sayHello() { System.out.println("Hello World, "+this.name); } @PostConstruct public void init(){ this.name="teacher"; } @Override public String toString() { return "TeacherImpl{" + "name='" + name + '\'' + '}'; } }
@Configuration @ComponentScan(value = "com.best") public class AppConfig { }
/** * 自定義HelloWorldBeanPostProcessor實現BeanPostProcessor接口 */ @Component public class HelloWorldBeanPostProcessor implements BeanPostProcessor { @Autowired private ApplicationContext applicationContext; // 直接返回實例化的bean,在bean初始化之前執行 @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization: " + bean + ", " + beanName + ", " + applicationContext.getApplicationName()); return bean; } // 直接返回實例化的bean,在bean初始化之後執行 @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization: " + bean + ", " + beanName + ", " + applicationContext.getApplicationName()); return Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("BeanPostProcessor織入,Spring AOP實現原理"); return method.invoke(bean, args); } }); } }
執行入口:
public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); Person student = (Person) applicationContext.getBean("student"); System.out.println(student.getClass().getName()); student.sayHello(); Person teacher = (Person) applicationContext.getBean("teacher"); System.out.println(teacher.getClass().getName()); teacher.sayHello(); } }
上面程序執行的結果如下:
四、BeanFactoryPostProcessor
BeanFactory級別的處理,是針對整個Bean的工廠進行處理,這是Spring容器的另外一個擴展點,和BeanPostProcessor不同的地方在於,它是對beanDefiniton進行操作。
實現該接口,可以在spring的bean創建之前,修改bean的定義屬性。
當調用BeanFactoryPostProcess 方法時,這時候bean還沒有實例化,此時Bean剛被解析成 BeanDefinition對象。也就是說,Spring允許BeanFactoryPostProcessor在容器實例化任何其它bean之前讀取配置元數據,並可以根據需要進行修改,
例如可以把bean的scope從singleton改爲prototype,也可以把property的值給修改掉。可以同時配置多個BeanFactoryPostProcessor,並通過設置'order'屬性或實現ordered接口來控制各個BeanFactoryPostProcessor的執行次序,
這些和BeanPostProcessor很類似,並且其啓用方式和容器相關性也與之一致。
注意:BeanFactoryPostProcessor是在spring容器加載了bean的定義文件之後,在bean實例化之前執行的。
接口方法的入參是ConfigurrableListableBeanFactory,使用該參數,可以獲取到相關bean的定義信息: BeanDefinition obj = arg0.getBeanDefinition("sumBean");
Spring內置實現了很多的BeanFactoryPostProcessor實現,例如:
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
org.springframework.beans.factory.config.PropertyOverrideConfigurer
org.springframework.beans.factory.config.CustomEditorConfigurer:用來註冊自定義的屬性編輯器。
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println(" IOC 容器調用了 YjBeanFactoryPostProcessor 的 postProcessBeanFactory方法"); for(String name:beanFactory.getBeanDefinitionNames()) { if("yjLog".equals(name)) { BeanDefinition beanDefinition = beanFactory.getBeanDefinition(name); //beanDefinition.setLazyInit(true); } } } }
下面示例,如何通過BeanFactoryPostProcessor動態註冊Bean進去。
@Component public class User { private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
@Configuration @ComponentScan(value = "com.best") public class AppConfig { }
@Component public class HelloWorldBeanFactoryPostProcessor implements BeanFactoryPostProcessor { // 實現BeanFactoryPostProcessor,在spring的bean創建之前,對beanDefinition進行操作,修改bean的定義屬性 @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory; BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class); beanDefinitionBuilder.addPropertyValue("id", 1); beanDefinitionBuilder.addPropertyValue("name", "jak"); defaultListableBeanFactory.registerBeanDefinition("user", beanDefinitionBuilder.getBeanDefinition()); } }
程序入口,獲取User並輸出。
public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); User user = (User) applicationContext.getBean("user"); System.out.println(user.toString()); } }
程序輸出結果,如下:
五、BeanDefinitionRegistryPostProcessor
這個接口繼承了BeanFactoryPostProcessor. 從名字上來看, 這個接口是BeanDefinitionRegistry的後處理器,
我們先介紹下BeanDefinitionRegistry.
BeanDefinitionRegistry是用來註冊BeanDefinition的.
BeanDefinition就是Bean的配置元數據或Bean的描述信息, 比如Bean的屬性值, 構造方法的參數值等. 上面的BeanFactory的BeanDefinition也是由它註冊的.
BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的擴展, 允許在BeanFactoryPostProcessor被調用之前對BeanDefinition做一些操作, 尤其是它可以註冊BeanFactoryPostProcessor的BeanDefinition.
它提供了一個方法postProcessBeanDefinitionRegistry(), 這個方法被調用的時候, 所有的BeanDefinition已經被加載了, 但是所有的Bean還沒被創建.
注意:
所有的Bean生成都有個順序: 定義 --> 創建 --> 初始化.
BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法在Bean被定義但還沒被創建的時候執行.
BeanFactoryPostProcessor的postProcessBeanFactory方法在Bean被創建但還沒被初始化的時候執行
@Component public class BestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { //該方法用來註冊更多的bean到spring容器中 @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { System.out.println("BestBeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法"); //框架自己的 BeanDefiniton Count System.out.println("bean定義的數據量:" + registry.getBeanDefinitionCount()); RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(BestBeanDefinitionRegistryPostProcessor.class); registry.registerBeanDefinition("bestBeanDefinitionRegistryPostProcessor", rootBeanDefinition); } // 繼承自BeanFactoryPostProcessor的方法 主要用來對bean定義做一些改變 @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("BestBeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法"); System.out.println("bean定義的數據量:" + beanFactory.getBeanDefinitionCount()); } }
public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); BestBeanDefinitionRegistryPostProcessor bestBeanDefinitionRegistryPostProcessor = (BestBeanDefinitionRegistryPostProcessor) applicationContext.getBean("bestBeanDefinitionRegistryPostProcessor"); System.out.println(bestBeanDefinitionRegistryPostProcessor.getClass().getCanonicalName()); } }
運行結果:
六、InitializingBean和DisposableBean
Spring 中定義了 3 種自定義初始化和銷燬方法。
1.過@Bean指定init-method和destroy-method屬性
2.Bean實現InitializingBean(定義初始化邏輯),DisposableBean(定義銷燬邏輯);
3.@PostConstruct:在bean創建完成並且屬性賦值完成;來執行初始化方法
Spring bean 通過實現 InitializingBean ,DisposableBean 接口實現初始化方法和銷燬前操作
這個接口有一個方法:afterPropertiesSet, 該方法在所有的屬性都被賦值後調用. 屬性被賦值是在初始化的時候做的, 與BeanPostProcessor結合來看,
afterPropertiesSet方法將在postProcessBeforeInitialization和postProcessAfterInitialization之間被調用.
@Component public class Student implements InitializingBean, DisposableBean { @Override public void destroy() throws Exception { System.out.println("DisposableBean destroy"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("InitializingBean afterPropertiesSet"); } }
@Configuration @ComponentScan(value = "com.best") public class AppConfig { }
public class Test { public static void main(String[] args) { /** * 1.把類掃描出來--掃描以後幹了什麼事情 * 2.把bean實例化 */ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); Student student = applicationContext.getBean(Student.class); System.out.println(student.getClass().getName()); applicationContext.close(); } }
運行結果:
七、 Aware接口
Spring中提供了各種Aware接口,如果檢測到一個bean實現了Aware接口,則能在bean中獲取相應的Spring資源;
如果某個對象實現了某個Aware接口,比如需要依賴Spring的上下文容器(ApplicationContext),則可以實現ApplicationContextAware接口。
Spring在Bean進行初始化(注意與實例化的區別)之前,會將依賴的ApplicationContext對象通過調用ApplicationContextAware#setApplicationContext注入。
Spring 提供的Aware接口如下:
那麼這些Aware接口在源碼中是什麼時候調用的呢?
AbstractAutowireCapableBeanFactory#invokeAwareMethods
其他的Aware接口呢?通過 ApplicationContextAwareProcessor
應用示例
@Component public class BestApplicationContextAware implements ApplicationContextAware { ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; String[] beanDefinitionNames = this.applicationContext.getBeanDefinitionNames(); System.out.println(Arrays.toString(beanDefinitionNames)); } }
public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); BestApplicationContextAware bestApplicationContextAware = (BestApplicationContextAware) applicationContext.getBean("bestApplicationContextAware"); System.out.println(bestApplicationContextAware.getClass().getCanonicalName()); } }
運行結果:
八、FactoryBean
一般情況下,Spring通過反射機制利用bean的class屬性指定實現類來實例化bean 。 在某些情況下,實例化bean過程比較複雜,如果按照傳統的方式,則需要在bean中提供大量的配置信息,配置方式的靈活性是受限的,這時採用編碼的方式可能會得到一個簡單的方案。 Spring爲此提供了一個org.Springframework.bean.factory.FactoryBean的工廠類接口,用戶可以通過實現該接口定製實例化bean的邏輯。 (後面Spring又提供了@Configration和@Bean這種方式,一定程度上可以替代FactoryBean)
public interface FactoryBean<T> { @Nullable T getObject() throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton() { return true; } }
FactoryBean和BeanFactory的區別
BeanFactory
FactoryBean
應用場景
@Component public class BestFactoryBean implements FactoryBean<User> { private String userInfo; public User getObject() throws Exception { User User = new User(); String[] infos = userInfo.split(","); User.setId(Integer.parseInt(infos[0])); User.setName(infos[1]); return User; } public Class<User> getObjectType() { return User.class; } public boolean isSingleton() { return false; } public String getUserInfo() { return this.userInfo; } // 接受逗號分割符設置屬性信息 public void setUserInfo(String userInfo) { this.userInfo = userInfo; } }
九、ApplicationListener
這跟Servlet中的監聽器一樣, 採用了觀察者模式. 監聽器往往都是監聽某些事件源,
下面是配合ApplicationContextAware一起使用的例子.
我們定義一個事件, 在實現了ApplicationContextAware的Bean中觸發事件, 在實現了ApplicationListener的類中對事件做出反應
// 自定義事件 public class RumenEvent extends ApplicationEvent { public RumenEvent(Object source) { super(source); } } // 自定義 Bean 實現 ApplicationContextAware 接口 @Component public class RumenzBean implements ApplicationContextAware { private ApplicationContext applicationContext; private String name; public void setApplicationContext(ApplicationContext context) { this.applicationContext = context; } // 當調用 setName 時, 觸發事件 public void setName(String name) { this.name = name; applicationContext.publishEvent(new RumenEvent(this)); // 這行代碼執行完會立即被監聽到 } public String getName() { return name; } } // 自定義監聽器, 監聽上面的事件 @Component public class MyApplicationListener implements ApplicationListener { @Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof RumenEvent) { System.out.println(((RumenzBean)event.getSource()).getName()); } } }
參考博客:Spring常用擴展點
參考視頻:視頻教程