Is Spring's BeanFactory confused with FactoryBean?

Keywords: Java Spring xml Attribute

BeanFacotry is the more primitive Factory in spring.XMLBeanFactory, for example, is a typical BeanFactory.The original BeanFactory did not support many of Spring's plug-ins, such as AOP capabilities, Web applications, and so on.

The ApplicationContext interface, which is derived from the BeanFactory interface.

The ApplicationContext contains all the capabilities of the BeanFactory and is generally recommended to take precedence over the BeanFactory.

Differences between BeanFactory and FactoryBean

BeanFactory is an interface that provides the basic form of OC container, provides specification for the implementation of specific IOC container, FactoryBean is also an interface, provides a more flexible way to implement Bean in IOC container, FactoryBean adds a simple factory mode and decoration mode to Bean's implementation based on IOC container (if you want to know decoration mode reference: Decorator mode).Decoration) We can configure it flexibly in the getObject() method.There are actually many implementation classes for FactoryBean in the Spring source.

The difference: BeanFactory is a Factory, that is, an IOC container or an object factory, and FactoryBean is a Bean.stay Spring In, all beans are managed by the Bean Factory (also known as the IOC container).

But for FactoryBean, this Bean is not a simple Bean, but a factory Bean that can produce or modify objects. Its implementation and Design Mode The factory mode and modifier mode in are similar.

1,BeanFactory

BeanFactory, which ends with Factory, means it is a factory class (interface) responsible for producing and managing bean s.In Spring, BeanFactory is the core interface of the IOC container and its responsibilities include instantiating, locating, configuring objects in the application, and establishing dependencies between them.

BeanFactory is just an interface, not a concrete implementation of the IOC container, but the Spring container gives many implementations, such as DefaultListableBeanFactory, XmlBeanFactory, ApplicationContext, etc. Among them, XmlBeanFactory is one of the most commonly used implementations, which describes in XML the objects that make up the application and the dependencies between them.The XmlBeanFactory class will hold this XML configuration metadata and use it to build a fully configurable system or application.

They are implementations with some additional functionality attached.It provides the most basic specification for other specific IOC containers, such as DefaultListableBeanFactory,XmlBeanFactory,ApplicationContext, which implement BeanFactory and attach other functions to it.

BeanFactory and ApplicationContext are the two IOC containers of the spring Framework. Now, ApplicationnContext is commonly used, which not only includes the role of BeanFactory, but also extends it further.

BeanFacotry is the more primitive Factory in spring.XMLBeanFactory, for example, is a typical BeanFactory.

The original BeanFactory did not support many of spring's plug-ins, such as AOP capabilities, Web applications, and so on.The ApplicationContext interface, which is derived from the BeanFactory interface.

ApplicationContext contains all the functions of BeanFactory and is generally recommended over BeanFactory

The ApplicationContext package also provides the following functionality as it works in a more framework-oriented manner and layers and implements context inheritance:

  • MessageSource, providing international message access

  • Resource access, such as URL s and files

  • Event Propagation

  • Load multiple (inherited) contexts so that each context is focused on a specific level, such as the web tier of the application;

Before using the spring framework, to use objects in the dao layer in our service layer, we had to have a new object in the service layer.

Problem: Layer-to-layer dependency.The service layer needs to be configured into an xml configuration file to use dao layer objects. As to how the objects are created and how relationships are combined, it is up to the spring framework to implement them.

Mode 1,

Resource resource = new FileSystemResource("beans.xml");  
BeanFactory factory = new XmlBeanFactory(resource);

Mode 2,

ClassPathResource resource = new ClassPathResource("beans.xml");  
BeanFactory factory = new XmlBeanFactory(resource);

Mode 3,

ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml", "applicationContext-part2.xml"});  
BeanFactory factory = (BeanFactory) context;

That's it, and then you can get an instance of the bean using the getBean(String beanName) method; BeanFactory provides the method and is simple, providing only six methods for the customer to invoke:

boolean containsBean(String beanName) Determines if the factory contains a bean definition with a given name and returns true if it does

Object getBean(String) returns an instance of a bean registered with a given name.Depending on the configuration of the beans, a shared instance will be returned if it is in singleton mode, otherwise a new instance will be returned, and if the specified beans are not found, the method may throw an exception.

Object getBean(String, Class) returns an instance of a bean registered with a given name and converts it to a given class type.

Class getType(String name) returns lass for a bean with a given name, and excludes NoSuchBeanDefinitionException if no specified bean instance is found

boolean isSingleton(String) Determines whether a bean definition with a given name is a singleton pattern

String[] getAliases(String name) Returns all aliases for a given bean name

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

In general, Spring implements class instantiation beans by specifying class attributes that are utilized by the reflection mechanism. In some cases, the process of instantiating beans is complex and, if done in a traditional way, requires a large amount of configuration information to be provided in it.The flexibility of the configuration is limited, and coding may result in a simple solution.

Spring provides a factory-class interface for org.springframework.bean.factory.FactoryBean that allows users to customize the logic for instantiating beans. Why is the bean default singleton? Recommended.Focus on the WeChat Public Number: Java technology stack, reply in the background: spring, you can get the N Spring tutorials I organized, they are all dry goods.

The FactoryBean interface plays an important role in the Spring framework, which itself provides over 70 implementations of FactoryBeans.They hide the details of instantiating some complex beans and make it easier for upper-level applications.

Starting with Spring 3.0, FactoryBean supports generics, that is, the interface declaration changes to FactoryBean and ends with a Bean to indicate that it is a Bean, unlike ordinary beans: it is a Bean that implements the FactoryBean interface, and what it gets from BeanFactory according to its ID is actually the object returned by the getObject() of the FactoryBean, not the FactoryBean itself, if you want to get the F BeanActoryBean object, prefix ID with a &symbol to get it.

For example, implement a FactoryBean by yourself, which is used to proxy an object, intercept all methods of the object, output a line of LOG before and after the call, and mimic the functions of ProxyFactoryBean.

/**  
 * my factory bean<p>  
 * Proxy a class, intercept all methods of that class, and log output before and after method invocation  
 * @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;  
    }  
  
}

The XML-Bean configuration is as follows

<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;   
    /**  
     * Tests validate the FactoryBean principle, proxy a servcie before and after calling its method, print logs can also be used for other processing  
     * Get a custom FactoryBean from the ApplicationContext  
     * context.getBean(String beanName) ---> The resulting Object is FactoryBean.getObejct(),  
     * Proxy class for service generation using Proxy.newInstance  
     */  
    @Test  
    public void testFactoryBean() {  
        HelloWorldService helloWorldService = (HelloWorldService) context.getBean("fbHelloWorldService");  
        helloWorldService.getBeanName();  
        helloWorldService.sayHello();  
    }  
}

FactoryBean is an interface. When a Bean in an IOC container implements FactoryBean, the Bean object obtained by getBean(String BeanName) is not an implementation class object of FactoryBean, but an object returned by the getObject() method in this implementation class.To get an implementation class for FactoryBean, you need a getBean (&BeanName), preceded by a BeanName.

package org.springframework.beans.factory;   
public interface FactoryBean<T> {   
    T getObject() throws Exception;   
    Class<?> getObjectType();   
    boolean isSingleton();   
}

There are also three methods defined in this interface:

TgetObject(): Returns a Bean instance created by FactoryBean, and if isSingleton() returns true, the instance is placed in the single instance cache pool in the Spring container;

booleanisSingleton(): Returns whether the scope of a Bean instance created by FactoryBean is singleton or prototype;

ClassgetObjectType(): Returns the type of Bean created by FactoryBean.

When the implementation class of the class attribute configuration in the configuration file is a FactoryBean, the object returned by the getBean() method is not the FactoryBean itself, but the object returned by the FactoryBean#getObject() method, which is equivalent to the FactoryBean#getObject() proxying the getBean() method.Example: If you configure Car below in a traditional way, each attribute of Car corresponds to an element tag.

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

This is flexible if implemented as a FactoryBean, and the following example specifies configuration values for all Car attributes at once through a comma separator:

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 ;   
    }   
  
    // Accept comma separator setting property information  
    public   void  setCarInfo ( String carInfo )   {   
        this . carInfo = carInfo;   
    }   
}

With this CarFactoryBean, you can configure the CarBean in the configuration file using this custom configuration:

<bean d="car"class="com.baobaotao.factorybean.CarFactoryBean"  
P:carInfo="Ferrari,400,2000000"/>

When getBean("car") is called, Spring discovers through the reflection mechanism that CarFactoryBean implements the FactoryBean's interface, and the Spring container returns by calling the interface method CarFactoryBean#getObject().

If you want to get an instance of CarFactoryBean, you need to prefix the beanName with a'&'when using the getBean(beanName) method: for ex amp le, getBean ('&car');

Here is an example of using 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>

Implementation class for FactoryBean

import org.springframework.beans.factory.FactoryBean;   
  
/**   
 * @author  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;   
    }   
  
}

Ordinary bean s

/**   
 * @author  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 + "]";   
    }   
}

Test Class

import org.springframework.context.support.ClassPathXmlApplicationContext;   
  
import com.spring.bean.FactoryBeanPojo;   
  
/**   
 * @author  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());   
    }   
}

Output results:

November 16, 2016 10:28:24 morning 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    
//November 16, 2016 10:28:24 a.m. org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions  
INFO: Loading XML bean definitions from class path resource [com/spring/config/BeanConfig.xml]    
//November 16, 2016 10:28:24 a.m. 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

You can see from the result that when you get the FactoryBeanPojo object from the IOC container, it is really a Student object that you get with getBean(String BeanName). You can see that when the type property in FactoryBeanPojo is set to student, the Student object is returned in the getObject() method.

So when you get an implementation class that implements FactoryBean from the IOC container, it returns the object returned by the getObject method in the implementation class. To get an implementation class of FactoryBean, you have to write a getBean (String &BeanName) by adding &before the BeanName in the getBean(String BeanName).

Reference resources

https://blog.csdn.net/wangbiao007/article/details/53183764
https://blog.csdn.net/qiesheng/article/details/72875315
https://www.cnblogs.com/redcool/p/6413461.html

Author: Supreme Treasure
https://www.cnblogs.com/aspirant/p/9082858.html

Recommend going to my blog to read more:

1.Java JVM, Collections, Multithreaded, New Features Series Tutorial

2.Spring MVC, Spring Boot, Spring Cloud series tutorials

3.Maven, Git, Eclipse, Intellij IDEA Series Tools Tutorial

4.Latest Interview Questions for Java, Backend, Architecture, Alibaba, etc.

Life is good. See you tomorrow~

Posted by Adika on Mon, 13 Apr 2020 20:47:21 -0700