小记BeanFactory 与 FactoryBean的区别

本文深入探讨了Spring框架中BeanFactory与FactoryBean的区别及应用场景。BeanFactory是Spring的基础工厂,而FactoryBean则用于复杂Bean的创建逻辑。文章通过代码示例展示了如何使用FactoryBean定制Bean的实例化过程。

BeanFactory 与 FactoryBean的区别

1. BeanFactory

    BeanFacotry是spring中比较原始的Factory。如XMLBeanFactory就是一种典型的BeanFactory。
    原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。 
    
    ApplicationContext接口,它由BeanFactory接口派生而来,ApplicationContext包含BeanFactory的所有功能,
    通常建议比BeanFactory优先
    常见:xmlBeanFactory (从spring 3.1版本后,xmlBeanFactory被表明为Deprecated. 
                        推荐使用DefaultListableBeanFactory和XmlBeanDefinitionReader替换)

2. FactoryBean

    以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean<T>接口的Bean,
    根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,
    如果要获取FactoryBean对象,请在id前面加一个&符号来获取。
    
    为什么使用FactoryBean : 一般情况下,Spring通过反射机制利用<bean>的class属性指定实现类实例化Bean,在某些情况下,
    实例化Bean过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息。配置方式的灵活性是受限的,
    这时采用编码的方式可能会得到一个简单的方案。
    Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制
    实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,
    Spring自身就提供了70多个FactoryBean的实现.
    SqlSessionFactoryBean , MapperFactoryBean 。
package com.springcloud.beanTest;

import com.springcloud.MybatisApplication;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

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

/**
 * @Auther:ok168
 * @Date: 2019/4/24 16:44
 * @Description:
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {MybatisApplication.class})
@Slf4j
@Import(FactoryBeanTest2.class)
public class FactoryBeanTest{

    @Autowired
    private ApplicationContext context;

    @Test
    public void test(){
        FactoryBeanTest2 factoryBeanTest2= (FactoryBeanTest2)context.getBean(FactoryBeanTest2.class);
        log.info("myBean = " + factoryBeanTest2.getObject() );

        MyBeanService myBean = (MyBeanService) factoryBeanTest2.getObject();
        myBean.sayHello("hello,我是factoryBeanTest2.getObject得到的!");

        MyBeanService myBean2= (MyBeanService)context.getBean(MyBeanService.class);
        myBean2.sayHello("hello,我是context.getBean得到的!");
    }

}

@Slf4j
class FactoryBeanTest2 implements FactoryBean<Object> , InitializingBean {
    //接口类
    private String interfaceName = "com.springcloud.beanTest.MyBeanService";
    //bean
    private Object target = new MyBean();
    //代理类对象
    private Object proxyObj;

    @Override
    public Object getObject(){
        return proxyObj;
    }

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

    // 模仿ProxyFactoryBean的功能
    @Override
    public void afterPropertiesSet() throws Exception {
        // require interface

        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 {

                log.info("invoke method before......" + System.currentTimeMillis());
                Object result = method.invoke(target, args);
                log.info("invoke method after......" + System.currentTimeMillis());

                return result;
            }
        });

        log.info("proxyObj = " + proxyObj );
    }
}

interface MyBeanService{
    public void sayHello(String msg);

}

class MyBean implements MyBeanService{
    @Override
    public void sayHello(String msg){
        System.out.println(StringUtils.defaultIfEmpty(msg , "msg是空的!"));
    }

}

PS : @Slf4j注解 安装lombok插件 : https://www.cnblogs.com/shindo/p/7550790.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值