spring FactoryBean 学习笔记【抄】

本节,我们最分析ioc的最后一个核心点,那就是FactoryBean;
在ioc中,存在着这样的一种bean,他的引用并不是只想他自身,而 是通过折射指向了别的bean,就因为他的存在,使得他支持了jdbc,jndi等多种j2ee技术,他维持了spring的80%的功能的实现,那么, 就让我们来详细的分析一些这个神奇的bean,就好像武林外传里面的秀才杀死姬无命一样的,谁到底是谁,我们看似在取得factoryBean,却拿到了 另外的一个类,失之东隅,收之桑榆;

我们以MethodInvokingFactoryBean为例子,这是一个很奇妙的bean,如下配置:

<bean name="methodInvoke" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod">
  <value>org.corey.demo.Demo.staticMethod</value>
</property>
</bean>


我们在代码:

  1. ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");


  2. ac.getBean("methodInvoke");


  1. ac.getBean("methodInvoke");返回的是org.corey.demo.Demo类的staticMethod方法的返回值;

那么,我们来看一下这些都是怎么实现的:

spring FactoryBean 学习笔记【抄】

我们具体来看下几个类的代码:

public interface FactoryBean {
        
        Object getObject() throws Exception;
        Class getObjectType();
        
        boolean isSingleton();
    }


InitializingBean接口的话,我们已经不用介绍了;

MethodInvoker类主要含有这几个类:

  1.   

    private Class targetClass;
            private Object targetObject;
            private String targetMethod;
            private Object[] arguments;
            // the method we will call
            private Method methodObject;
    
    
    MethodInvoker类正式实现了MethodInvokingFactoryBean方法转嫁的核心功能,我们从入口来分析一下这个类:
    
            public void afterPropertiesSet() throws Exception {
                prepare();
                if (this.singleton) {
                    Object obj = doInvoke();
                    this.singletonObject = (obj != null ? obj : MethodInvoker.VOID);
                }
            }
    
    这是MethodInvokingFactoryBean的初始化方法:
    
        ublic void prepare() throws ClassNotFoundException, NoSuchMethodException {
                if (this.targetClass == null) {
                    throw new IllegalArgumentException("Either targetClass or targetObject is required");
                }
                if (this.targetMethod == null) {
                    throw new IllegalArgumentException("targetMethod is required");
                }
                if (this.arguments == null) {
                    this.arguments = new Object[0];
                }
                Class[] argTypes = new Class[this.arguments.length];
                for (int i = 0; i < this.arguments.length; ++i) {
                    argTypes[i] = (this.arguments[i] != null ? this.arguments[i].getClass() : Object.class);
                }
                // Try to get the exact method first.
                try {
                    this.methodObject = this.targetClass.getMethod(this.targetMethod, argTypes);
                }
                catch (NoSuchMethodException ex) {
                    // Just rethrow exception if we can't get any match.
                    this.methodObject = findMatchingMethod();
                    if (this.methodObject == null) {
                        throw ex;
                    }
                }
                if (this.targetObject == null && !Modifier.isStatic(this.methodObject.getModifiers())) {
                    throw new IllegalArgumentException("Target method must not be non-static without a target");
                }
            }

    将你在xml文件中配置的MethodInvokingFactoryBean的属性(字符串)转化成为元数据,为等下的调用做准备;

private Object doInvoke() throws Exception {
            try {
                return invoke();
            }
            catch (InvocationTargetException ex) {
                if (ex.getTargetException() instanceof Exception) {
                    throw (Exception) ex.getTargetException();
                }
                if (ex.getTargetException() instanceof Error) {
                    throw (Error) ex.getTargetException();
                }
                throw ex;
            }
        }

        public Object invoke() throws InvocationTargetException, IllegalAccessException {
            if (this.methodObject == null) {
                throw new IllegalStateException("prepare() must be called prior to invoke() on MethodInvoker");
            }
            // In the static case, target will just be <code>null</code>.
            return this.methodObject.invoke(this.targetObject, this.arguments);
        }




在这里分别调用了开始准备的目标类和目标方法;得到结果并且把他存储在singletonObject中,

在factoryBean接口中,实现了这个方法:

public Object getObject() throws Exception {
            if (this.singleton) {
                // Singleton: return shared object.
                return this.singletonObject;
            }
            else {
                // Prototype: new object on each call.
                Object retVal = doInvoke();
                return (retVal != null ? retVal : MethodInvoker.VOID);
            }
        }

用getObject把真正的bean返回出去了,那么,现在我们的疑问来了,我们在getBean的时候,什么时候调用了这个getObject()方法呢???

我们来看一下getBean的实现:
在AbstractBeanFactory中,
public Object getBean(String name, Class requiredType, Object[] args) throws BeansException
是一个典型的模板模式的应用,他的createBean();在AbstractAutowireCapableBeanFactory实现,他负责从BeanDefinition构造出一个Objct,而getBean在拿到这个Object后,就会调用第三步:

bean = getObjectForSharedInstance(name, sharedInstance);

从这个Object类中拿到一个真正我们要返回出去的bean,而这里主要就是我们的factoryBean的处理;

protected Object getObjectForSharedInstance(String name, Object beanInstance) throws BeansException {
            String beanName = transformedBeanName(name);
            // Don't let calling code try to dereference the
            // bean factory if the bean isn't a factory.
            if (isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
                throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
            }
            // Now we have the bean instance, which may be a normal bean or a FactoryBean.
            // If it's a FactoryBean, we use it to create a bean instance, unless the
            // caller actually wants a reference to the factory.
            if (beanInstance instanceof FactoryBean) {
                if (!isFactoryDereference(name)) {
                    // Return bean instance from factory.
                    FactoryBean factory = (FactoryBean) beanInstance;
                    if (logger.isDebugEnabled()) {
                        logger.debug("Bean with name '" + beanName + "' is a factory bean");
                    }
                    try {
                        beanInstance = factory.getObject();
                    }
                    catch (Exception ex) {
                        throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
                    }
                    if (beanInstance == null) {
                        throw new FactoryBeanNotInitializedException(
                            beanName, "FactoryBean returned null object: " +
                                "probably not fully initialized (maybe due to circular bean reference)");
                    }
                }
                else {
                    // The user wants the factory itself.
                    if (logger.isDebugEnabled()) {
                        logger.debug("Calling code asked for FactoryBean instance for name '" + beanName + "'");
                    }
                }
            }
            return beanInstance;
        }

transformedBeanName去掉了beanName的&符号;
isFactoryDereference(name)判断一个类名是不是以&开头,如果这个类是FactoryBean并且beanName以&开头,那么则返回这个FactoryBean的本身,如果不是以&开始,则返回他所要转换的类;
 beanInstance = factory.getObject();

就这样,我们在不知不觉的就完成这次南水北调的转换! *_*

最 后,我们来总结一下Spring代码的此功能实现,在整个实现中,spring的代码都很有调理,很好的体现了面向接口编程,几乎每个具体的类(工具类除 外)都是从接口开始着手,并且一层一层就想洋葱一样展现在我们的眼前,比如,首先,抽象出来一个顶层的factoryBean接口,提供了bean转换的 统一接口,为我们组合型模板方式提供了可能,我们只要在beanFactory中调用他的getObject,而不必管这个类是从jndi还是从别的类的 方法中得到的,从而把BeanFactory与具体的FactoryBean实现解耦开来,而且在MethodInvokingFacrotyBean 中,我们把转换方法的实现用继承的方式委托给了MethodInvoker,功能复用的方式有两种,一种如这个一样的继承,坏处就是这是一种编译器的复 用,无法实现策略模式一样的转换算法的功能,但是他好的就是我们不用显示的把委托代码重新写一次,而组合复用的好处是我们可以更换不同的 MethodInvoker的实现,如果这里的targetClass和targetMethod有另外的处理方式,即MethodInvoker有另外 的实现方式,我们可以考虑使用,如果没有的话,我们选择更方便的继承方式;
在代码中,大量的使用了工具类,这是单一职责原则的体现,为了避免意外 的情况发生,或者说用户的盲目扩展,很多公开地方做了防御性的判断,并且在意外情况发生,输入参数非法的地方,抛出了明确的异常,这正式代码大全里所说的 防御性编程的良好的体现,往往是这么一些微小的细节,更加的体现了大牛们代码的质量;设计的合理;这些都是值得我们深入去研究的地方;

因 为我也初出茅庐,这些文章也只是我看spring源代码的一些小小的心得,在分享给有需要的朋友的同时,其实更多的是给自己招一个随处可得的笔记本,希望 大家能够多多交流,在前面的getBean方法中也许分析得有些模糊,但是通过前几节对反射的重新复习,cglib的应用和asm的了解,和对ioc的代 码一些全局的了解,现在我们再去看getBean代码,基本上不存在着什么疑问,至少我是这样的;所以,我想ioc的分析,应该就差不多到这里了,而 spring的微核就是这个ioc容器,搞清楚这些对我们将来分析外围打下一个良好的基础;

你可能感兴趣的:(spring FactoryBean 学习笔记【抄】)