关于javascript:Spring-的-BeanFactory-和-FactoryBean-傻傻分不清

36次阅读

共计 12185 个字符,预计需要花费 31 分钟才能阅读完成。

ApplicationContext 接口,它由 BeanFactory 接口派生而来。

ApplicationContext 蕴含 BeanFactory 的所有性能,通常倡议比 BeanFactory 优先。

BeanFactory 和 FactoryBean 的区别
BeanFactory 是接口,提供了 OC 容器最根本的模式,给具体的 IOC 容器的实现提供了标准,FactoryBean 也是接口,为 IOC 容器中 Bean 的实现提供了更加灵便的形式,FactoryBean 在 IOC 容器的根底上给 Bean 的实现加上了一个简略工厂模式和装璜模式(如果想理解装璜模式参考:润饰者模式(装璜者模式,Decoration) 咱们能够在 getObject() 办法中灵便配置。其实在 Spring 源码中有很多 FactoryBean 的实现类.

区别:BeanFactory 是个 Factory,也就是 IOC 容器或对象工厂,FactoryBean 是个 Bean。在 Spring 中,所有的 Bean 都是由 BeanFactory(也就是 IOC 容器)来进行治理的。

但对 FactoryBean 而言,这个 Bean 不是简略的 Bean,而是一个能生产或者润饰对象生成的工厂 Bean, 它的实现与设计模式中的工厂模式和润饰器模式相似。

1、BeanFactory
BeanFactory,以 Factory 结尾,示意它是一个工厂类(接口),它负责生产和治理 bean 的一个工厂。在 Spring 中,BeanFactory 是 IOC 容器的外围接口,它的职责包含:实例化、定位、配置应用程序中的对象及建设这些对象间的依赖。

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

都是附加了某种性能的实现。它为其余具体的 IOC 容器提供了最根本的标准,例如 DefaultListableBeanFactory,XmlBeanFactory,ApplicationContext 等具体的容器都是实现了 BeanFactory,再在其根底之上附加了其余的性能。

BeanFactory 和 ApplicationContext 就是 spring 框架的两个 IOC 容器,当初个别应用 ApplicationnContext,其岂但蕴含了 BeanFactory 的作用,同时还进行更多的扩大。

BeanFacotry 是 spring 中比拟原始的 Factory。如 XMLBeanFactory 就是一种典型的 BeanFactory。

原始的 BeanFactory 无奈反对 spring 的许多插件,如 AOP 性能、Web 利用等。ApplicationContext 接口, 它由 BeanFactory 接口派生而来。

ApplicationContext 蕴含 BeanFactory 的所有性能,通常倡议比 BeanFactory 优先

ApplicationContext 以一种更向面向框架的形式工作以及对上下文进行分层和实现继承,ApplicationContext 包还提供了以下的性能:

MessageSource, 提供国际化的音讯拜访

资源拜访,如 URL 和文件

事件流传

载入多个(有继承关系)上下文,使得每一个上下文都专一于一个特定的档次,比方利用的 web 层;

在不应用 spring 框架之前,咱们的 service 层中要应用 dao 层的对象,不得不在 service 层中 new 一个对象。

存在的问题:层与层之间的依赖。service 层要用 dao 层对象须要配置到 xml 配置文件中,至于对象是怎么创立的,关系是怎么组合的都交给了 spring 框架去实现。

形式 1、

Resource resource = new FileSystemResource(“beans.xml”);
BeanFactory factory = new XmlBeanFactory(resource);
形式 2、

ClassPathResource resource = new ClassPathResource(“beans.xml”);
BeanFactory factory = new XmlBeanFactory(resource);
形式 3、

ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {“applicationContext.xml”, “applicationContext-part2.xml”});
BeanFactory factory = (BeanFactory) context;
根本就是这些了,接着应用 getBean(String beanName)办法就能够获得 bean 的实例;BeanFactory 提供的办法及其简略,仅提供了六种办法供客户调用:

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

Object getBean(String) 返回给定名称注册的 bean 实例。依据 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 名称的所有别名

package org.springframework.beans.factory;
import org.springframework.beans.BeansException;
public interface BeanFactory {

String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);

}

2、FactoryBean
个别状况下,Spring 通过反射机制利用的 class 属性指定实现类实例化 Bean,在某些状况下,实例化 Bean 过程比较复杂,如果依照传统的形式,则须要在中提供大量的配置信息。配置形式的灵活性是受限的,这时采纳编码的形式可能会失去一个简略的计划。

Spring 为此提供了一个 org.springframework.bean.factory.FactoryBean 的工厂类接口,用户能够通过实现该接口定制实例化 Bean 的逻辑。bean 为什么默认单例?举荐看下。关注微信公众号:Java 技术栈,在后盾回复:spring,能够获取我整顿的 N 篇 Spring 教程,都是干货。

FactoryBean 接口对于 Spring 框架来说占用重要的位置,Spring 本身就提供了 70 多个 FactoryBean 的实现。它们暗藏了实例化一些简单 Bean 的细节,给下层利用带来了便当。

从 Spring3.0 开始,FactoryBean 开始反对泛型,即接口申明改为 FactoryBean 的模式以 Bean 结尾,示意它是一个 Bean,不同于一般 Bean 的是:它是实现了 FactoryBean 接口的 Bean,依据该 Bean 的 ID 从 BeanFactory 中获取的实际上是 FactoryBean 的 getObject()返回的对象,而不是 FactoryBean 自身,如果要获取 FactoryBean 对象,请在 id 后面加一个 & 符号来获取。

例如本人实现一个 FactoryBean,性能:用来代理一个对象,对该对象的所有办法做一个拦挡,在调用前后都输入一行 LOG,模拟 ProxyFactoryBean 的性能。

/**

  • my factory bean<p>
  • 代理一个类,拦挡该类的所有办法,在办法的调用前后进行日志的输入
  • @author daniel.zhao
    *
    */

public class MyFactoryBean implements FactoryBean<Object>, InitializingBean, DisposableBean {

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 配置如下

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

@RunWith(JUnit4ClassRunner.class)
@ContextConfiguration(classes = { MyFactoryBeanConfig.class})
public class MyFactoryBeanTest {

@Autowired
private ApplicationContext context;
/**
 * 测试验证 FactoryBean 原理,代理一个 servcie 在调用其办法的前后,打印日志亦可作其余解决
 * 从 ApplicationContext 中获取自定义的 FactoryBean
 * context.getBean(String beanName) ---> 最终获取到的 Object 是 FactoryBean.getObejct(),
 * 应用 Proxy.newInstance 生成 service 的代理类
 */
@Test
public void testFactoryBean() {HelloWorldService helloWorldService = (HelloWorldService) context.getBean("fbHelloWorldService");
    helloWorldService.getBeanName();
    helloWorldService.sayHello();}

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

package org.springframework.beans.factory;
public interface FactoryBean<T> {

T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();

}
在该接口中还定义了以下 3 个办法:

TgetObject():返回由 FactoryBean 创立的 Bean 实例,如果 isSingleton()返回 true,则该实例会放到 Spring 容器中单实例缓存池中;

booleanisSingleton():返回由 FactoryBean 创立的 Bean 实例的作用域是 singleton 还是 prototype;

ClassgetObjectType():返回 FactoryBean 创立的 Bean 类型。

当配置文件中的 class 属性配置的实现类是 FactoryBean 时,通过 getBean()办法返回的不是 FactoryBean 自身,而是 FactoryBean#getObject()办法所返回的对象,相当于 FactoryBean#getObject()代理了 getBean()办法。例:如果应用传统形式配置上面 Car 的时,Car 的每个属性别离对应一个元素标签。

package com.baobaotao.factorybean;

public   class  Car  {
    private   int maxSpeed ;
    private  String brand ;
    private   double price ;
    public   int  getMaxSpeed ()   {return   this . maxSpeed ;}
    public   void  setMaxSpeed (int  maxSpeed)   {this . maxSpeed = maxSpeed;}
    public  String getBrand ()   {return   this . brand ;}
    public   void  setBrand (String brand)   {this . brand = brand;}
    public   double  getPrice ()   {return   this . price ;}
    public   void  setPrice (double  price)   {this . price = price;}

}
如果用 FactoryBean 的形式实现就灵便点,下例通过逗号宰割符的形式一次性的为 Car 的所有属性指定配置值:

package com.baobaotao.factorybean;
import org.springframework.beans.factory.FactoryBean;
public class CarFactoryBean implements FactoryBean<Car> {

private  String carInfo ;
public  Car getObject ()   throws  Exception {Car car = new  Car () ;
    String [] infos = carInfo .split ( ",") ;
    car.setBrand (infos [ 0]) ;
    car.setMaxSpeed (Integer. valueOf ( infos [ 1])) ;
    car.setPrice (Double. valueOf ( infos [ 2])) ;
    return  car;
}
public  Class<Car> getObjectType ()   {return  Car. class;}
public   boolean  isSingleton ()   {return   false ;}
public  String getCarInfo ()   {return   this . carInfo ;}

// 承受逗号宰割符设置属性信息
public   void  setCarInfo (String carInfo)   {this . carInfo = carInfo;}

}
有了这个 CarFactoryBean 后,就能够在配置文件中应用上面这种自定义的配置形式配置 CarBean 了:

<bean d=”car”class=”com.baobaotao.factorybean.CarFactoryBean”
P:carInfo=” 法拉利,400,2000000″/>
当调用 getBean(“car”)时,Spring 通过反射机制发现 CarFactoryBean 实现了 FactoryBean 的接口,这时 Spring 容器就调用接口办法 CarFactoryBean#getObject()办法返回。

如果心愿获取 CarFactoryBean 的实例,则须要在应用 getBean(beanName)办法时在 beanName 前显示的加上”&”前缀:如 getBean(“&car”);

上面是一个利用 FactoryBean 的例子

<beans xmlns=”http://www.springframework.org/schema/beans”

         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:context="http://www.springframework.org/schema/context"
         xmlns:aop="http://www.springframework.org/schema/aop"
         xmlns:tx="http://www.springframework.org/schema/tx"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
                 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                 http://www.springframework.org/schema/context
                 http://www.springframework.org/schema/context/spring-context-3.0.xsd
                 http://www.springframework.org/schema/aop
                 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
                 http://www.springframework.org/schema/tx
                 http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

<bean id=”student” class=”com.spring.bean.Student”>
<property name=”name” value=”zhangsan” />
</bean>

<bean id=”school” class=”com.spring.bean.School”>
</bean>

<bean id=”factoryBeanPojo” class=”com.spring.bean.FactoryBeanPojo”>

<property name="type" value="student" />

</bean>
</beans>
FactoryBean 的实现类

import org.springframework.beans.factory.FactoryBean;

/**

  • @author 作者 wangbiao
  • @parameter
  • @return
    */

public class FactoryBeanPojo implements FactoryBean{

private String type;

@Override
public Object getObject() throws Exception {if("student".equals(type)){return new Student();
    }else{return new School();
    }

}

@Override
public Class getObjectType() {return School.class;}

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

public String getType() {return type;}

public void setType(String type) {this.type = type;}

}
一般的 bean

/**

  • @author 作者 wangbiao
  • @parameter
  • @return
    */

public class School {

private String schoolName;
private String address;
private int studentNumber;
public String getSchoolName() {return schoolName;}
public void setSchoolName(String schoolName) {this.schoolName = schoolName;}
public String getAddress() {return address;}
public void setAddress(String address) {this.address = address;}
public int getStudentNumber() {return studentNumber;}
public void setStudentNumber(int studentNumber) {this.studentNumber = studentNumber;}
@Override
public String toString() {
    return "School [schoolName=" + schoolName + ", address=" + address
            + ", studentNumber=" + studentNumber + "]";
}

}
测试类

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.spring.bean.FactoryBeanPojo;

/**

  • @author 作者 wangbiao
  • @parameter
  • @return
    */

public class FactoryBeanTest {

public static void main(String[] args){
    String url = "com/spring/config/BeanConfig.xml";
    ClassPathXmlApplicationContext cpxa = new ClassPathXmlApplicationContext(url);
    Object school= cpxa.getBean("factoryBeanPojo");
    FactoryBeanPojo factoryBeanPojo= (FactoryBeanPojo) cpxa.getBean("&factoryBeanPojo");
    System.out.println(school.getClass().getName());
    System.out.println(factoryBeanPojo.getClass().getName());
}

}
输入的后果:

十一月 16, 2016 10:28:24 上午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1e8ee5c0: startup date [Wed Nov 16 10:28:24 CST 2016]; root of context hierarchy
十一月 16, 2016 10:28:24 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [com/spring/config/BeanConfig.xml]
十一月 16, 2016 10:28:24 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@35b793ee: defining beans [student,school,factoryBeanPojo]; root of factory hierarchy
com.spring.bean.Student
com.spring.bean.FactoryBeanPojo
从后果上能够看到当从 IOC 容器中获取 FactoryBeanPojo 对象的时候,用 getBean(String BeanName)获取确实是 Student 对象,能够看到在 FactoryBeanPojo 中的 type 属性设置为 student 的时候,会在 getObject()办法中返回 Student 对象。

所以说从 IOC 容器获取实现了 FactoryBean 的实现类时,返回的却是实现类中的 getObject 办法返回的对象,要想获取 FactoryBean 的实现类,得在 getBean(String BeanName)中的 BeanName 之前加上 &, 写成 getBean(String &BeanName)。

最初
如果你感觉此文对你有一丁点帮忙,点个赞。或者能够退出我的开发交换群:1025263163 互相学习,咱们会有业余的技术答疑解惑

如果你感觉这篇文章对你有点用的话,麻烦请给咱们的开源我的项目点点 star: https://gitee.com/ZhongBangKe… 不胜感激!

JAVA 学习手册:https://doc.crmeb.com
技术交换论坛:https://q.crmeb.com

正文完
 0