013_BeanFactory和FactoryBean

2020-10-25   17 次阅读


1.1 BeanFacotry

  1. BeanFacotry是spring中比较原始的Factory。如XMLBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。
  2. ApplicationContext接口,它由BeanFactory接口派生而来。ApplicationContext包含BeanFactory的所有功能,通常建议优先使用此接口。
  3. 以Factory结尾,表示它是一个工厂类(提供规范的接口),它负责生产和管理bean的一个工厂,是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
  4. 获取ApplicationContext实例
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
BeanFactory factory = (BeanFactory) context;

/*
boolean containsBean(String beanName): 判断工厂中是否包含给定名称的bean定义,若有则返回true

Object getBean(String): 返回给定名称注册的bean实例。如果是singleton模式将返回一个共享实例,否则将返回一个新建的实例,如果没有找到指定bean,该方法可能会抛出异常

Object getBean(String, Class): 返回以给定名称注册的bean实例,并转换为给定class类型

Class getType(String name): 返回给定名称的bean的Class,如果没有找到指定的bean实例,则排除NoSuchBeanDefinitionException异常

boolean isSingleton(String) 判断给定名称的bean定义是否为单例模式

String[] getAliases(String name) 返回给定bean名称的所有别名
*/

1.2 FactoryBean

  1. 一般情况下,Spring在XML中通过反射机制利用的class属性指定实现类实例化Bean,但当实例化Bean过程比较复杂时通过实现FactoryBean接口是一个更好的方案。
  2. 不同于普通Bean的是,从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取。

实现,模仿ProxyFactoryBean的功能,代理并拦截所有方法

package site.javaee.docker_demo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author Tao
 * @Date 2020/10/25
 * @Time 11:27
 */
public class MyFactoryBean implements FactoryBean<Object>, InitializingBean, DisposableBean {

/*

TgetObject():返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中
booleanisSingleton():返回由FactoryBean创建的Bean实例的作用域是singleton还是prototype;
Class<T>getObjectType():返回FactoryBean创建的Bean类型。
*/
    private static final Logger logger = LoggerFactory.getLogger(MyFactoryBean.class);
    private String interfaceName;
    private Object target;
    private Object proxyObj;

    @Override
    public void destroy() throws Exception {
        logger.debug("destroy......");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        proxyObj = Proxy.newProxyInstance(
                this.getClass().getClassLoader(),
                new Class[]{Class.forName(interfaceName)},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        logger.debug("invoke method......" + method.getName());
                        logger.debug("invoke method before......" + System.currentTimeMillis());
                        Object result = method.invoke(target, args);
                        logger.debug("invoke method after......" + System.currentTimeMillis());
                        return result;
                    }
                });
        logger.debug("afterPropertiesSet......");
    }

    @Override
    public Object getObject() throws Exception {
        logger.debug("getObject......");
        return proxyObj;
    }

    @Override
    public Class<?> getObjectType() {
        return proxyObj == null ? Object.class : proxyObj.getClass();
    }

    @Override
    public boolean isSingleton() {
        return true;    
    }

    public String getInterfaceName() {
        return interfaceName;
    }

    public void setInterfaceName(String interfaceName) {
        this.interfaceName = interfaceName;
    }

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    public Object getProxyObj() {
        return proxyObj;
    }

    public void setProxyObj(Object proxyObj) {
        this.proxyObj = proxyObj;
    }

}

xml

<bean id="fbHelloWorldService" class="com.ebao.xxx.MyFactoryBean">
   <property name="interfaceName" value="com.ebao.xxx.HelloWorldService" />
   <property name="target" ref="helloWorldService" />
</bean>

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议