Spring原理解析 之FactoryBean、BeanFactory区别

FactoryBean

创建对象的工厂 Bean ,可以使用它来直接创建一些初始化流程比较复杂的对象。

FactoryBean接口是SpringIoC容器实例化逻辑的扩展点,为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式, 我们可以在getObject()方法中灵活配置。其实在Spring源码中有很多FactoryBean的实现类。

Spring提供了一个org.springframework.bean.factory.FactoryBean<T>的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。

在Spring框架内部,有很多地方有FactoryBean的实现类,它们在很多应用如(Spring的AOP、ORM、事务管理)及与其它第三框架(ehCache)集成时都有体现。

什么叫扩展点?
Spring处理Bean生命周期的时候在Bean初始化前后回调自定义方法就是扩展点。

BeanFactory

BeanFactory是接口,提供了OC容器最基本的形式,给具体的IOC容器的实现提供了规范。

BeanFactory,以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理Bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

BeanFacotry接口是Spring中比较原始的Factory,Ioc容器顶级接口。如XMLBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持Spring的许多插件,如AOP功能、Web应用等。

BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。

BeanFactory和ApplicationContext就是spring框架的两个IOC容器,现在一般使用ApplicationnContext,其不但包含了BeanFactory的作用,同时还进行更多的扩展。

ApplicationContext接口,它由BeanFactory接口派生而来。ApplicationContext包含BeanFactory的所有功能,通常建议比BeanFactory优先。

ApplicationContext以一种更向面向框架的方式工作,通常工作中说的Spring上下文就是ApplicationContext。

FactoryBean和BeanFactory的区别

BeanFactory是个Factory,是个生产Bean的工厂,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。
FactoryBean是个Bean,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似

FactoryBean和普通Bean的区别

Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean即FactoryBean,这两种Bean都被容器管理。
工厂Bean是实现了org.springframework.beans.factory.FactoryBean<T>接口的Bean,凡是实现了FactoryBean的Bean,从ApplicationContext的getBean()方法获取的对象不是该类的一个实例,而是该类的getObject()方法所返回的对象。

当我们需要获取FactoryBean实例本身而不是它所产生的Bean,则要使用&符号。
比如,现有FactoryBean,id为playerBean,在容器上调用getBean("playerBean")将返回FactoryBean产生的Bean。调用getBean("&playerBean")将返回FactoryBean它本身的实例。

FactoryBean使用场景

需求: 用来代理一个对象,对该对象的所有方法做一个拦截,在调用前后都输出一行日志。
自定义实现一个FactoryBean:

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

import java.lang.reflect.Proxy;

// 代理一个类,拦截该类的所有方法,在方法的调用前后进行日志的输出
public class MyFactoryBean implements FactoryBean<Object>, InitializingBean, DisposableBean {
    // 被代理类的接口
    private String interfaceName;
    // 被代理类的实现
    private Object target;
    // 代理类
    private Object proxyObj;

    @Override
    public Object getObject() throws Exception {
        System.out.println("getObject......");
        return proxyObj;
    }

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

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

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

    @Override
    public void destroy() throws Exception {
        System.out.println("destroy......");
    }

    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;
    }
}

被代理的接口和实现类:

public interface DemoService {
    void sayHello();
}

public class DemoServiceImpl implements DemoService {
    @Override
    public void sayHello() {
        System.out.println("sayHello...");
    }
}

beans.xml中配置:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="demoService" class="com.demo.config.DemoServiceImpl"/>
    <bean id="proxyDemoService" class="com.demo.config.MyFactoryBean"
          p:interfaceName="com.demo.config.DemoService"
          p:target-ref="demoService" />
</beans>

测试:

@Test
public void testFactoryBean() {
    ApplicationContext context = new ClassPathXmlApplicationContext("classpath:beans.xml");
    DemoService bean = (DemoService) context.getBean("proxyDemoService");
    bean.sayHello();
	MyFactoryBean myFactoryBean = (MyFactoryBean) context.getBean("&proxyDemoService");
	System.out.println(myFactoryBean);
}

结果:
afterPropertiesSet......
getObject......
invoke method......sayHello
invoke method before......1585039614627
sayHello...
invoke method after......1585039614627
com.demo.config.MyFactoryBean@3d299e3

FactoryBean是一个接口,当在IOC容器中的Bean实现了FactoryBean后,通过getBean(String BeanName)获取到的Bean对象并不是FactoryBean的实现类对象,而是这个实现类中的getObject()方法返回的对象。要想获取FactoryBean的实现类,就要getBean(&BeanName),在BeanName之前加上&。

需求二:
足球运动员踢球。

// 运动员动作接口
public interface PlayerActionInterface {
    void shoot();
    void pass();
}

// 实现一个足球运动员
public class FootballPlayer implements PlayerActionInterface {
    String name;//球员名字
    String team;//所在球队
    // 省略getter、setter
}
    

beans.xml中配置:

<bean id="footballPlayer" class="com.mvc.FootballPlayer">
    <property name="name" value="C.罗纳尔多"></property>
</bean>

现在有一个新的需求,要求每个球员在做射门和传球这两个动作之前,先要“观察进攻及防守队员跑位”;做完动作后要完成“无球跑动”。
本着开闭原则,在不修改原有类的基础上,我们创建一个代理类来实现。

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;

public class PlayerFactory implements FactoryBean<PlayerActionInterface>, InitializingBean,
        DisposableBean {

    /*被代理的PlayerActionInterface实现对象,通过XML注入*/
    private PlayerActionInterface target;

    /*本类生成的代理对象*/
    private PlayerActionInterface proxyObj;

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");
        proxyObj = (PlayerActionInterface) Proxy.newProxyInstance(this.getClass().getClassLoader(),
                new Class[] { Class.forName("com.mvc.PlayerActionInterface") },
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method,
                                         Object[] args) throws Throwable {
                        System.out.println("method:" + method.getName());
                        System.out.println("观察进攻及防守队员跑位");
                        Object result = method.invoke(target, args);
                        System.out.println("无球跑动");
                        return result;
                    }
                });
    }

    @Override
    public PlayerActionInterface getObject() throws Exception {
        System.out.println("getObject");
        return proxyObj;
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("distory");
    }

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

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

    public PlayerActionInterface getTarget() {
        return target;
    }
    
    public void setTarget(PlayerActionInterface target) {
        this.target = target;
    }
    
}

可以看到在PlayerFactory这个类,我们实现了FactoryBean接口的三个方法。其中getObject()方法返回的是代理对象proxyObj。
这个对象是在bean初始化的时候回调InitializingBean接口的实现方法afterPropertiesSet()里创建的。使用了Proxy.newProxyInstance给原来的类创建了一个代理类,该代理类在方法调用的前后都加上了动作。

最后在beans.xml中定义:

<bean id="playerfacory" class="com.mvc.PlayerFactory">
    <property name="target" ref="footballPlayer"></property>
</bean>

业务代码调用:

import com.mvc.PlayerActionInterface;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class IOCTest {

    @Test
    public void test(){
        ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext.xml");
        // 最终调用getObject来获取实例对象
        Object obj1 = ctx.getBean("playerfacory");
        // 加上&,表示获取的是实例的本身
        Object obj2 = ctx.getBean("&playerfacory");
        System.out.println("ctx.getBean(\"playerfacory\"):"+obj1.getClass().getName());
        System.out.println("ctx.getBean(\"&playerfacory\"):"+obj2.getClass().getName());
        System.out.println("-----------------------");
        PlayerActionInterface smone = ctx.getBean("playerfacory",
                PlayerActionInterface.class);
        smone.shoot();
        System.out.println("");
        smone.pass();
    }
}

输出:

afterPropertiesSet
getObject
ctx.getBean("playerfacory"):com.sun.proxy.$Proxy3
ctx.getBean("&playerfacory"):com.mvc.PlayerFactory
-----------------------
method:shoot
观察进攻及防守队员跑位
C.罗纳尔多射门
无球跑动

method:pass
观察进攻及防守队员跑位
C.罗纳尔多边路传中
无球跑动
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值