【Spring学习22】容器扩展点:FactoryBean

FactoryBean接口是Spring IoC容器实例化逻辑的扩展点。什么叫扩展点?还记得前面说的bean生命周期(点击回顾)吗,Spring处理Bean生命周期的回调的事件就是扩展点。往下看例子就会明白。

一、区别FactoryBean和BeanFactory

首先不要混淆FactoryBean和BeanFactory。
BeanFactory直译是生产Bean的工厂,在Srping中就是容器,常用的ApplicationContext就是它的一个继承类。我们也可以直接使用BeanFactory示例:

BeanFactory factory = new XmlBeanFactory(new FileSystemResource("c:/piratebean.xml"));

而FactoryBean顾名思义就是一个bean,但这个bean和普通bean有点不同。

二、区别FactoryBean和普通Bean

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

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

三、使用场景

当需要在类中撰写复杂的初始化程序,此时使用java编码比使用XML配置更容易表达。我们常接触的代理类就可以用这个接口实现(最后有例子)。
在Spring框架内部,有很多地方有FactoryBean的实现类,它们在很多应用如(Spring的AOP、ORM、事务管理)及与其它第三框架(ehCache)集成时都有体现.

四、示例

原有的程序中已有一个接口及实现:

接口:

package twm.spring.LifecycleTest;
public interface PlayerActionInterface {
    void shoot();
    void pass();
}

实现:

package twm.spring.LifecycleTest;
public class footballPlayer implements PlayerActionInterface{

    String name;//球员名字
    String team;//所在球队

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getTeam() {
        return team;
    }
    public void setTeam(String team) {
        this.team = team;
    }
    @Override
    public void shoot() {
        System.out.println(this.getName()+"射门");
    }
    @Override
    public void pass() {
        System.out.println(this.getName()+"边路传中");
    }
}

beans.xml中配置:

<bean id="cluo" class="twm.spring.LifecycleTest.footballPlayer">
    <property name="name" value="C.罗纳尔多"></property>
</bean>

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

package twm.spring.LifecycleTest;

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

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

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

    /*被代理的PlayerActionInterface实现对象,通过XML注入*/
    private PlayerActionInterface target;
    public PlayerActionInterface getTarget() {
        return target;
    }
    public void setTarget(PlayerActionInterface target) {
        this.target = target;
    }

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


    /*在容器设置bean必须的属性之后执行初始化工作*/
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");
        proxyObj = (PlayerActionInterface)Proxy.newProxyInstance(this.getClass().getClassLoader(),
                new Class[] { Class.forName("twm.spring.LifecycleTest.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;
                    }
                });
    }
    public void destroy() throws Exception {
        System.out.println("distory");
    }

    @Override
    public PlayerActionInterface 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;
    }
}

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

最后在beans.xml中定义:

<bean id="playerfacory" class="twm.spring.LifecycleTest.PlayerFactory">
    <property name="target" ref="cluo"></property>
</bean>

业务代码调用:

public class Test {
    public static void main(String[] args) throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        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();
    }
}

输出:

getObject
ctx.getBean(“playerfacory”):com.sun.proxy.$Proxy1
ctx.getBean(“&playerfacory”):twm.spring.LifecycleTest.PlayerFactory
-----------------------
method:shoot
C.罗纳尔多射门
无球跑动

method:pass
观察进攻及防守队员跑位
C.罗纳尔多边路传中
无球跑动

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值