1. 程式人生 > >白話Spring原始碼(八):Aware介面

白話Spring原始碼(八):Aware介面

我們知道spring框架中所有bean都是在工廠裡建立的,bean對自己是“無知覺”的,不知道自己叫什麼名字(bean的id或者name),從哪裡來(哪個工廠建立)。

一、為什麼需要Aware

大家看過黑客帝國電影吧,黑客帝國中機械工廠裡面“養殖”的人類,他們雖然能完成一定的功能,但是根本不知道自己在工廠(BeanFactory)中的代號(id),或者自己是在哪個工廠(BeanFactory的引用)中沉睡。所以,本節的目的就是要創造出一個尼奧一樣的Bean,讓他知道自己在工廠中的id和自己原來躺在哪個工廠中。

這裡,稱之為,Bean對Spring有知覺(Aware翻譯過來就是知覺)。

二、Aware是怎麼實現的

在spring1.0中定義了兩個介面BeanNameAware和BeanFactoryAware 介面。

BeanNameAware:讓Bean獲取自己在BeanFactory配置中的名字(根據情況是id或者name)

public interface BeanNameAware {

	/**
	 * Set the name of the bean in the bean factory that created this bean.
	 * <p>Invoked after population of normal bean properties but before an init
	 * callback like InitializingBean's afterPropertiesSet or a custom init-method.
	 * @param name the name of the bean in the factory
	 */
	void setBeanName(String name);

}

BeanFactoryAware :讓Bean獲取配置他們的BeanFactory的引用。

public interface BeanFactoryAware {
	
	/**
	 * Callback that supplies the owning factory to a bean instance.
	 * <p>Invoked after population of normal bean properties but before an init
	 * callback like InitializingBean's afterPropertiesSet or a custom init-method.
	 * @param beanFactory owning BeanFactory (may not be null).
	 * The bean can immediately call methods on the factory.
	 * @throws BeansException in case of initialization errors
	 * @see BeanInitializationException
	 */
	void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}

我們只需實現這個介面,就可以獲取bean的名稱或者bean工廠的例項,那怎麼做到的呢,我們再來看一下工廠獲取bean的原始碼:

	protected Object createBean(String beanName, RootBeanDefinition mergedBeanDefinition) throws BeansException {
        //省略其他程式碼

		//注意:這個就會Aware實現的原始碼
		try {
			if (bean instanceof BeanNameAware) {
				if (logger.isDebugEnabled()) {
					logger.debug("Invoking setBeanName() on BeanNameAware bean '" + beanName + "'");
				}
				((BeanNameAware) bean).setBeanName(beanName);
			}

			if (bean instanceof BeanFactoryAware) {
				if (logger.isDebugEnabled()) {
					logger.debug("Invoking setBeanFactory() on BeanFactoryAware bean '" + beanName + "'");
				}
				((BeanFactoryAware) bean).setBeanFactory(this);
			}
 //省略其他程式碼


	}

看到沒有,其實很簡單嘛!

三、demo

1、beanNameAware介面:

package com.pb.entity;

import org.springframework.beans.factory.BeanNameAware;
/*
 * 實體類實現init方法和BeanNameAware介面
 */
public class Hello implements BeanNameAware{

    @Override
    public void setBeanName(String arg0) {
        System.out.println("回撥setBeanName方法  id屬性是"+arg0);
        
    }
    public void init(){
        System.out.println("正在執行初始化方法init");
    }

}

applicationContext.xml

<bean id="hello" class="com.pb.entity.Hello" init-method="init"></bean>

測試類:

package com.pb.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.pb.entity.Hello;

public class HelloTest {

    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        Hello hello=context.getBean("hello",Hello.class);

    }

}

結果:

回撥setBeanName方法  id屬性是hello
正在執行初始化方法init

2、BeanFactoryAware介面:

package com.pb.entity;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
/*
 * 實體類實現init方法和BeanNameAware介面
 */
public class Hello implements BeanNameAware,BeanFactoryAware{
    private BeanFactory bf;
    @Override
    public void setBeanName(String arg0) {
        System.out.println("回撥setBeanName方法  id屬性是"+arg0);
        
    }
    public void init(){
        System.out.println("正在執行初始化方法init");
    }
    
    /*
     * 重寫setBeanFactory方法
     * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org.springframework.beans.factory.BeanFactory)
     */
    @Override
    public void setBeanFactory(BeanFactory arg0) throws BeansException {
        this.bf=arg0;
        
    }
    public BeanFactory getBf() {
        return bf;
    }


}

配置檔案不變

測試類:

package com.pb.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.pb.entity.Hello;

public class HelloTest {

    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        Hello hello=context.getBean("hello",Hello.class);
        System.out.println("得到beanFactory物件 "+hello.getBf());

    }

}

結果:

回撥setBeanName方法  id屬性是hello
正在執行初始化方法init
得到beanFactory物件 org.s[email protected]3dc0bb: defining beans [hello]; root of factory hierarchy