溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何把Bean塞到Spring容器里

發(fā)布時間:2021-10-15 09:46:15 來源:億速云 閱讀:172 作者:iii 欄目:編程語言

本篇內(nèi)容介紹了“如何把Bean塞到Spring容器里”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

代理Bean注冊到Spring容器

如何把Bean塞到Spring容器里  
Bean注冊
  • 關(guān)于Bean注冊的技術(shù)場景,在我們?nèi)粘S玫降募夹g(shù)框架中,MyBatis 是最為常見的。通過在使用 MyBatis 時都只是定義一個接口不需要寫實現(xiàn)類,但是這個接口卻可以和配置的 SQL 語句關(guān)聯(lián),執(zhí)行相應(yīng)的數(shù)據(jù)庫操作時可以返回對應(yīng)的結(jié)果。那么這個接口與數(shù)據(jù)庫的操作就用到的 Bean 的代理和注冊。
  • 我們都知道類的調(diào)用是不能直接調(diào)用沒有實現(xiàn)的接口的,所以需要通過代理的方式給接口生成對應(yīng)的實現(xiàn)類。接下來再通過把代理類放到 Spring 的 FactoryBean 的實現(xiàn)中,最后再把這個 FactoryBean 實現(xiàn)類注冊到 Spring 容器。那么現(xiàn)在你的代理類就已經(jīng)被注冊到 Spring 容器了,接下來就可以通過注解的方式注入到屬性中。

按照這個實現(xiàn)方式,我們來操作一下,看看一個 Bean 的注冊過程在代碼中是如何實現(xiàn)的。 

1. 定義接口

public interface IUserDao {

    String queryUserInfo();

}
 
  • 先定義一個類似 DAO 的接口,基本這樣的接口在使用 MyBatis 時還是非常常見的。后面我們會對這個接口做代理和注冊。 

2. 類代理實現(xiàn)

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?>[] classes = {IUserDao.class};    

InvocationHandler handler = (proxy, method, args) -> "你被代理了 " + method.getName();
IUserDao userDao = (IUserDao) Proxy.newProxyInstance(classLoader, classes, handler); 

String res = userDao.queryUserInfo();
logger.info("測試結(jié)果:{}", res);
 
  • Java 本身的代理方式使用起來還是比較簡單的,用法也很固定。
  • InvocationHandler 是個接口類,它對應(yīng)的實現(xiàn)內(nèi)容就是代理對象的具體實現(xiàn)。
  • 最后就是把代理交給 Proxy 創(chuàng)建代理對象,     Proxy.newProxyInstance。 

3. 實現(xiàn)Bean工廠

public class ProxyBeanFactory implements FactoryBean {

    @Override
    public Object getObject() throws Exception {

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Class[] classes = {IUserDao.class};
        InvocationHandler handler = (proxy, method, args) -> "你被代理了 " + method.getName();

        return Proxy.newProxyInstance(classLoader, classes, handler);
    }

    @Override
    public Class<?> getObjectType() {
        return IUserDao.class;
    } 

}
 
  • FactoryBean 在 spring 起到著二當(dāng)家的地位,它將近有70多個小弟(實現(xiàn)它的接口定義),那么它有三個方法;
    • T getObject() throws Exception; 返回bean實例對象
    • Class<?> getObjectType(); 返回實例類類型
    • boolean isSingleton(); 判斷是否單例,單例會放到Spring容器中單實例緩存池中
  • 在這里我們把上面使用Java代理的對象放到了 getObject() 方法中,那么現(xiàn)在再從 Spring 中獲取到的對象,就是我們的代理對象了。
 

4. Bean 注冊

public class RegisterBeanFactory implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(ProxyBeanFactory.class);

        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(beanDefinition, "userDao");
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
    }

}
 

在 Spring 的 Bean 管理中,所有的 Bean 最終都會被注冊到類 DefaultListableBeanFactory 中,以上這部分代碼主要的內(nèi)容包括:

  • 實現(xiàn) BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry方法,獲取 Bean 注冊對象。
  • 定義 Bean,GenericBeanDefinition,這里主要設(shè)置了我們的代理類工廠。
  • 創(chuàng)建 Bean 定義處理類,BeanDefinitionHolder,這里需要的主要參數(shù);定義 Bean 和名稱     setBeanClass(ProxyBeanFactory.class)。
  • 最后將我們自己的bean注冊到spring容器中去,registry.registerBeanDefinition()
 

測試驗證

在上面我們已經(jīng)把自定義代理的 Bean 注冊到了 Spring 容器中,接下來我們來測試下這個代理的 Bean 被如何調(diào)用。

 

1. 定義 spring-config.xml

<bean id="userDao" class="org.itstack.interview.bean.RegisterBeanFactory"/>
 
  • 這里我們把 RegisterBeanFactory 配置到 spring 的 xml 配置中,便于啟動時加載。
 

2. 單元測試

@Test
public void test_IUserDao() {
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config.xml");
    IUserDao userDao = beanFactory.getBean("userDao", IUserDao.class);
    String res = userDao.queryUserInfo();
    logger.info("測試結(jié)果:{}", res);
}
 

「測試結(jié)果」

22:53:14.759 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source
22:53:14.760 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'userDao'
22:53:14.796 [main] INFO  org.itstack.interview.test.ApiTest - 測試結(jié)果:你被代理了 queryUserInfo

Process finished with exit code 0
 
  • 從測試結(jié)果可以看到,我們已經(jīng)可以通過注入到Spring的代理Bean對象,實現(xiàn)我們的預(yù)期結(jié)果。
  • 其實這個過程也是很多框架中用到的方式,尤其是在一些中間件開發(fā),類似的 ORM 框架都需要使用到。

“如何把Bean塞到Spring容器里”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI