From the previous articles, you’ve been able to create and assign objects using Spring. In this way, we can already hand over our own classes to the Spring container for management. Spring can help us create objects, and we have analyzed that the way spring helps us create objects is through reflection call constructors. So the question is, what if there are classes that we can’t create objects with constructors? Or, what if some object already exists that I don’t want Spring to create for me, but it’s managed through its container? This question is a bit abstract, and may be hard to understand at first glance. So let’s take an example

Is there really such an object

For example, we have learned JDBC before, there is a Connection object in JDBC, is to help us connect to the database, how is this object created? So let’s go back.

Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db"."root"."123456");
return conn;

// omit exception
Copy the code

In this case, you can see that the Connection is not created by simply using a new. If we hand this object over to Spring to create, we’ll get the wrong object.

<bean id="conn" class="com.sql.Connection" />
Copy the code

Note the counterexample above. It is obvious that the Connection object is too complex to be created in a simple new way. It is better for the Spring framework to give the object creation authority to us, but we need to hand it over to the factory. Spring provides a hook for this, FactoryBean. Before we get there, let’s agree on two concepts:

Simple object: can directly through the way of new created the complex object, cannot be directly built by means of new objects, such as Connection, SqlSessionFactory.

FactoryBean interface

To solve these problems, Spring provides an interface called FactoryBean:, and this class is also a commonly used interface within Spring. Its main purpose is to help us create complex objects. This interface is a generic interface, and when we implement it, we can specify generics, and there are three methods that we need to implement. So let’s experiment.

public class ConnectionFactoryBean implements FactoryBean<Connection>{
  
  @Override
  public Connection getObject(a){
    // Write code that creates a complex object and returns the complex object as the object's return value
    // the exception is omitted
    Class.forName("com.mysql.jdbc.Driver");
    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db"."root"."123456");
    return conn;
  }
  
  @Override
  public Class<Connection> getObjectType(a){
    // Returns the Class object of the created complex object
    return Connection.class;
  }
  
@Override
  public boolean isSingleton(a) {
    // Need to create once: true
    // Each time it is called, it is created: false
    reuturn false; }}Copy the code

There are three methods in this interface, the most important of which is getObject(); The purpose of this method is that when you get an object from the Spring container, the object you get is the object you get by calling getObject(). Let’s verify that.

<bean id="conn" class="com.xxx.ConnectionFactoryBean" /> 
Copy the code

Junit is used here for testing

@Test
public void test(a){
  ApplicationContext  ctx = new ClasssPathXmlApplicationContext("/applicationContext.xml");
  
Object obj = ctx.getBean("conn");

}
Copy the code

It’s important to note that we don’t get a ConnectionFactoryBean object via getBean, we get a Connection object. If the type specified in class is the implementation class of the FactoryBean interface, then the id value is the object that the class gets when it calls getObject(). In this program, when we get conn, because the class is ConnectionFactoryBean, Is the implementation of the FactoryBean interface, so when you get an object, you get the return value of the getObject() method, which is Connection. This gives the programmer control over the object creation process through this interface.

Principle analysis and matters needing attention

ConnectionFacotoryBean is a subclass of FactoryBean. If you use instanceof to determine if you are a subclass of FactoryBean, If true is returned, simply call getObject() to return the object.

Matters needing attention:

  1. For example, we pass getBean(“conn”); Method doesn’t get the configured Class: ConnectionFactoryBean object. Instead, it gets a Connection object by calling its getObject() method. What if we just want the ConnectionFactoryBean object? Ctx.getbean (“&conn”); Add an & to the ID to get the object of the implementation class.
  2. IsSingleton (); This method is used to limit the number of objects created. If false is returned, a new object will be created for each fetch. If true, you get the same object multiple times, which is what we call a singleton. When we use it, we should return the corresponding result according to the characteristics of the object. Return false if connection objects cannot be shared because there are transactions inside and cannot interfere with each other. Returns true if a heavyweight resource like SqlSessionFactoryBean is thread-safe;
  3. Mysql > select SSL certificate from url; UseSSL =false.
  4. Information like database connection addresses for names and passwords can be set as member variables in the ConnectionFactoryBean class, specifying the GET and set methods. The property value set injection is also convenient for later use of configuration files for decoupling.
<bean id="conn" class="com.xxx.ConnectionFactoryBean"  >
 	<property name="driverName" value="com.mysql.jdbc.Driver" />
  <property name="url" value="jdbc::mysql://localhost:3306/db? userSSL=false" />
  <property name="username" value="root" />
  <property name="password" value="123456" />
</bean>
Copy the code

Example factory and static factory

We talked about creating complex objects through the FactoryBean interface. But sometimes, what if we already have methods to create objects in a class that doesn’t have a way to implement the FactoryBean interface, and we want to manage it through the Spring factory? For example, some third-party libraries, we can only get their.class files, can not modify their source code how to do. At this point Spring provides us with instance factories and static factories to implement.

public class ConnectionFactory {
  
  public Connection getConnection(a) {
    Class.forName("com.mysql.jdbc.Driver");
    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db"."root"."123456");
    returnconn; }}Copy the code

Suppose we have a class above that already provides methods to create objects, but this class can’t implement the interface. What should we do? Objects can be obtained in the following ways.

<bean id="connFactory" class="com.xxx.FactoryBean" />
<bean id="conn" factory-bean="connFactory" factory-method="getConnection" />
Copy the code

Factory-bean to specify the class, factory-method to specify the method to get the object, so we can get the object with conn. So the factory-method here is the same thing as the getObject() method. We get the Connection object by getting the conn from the Spring factory. This is called an instance factory.

If we have a static method to get an object, we use a static factory.

public class StaticConnectionFactory { public static Connection getConnection() { Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db","root","123456"); return conn; }}Copy the code

Static factories simply specify factory-method because they don’t need an object to call.

<bean id="conn" class="com.xxx.StaticFactoryBean" factory-method="getConnection" />
Copy the code

This article focuses on how Spring provides a way to leave the object creation process in the hands of the programmer. FactoryBean factory, instance factory and static factory are the main methods. In fact, this approach is mainly used when integrating with some third-party frameworks. Because some third-party frameworks do not use the source code directly, so we cannot modify the corresponding source code, but it provides methods to create objects, at this time we can through this way, the objects in the third-party framework to the Spring factory to manage.

For example, when we use Mybatis framework, we need to use a factory class SqlSessionFactory, this factory class can help us obtain the operation database Session. This class can’t be created simply by new, so we can create this object in the getObject method by implementing a FactoryBean. So when we do spring integration with Mybatis, we have a configuration like this:

<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
  	<property name="typeAliasesPackage" value="com.xxx.entity"></property>
  	<property name="mapperLocations">
  			<list>
          	<value>classpatrh:/com.xxx.mapper/*Mapper.xml</value>
      	</list>
  	</property>
</bean>
Copy the code

SqlSessionFactoryBen is a FactoryBean implementation class provided by Mybatis for spring integration. The SqlSessionFactory object is returned in the getObject() method of the SqlSessionFactoryBean inside the SqlSessionFactoryBean, thus handing it over to the Spring container for management and integration. We can take a quick look at the source code:

As for the integration with Mybatis, we will talk more about it later

Again, sometimes there’s an interview question that says, The difference between a BeanFactory and a FactoryBean, a FactoryBean we’ve covered, what is a BeanFactory, it’s the basic base class of a Spring factory, This interface is implemented to our common ApplicationContext and various factories, so it is the core abstract interface of all Spring factories. For example, the commonly used getBean(“”) method is defined in the BeanFactory.

References:

Sun Shuai spring a: www.bilibili.com/video/BV185…