springboot 實現bean手動註入操作
1、springboot啟動類實現接口ApplicationListener<ContextRefreshedEvent>,實現方法onApplicationEvent,初始化上下文
package test.projectTest; import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.system.ApplicationPidFileWriter; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import test.projectTest.util.SpringContextUtil; @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class, MybatisAutoConfiguration.class}) @SpringBootApplication(scanBasePackages={"test.projectTest"}) public class TestApplication implements ApplicationListener<ContextRefreshedEvent> { public static void main( String[] args ) { SpringApplication application = new SpringApplication(TestApplication.class); application.addListeners(new ApplicationPidFileWriter()); application.run(args); System.out.println( "啟動成功" ); } @Override public void onApplicationEvent(ContextRefreshedEvent event) { SpringContextUtil.setApplicationContext(event.getApplicationContext()); } }
2.SpringContextUtil工具類初始化ApplicationContext applicationContext
package test.projectTest.util; import org.springframework.context.ApplicationContext; /** * 獲取spring容器,以訪問容器中定義的其他bean */ public class SpringContextUtil{ //spring上下文 private static ApplicationContext applicationContext; /** * 實現ApplicationContextAware接口的回調方法,設置上下文環境 * @param applicationContext */ public static void setApplicationContext(ApplicationContext applicationContext){ if(null==SpringContextUtil.applicationContext) SpringContextUtil.applicationContext=applicationContext; } public static ApplicationContext getApplicationContext(){ return applicationContext; } /** * 通過name獲取 Bean. * * @param name * @return */ public static Object getBean(String name) { return getApplicationContext().getBean(name); } /** * 通過name獲取 Bean. * * @param clazz * @return */ public static <T> T getBean(Class<T> clazz) { return getApplicationContext().getBean(clazz); } /** * 通過name,以及Clazz返回指定的Bean * * @param name * @param clazz * @return */ public static <T> T getBean(String name, Class<T> clazz) { return getApplicationContext().getBean(name, clazz); } }
3.獲取bean
package test.projectTest.util; import test.projectTest.mapper.slave.DailyDataMapper; public class TestUtil{ private static DailyDataMapper dailyDataMapper; static{//手動註入bean if(dailyDataMapper==null){ dailyDataMapper = (DailyDataMapper)SpringContextUtil.getBean("dailyDataMapper"); } } public static void test(){ dailyDataMapper.selectByPrimaryKey(1); } }
補充:springboot中bean的實例化和屬性註入過程
springboot版本(2.0.4 RELEASE)
大致描述springboot中bean的實例化和屬性註入過程流程
1) 在某一時刻Spring調用瞭Bean工廠的getBean(beanName)方法。beanName可能是simpleController,或者simpleService,simpleDao,順序沒關系(因為後面會有依賴關系的處理)。我們假設simpleController吧
2)getBean方法首先會調用Bean工廠中定義的getSingleton(beanName)方法,來判斷是否存在該名字的bean單例,如果存在則返回,方法調用結束(spring默認是單例,這樣可以提高效率)
3) 否則,Spring會檢查是否存在父工廠,如果有則返回,方法調用結束
4) 否則,Spring會檢查bean定義(BeanDefinition實例,用來描述Bean結果,component-scan掃描後,就是將beanDefinition實例放入Bean工廠,此時還沒有被實例化)是否有依賴關系,如果有,執行1)步,獲取依賴的bean實例
5) 否則,Spring會嘗試創建這個bean實例,創建實例前,Spring會檢查調用的構造器,並實例化該Bean,(通過Constructor.newInstance(args)進行實例化)
6) 實例化完成後,Spring會調用Bean工廠的populateBean方法來填充bean實例的屬性,也就是自動裝配。populateBean方法便是調用瞭BeanPostProcessor實例來完成屬性元素的自動裝配工作
7)在元素裝配過程中,Spring會檢查被裝配的屬性是否存在自動裝配的其他屬性,然後遞歸調用getBean方法,知道所有@Autowired的元素都被裝配完成。如在裝配simpleController中的simpleService屬性時,發現SimpleServiceImpl實例中存在@Autowired屬性simpleDao,然後調用getBean(simpleDao)方法,同樣會執行1)—-7)整個過程。所有可以看成一個遞歸過程。
8)裝配完成後,Bean工廠會將所有的bean實例都添加到工廠中來。
Bean的實例化
1. 進入SpringApplication類中refreshContext()方法
2. 進入AbstractApplicationContext類中refresh()方法,找到this.finishBeanFactoryInitialization()方法,這個方法就是完成beanFactory的實例化
3. 進入AbstractApplicationContext類中finishBeanFactoryInitialization()方法,找到preInstantiateSingletons()
4. 進入DefaultListableBeanFactory類中preInstantiateSingletons()方法,找到getBean()方法
5. 進入AbstractBeanFactory類中getBean()方法,找到doGetBean()方法
6. 在AbstractBeanFactory類中doGetBean方法中,找到createBean()方法
7. 進入AbstractAutowireCapableBeanFactory類中createBean方法中,找到doCreateBean()方法
8. 在AbstractAutowireCapableBeanFactory類中doCreateBean()方法中,找到createBeanInstance()方法,看名字就知道是實例化bean的
9. 在AbstractAutowireCapableBeanFactory類createBeanInstance()方法中,找到instantiateBean()方法
10. 在AbstractAutowireCapableBeanFactory類instantiateBean()方法中,找到instantiate()方法
11. 在SimpleInstantiationStrategy類instantiate()方法中,找到instantiateClass()方法
12. 在BeanUtils類instantiateClass()方法中,可知bean的實例化是通過Constructor.newInstance()進行實例化
Bean的屬性註入
1. 在AbstractAutowireCapableBeanFactory類doCreateBean()方法中,找到populateBean()方法,從名字可知是用來填充bean的
2. 在AbstractAutowireCapableBeanFactory類中populateBean()方法,找到postProcessPropertyValues()方法
3. 進入AutowiredAnnotationBeanPostProcessor類中postProcessPropertyValues()方法中,找到findAutowiringMetadata()方法,在這個方法中,如果屬性中含有@Autowired註解則會遞歸getBean()。沒有然後進入inject()方法中
4. 進入AutowiredAnnotationBeanPostProcessor類inject方法中,找到resolveDependency()方法,通過這個方法獲取對應字段的值
5. 進入AutowiredAnnotationBeanPostProcessor類inject方法中,找到field.set(bean, value)方法,通過反射將值設置到屬性中
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。如有錯誤或未考慮完全的地方,望不吝賜教。
推薦閱讀:
- SpringBoot項目如何將Bean註入到普通類中
- Springboot如何獲取上下文ApplicationContext
- SpringBoot中的main方法註入service
- 基於Spring上下文工具類 ApplicationContextUtil
- 解決netty中spring對象註入失敗的問題