Is Spring's BeanFactory and FactoryBean indistinguishable?

Java technology stack

www.javastack.cn

Open the website to see more quality articles

BeanFacotry is the original factory in spring. Such as XMLBeanFactory is a typical Be anFactory. The original BeanFactory could not support many of Spring's plug-ins, such as AOP functions, Web applications, etc.

ApplicationContext interface, which is derived from the BeanFactory interface.

ApplicationContext contains all the functions of BeanFactory, it is generally recommended to take precedence over BeanFactory.

The difference between BeanFactory and FactoryBean

BeanFactory is an interface that provides the most basic form of an OC container, provides specifications for the implementation of specific IOC containers, FactoryBean is also an interface, and provides a more flexible way for the implementation of Beans in IOC containers. The implementation of Bean adds a simple factory pattern and decorative pattern (if you want to understand the decorative pattern reference: decorator pattern (decorator pattern, Decoration), we can flexibly configure it in the getObject () method. In fact, there are many FactoryBean in the Spring source code Implementation class.

Difference: BeanFactory is a Factory, which is an IOC container or object factory, FactoryBean is a Bean. In Spring , all Beans are managed by BeanFactory (that is, IOC container).

But for FactoryBean, this Bean is not a simple Bean, but a factory Bean that can be produced or modified by object generation. Its implementation is similar to the factory pattern and decorator pattern in the design pattern .

1、BeanFactory

BeanFactory, which ends with Factory, indicates that it is a factory class (interface) that is responsible for a factory that produces and manages beans. In Spring, the BeanFactory is the core interface of the IOC container. Its responsibilities include: instantiating, locating, configuring objects in the application, and establishing dependencies between these objects.

BeanFactory is just an interface, not a specific implementation of the IOC container, but the Spring container gives a variety of implementations, such as DefaultListableBeanFactory, XmlBeanFactory, ApplicationContext, etc., among which XmlBeanFactory is a common one. Dependencies between objects. The XmlBeanFactory class will hold this XML configuration metadata and use it to build a fully configurable system or application.

It is the realization of a certain function. It provides the most basic specifications for other specific IOC containers. For example, DefaultListableBeanFactory, XmlBeanFactory, ApplicationContext and other specific containers implement BeanFactory, and then add other functions on top of it.

BeanFactory and ApplicationContext are two IOC containers of spring framework. Now ApplicationnContext is generally used, which not only includes the function of BeanFactory, but also expands more.

BeanFacotry is the original factory in spring. Such as XMLBeanFactory is a typical BeanFactory.

The original BeanFactory could not support many of Spring's plug-ins, such as AOP functions, Web applications, etc. ApplicationContext interface, which is derived from the BeanFactory interface.

ApplicationContext contains all the functions of BeanFactory, it is usually recommended to take precedence over BeanFactory

ApplicationContext works in a more framework-oriented way and layer and implement inheritance of the context. The ApplicationContext package also provides the following functions:

  • MessageSource, provides internationalized message access

  • Resource access, such as URLs and files

  • Event propagation

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

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

Existing problems: inter-layer dependencies. The service layer needs to be configured in the xml configuration file using the dao layer objects. As for how the objects are created and how the relationships are combined, they are all handed over to the spring framework.

Method 1,

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

Method 2.

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

Method 3.

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

This is basically all, and then use the getBean (String beanName) method to get an instance of the bean; the method provided by the BeanFactory is very simple and only provides six methods for customers to call:

boolean containsBean (String beanName) Determines whether the factory contains the bean definition of the given name, and returns true if there is

Object getBean (String) Returns the bean instance registered with the given name. According to the configuration of the bean, if it is singleton mode, it will return a shared instance, otherwise it will return a new instance. If the specified bean is not found, this method may throw an exception.

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

Class getType (String name) returns the Class of the bean with the given name, if no specified bean instance is found, exclude NoSuchBeanDefinitionException

boolean isSingleton (String) Determine whether the bean definition of the given name is singleton mode

String [] getAliases (String name) returns all aliases for the 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 uses the class attribute of the reflection mechanism to specify the class to instantiate the Bean. In some cases, the process of instantiating the Bean is more complicated. If you follow the traditional method, you need to provide a lot of configuration information. The flexibility of the configuration method is limited. At this time, a simple solution may be obtained by adopting the coding method.

Spring provides a factory class interface of org.springframework.bean.factory.FactoryBean for this purpose. Users can customize the logic of instantiating Bean by implementing this interface. Why does bean default singleton? Recommend to take a look. Pay attention to the WeChat public account: Java technology stack, reply in the background: spring, you can get the N Spring tutorials I have compiled, all are dry goods.

The FactoryBean interface occupies an important position for the Spring framework, and Spring itself provides more than 70 FactoryBean implementations. They hide the details of instantiating some complex beans and bring convenience to upper-layer applications.

Starting from Spring 3.0, FactoryBean supports generics, that is, the interface declaration is changed to FactoryBean in the form of ending with Bean, indicating that it is a Bean, different from ordinary Bean: it is a Bean that implements the FactoryBean interface, according to the Bean The ID obtained from the BeanFactory is actually the object returned by FactoryBean's getObject (), not the FactoryBean itself. If you want to get the FactoryBean object, please add an ampersand in front of the id to get it.

For example, implement a FactoryBean yourself, function: used to proxy an object, intercept all methods of the object, output a line of LOG before and after the call, imitating the function of 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;  
    }  

}

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;   
    /**  
     * 测试验证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 is an interface. When the Bean in the IOC container implements FactoryBean, the Bean object obtained through getBean (String BeanName) is not the object of the FactoryBean implementation class, but the object returned by the getObject () method in this implementation class . To get the implementation class of FactoryBean, getBean (& BeanName), and add & before BeanName.

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

The following 3 methods are also defined in this interface:

TgetObject (): returns the Bean instance created by FactoryBean. If isSingleton () returns true, the instance will be placed in the single-instance cache pool in the Spring container;

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

ClassgetObjectType (): Returns the bean type created by FactoryBean.

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

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

If you use FactoryBean to achieve flexibility, the following example uses a comma separator to specify configuration values ​​for all Car properties at once:

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

With this CarFactoryBean, you can use the following custom configuration method to configure CarBean in the configuration file:

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

When calling getBean ("car"), Spring finds that CarFactoryBean implements the FactoryBean interface through the reflection mechanism, and then the Spring container calls the interface method CarFactoryBean # getObject () method to return.

If you want to get an instance of CarFactoryBean, you need to add the "&" prefix displayed before the beanName when using the getBean (beanName) method: such as getBean ("& car");

The following 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>

FactoryBean implementation class

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

}

Ordinary 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 + "]";   
    }   
}

Test class

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

The output result:

十一月 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

From the results, you can see that when you get the FactoryBeanPojo object from the IOC container, you use getBean (String BeanName) to get the Student object. You can see that when the type property in FactoryBeanPojo is set to student, it will be in the getObject () method. Return the Student object.

So when you get the implementation class that implements FactoryBean from the IOC container, it returns the object returned by the getObject method in the implementation class. To get the implementation class of FactoryBean, you must add & before the BeanName in getBean (String BeanName) , Written as getBean (String & BeanName).

reference

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: Monkey King
https://www.cnblogs.com/aspirant/p/9082858.html

END

Learning materials:

Share a copy of the latest Java architect learning materials

Recent articles:

1. Java 10 big pack B writing method, you can brag!

2. Java 14 pattern matching, very new feature!

3. Heavy: Java 14 is officially released!

4. Are you still using Date? Quickly use LocalDateTime!

5. A bloody case caused by the leak of the Druid connection pool!

6. 8 data structures that every programmer must master!

7. The 8 ways of writing the singleton mode are very complete!

8. How to use chase MM to understand 23 design patterns?

9. When I go, my colleague actually stores the password in plain text! ! !

10. Why do big companies have to use microservices?

There are too many dry goods in the public account. Scan the code to pay attention to the public account of the Java technology stack . Read more.

Click " Read Original " to take you to fly ~

Published 474 original articles · praised 1030 · 1.45 million views +

Guess you like

Origin blog.csdn.net/youanyyou/article/details/105445452