Bean instantiation (Instantiation) in many ways

conventional way

via constructor

(Configuration meta information: use XML settings, set through Java annotations and call Java API configuration)

public static void main(String[] args)
    {
    
    
        ClassPathXmlApplicationContext beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-definition-create.xml");

        Object user = beanFactory.getBean("user");

        System.out.println(user);

    }
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user" class="org.example.pojo.User" >
        <property name="id" value="1" />
        <property name="name" value="Java" />
    </bean>
  

</beans>

It is the easiest to instantiate through the constructor. Configure a bean in xml, set the properties, and then get it through beanFactory.getBean(String).

via static factory method

(Configuration meta information: using XML settings and Java API configuration)
bean-definition-create.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 静态方法实例化 Bean -->
    <bean id="user-java" class="org.example.pojo.User" factory-method="createUser" />

</beans>

Define a Bean in xml, the id is user-java, and the corresponding entity is User. The way to create it is to use a static method to create a Bean object. This method must be static and exist in the User entity class.
User.java

package org.example.pojo;

/**
 * @author Java
 * @date 2022-11-22 21:16
 */
@Data
public class User {
    
    

    private Integer id;

    private String name;

    //静态方法
    public static User createUser(){
    
    
        return new User(1,"Java");
    }

    @Override
    public String toString()
    {
    
    
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public User(Integer id, String name)
    {
    
    
        this.id = id;
        this.name = name;
    }


}

Create a static method createUser in User with a return type of User.
Then the Bean can be initialized.
BeanDefinitionDemo.java

package org.example.bean;

import org.example.pojo.User;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author Java
 * @date 2022-11-22 20:43
 */
public class BeanDefinitionDemo {
    
    

    public static void main(String[] args)
    {
    
    
        // 配置 XML 配置文件
        // 启动 Spring 应用上下文
        ClassPathXmlApplicationContext beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-definition-create.xml");
  //获取bean
        User bean = beanFactory.getBean("user-java", User.class);
        //打印
        System.out.println(bean.toString());

    }

}

Through the Bean factory method

(Configuration meta information: use XML settings)
bean-definition-create.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 静态方法实例化 Bean -->
    <bean id="user-java" class="org.example.pojo.User" factory-method="createUser" />

    <!-- 实例方法实例化 Bean -->
    <bean id="user-by-instance" factory-bean="userFactory" factory-method="createUser" />

    <bean id="userFactory" class="org.example.factory.DefaultUserFactory" />
    
</beans>

Add instance method instantiation to the original foundation.
BeanDefinitionDemo.java

package org.example.definition;

import org.example.pojo.User;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author Java
 * @date 2022-11-22 20:43
 */
public class BeanDefinitionDemo {
    
    

    public static void main(String[] args)
    {
    
    
        // 配置 XML 配置文件
        // 启动 Spring 应用上下文
        ClassPathXmlApplicationContext beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-definition-create.xml");

        //获取bean
        User bean = beanFactory.getBean("user-java", User.class);
        User userByInstance = beanFactory.getBean("user-by-instance", User.class);
       
        //打印
        System.out.println(bean.toString());
        System.out.println(userByInstance.toString());
        
        //是否相等
        System.out.println(bean==userByInstance);

    }

}

Since these are two different ids in xml, they are not equal, they are two different beans.
There is actually no big difference between static methods and instance methods, and usually few people will implement it this way.

via FactoryBean

(Configuration meta information: using XML settings, setting via Java annotations, and Java API configuration)

Create a class that implements the FactoryBean class

public interface FactoryBean<T> {
    
    

     String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

     @Nullable
     T getObject() throws Exception;


     @Nullable
     Class<?> getObjectType();

 
     default boolean isSingleton() {
    
    
        return true;
     }

}

Since Java 8 is used after Spring 5, the isSingleton method in FactoryBean at this time has been modified by default. The default is a singleton, so we only need to reimplement the getObject and getObjectType methods.

package org.example.factory;

import org.springframework.beans.factory.FactoryBean;

/**
 * @author Java
 * @date 2022-11-22 21:54
 */
public class UserFactoryBean implements FactoryBean {
    
    

    @Override
    public Object getObject() throws Exception
    {
    
    
        return User.createUser();
    }

    @Override
    public Class<?> getObjectType()
    {
    
    
        return User.class;
    }
}

It means that my instance method, static method and FactoryBean are all implemented with the static method createUser.
bean-definition-create.xml

<bean id="user-by-factory-bean"  class="org.example.factory.UserFactoryBean" />

At this time, xml only needs to add such a sentence, instead of directly defining the User object, it will directly define a FactoryBean.
After that, you only need to get the bean by id

//获取bean
User beanFactoryBean = beanFactory.getBean("user-by-factory-bean", User.class);
//打印
System.out.println(beanFactoryBean.toString());

special way

Implement Bean through ServiceLoaderFactoryBean

By inheriting ServiceLoaderFactoryBean
Click on the ServiceLoaderFactoryBean source code, we will find such a class ServiceLoader, ServiceLoader is available after java1.6.

public class ServiceLoaderFactoryBean extends AbstractServiceLoaderBasedFactoryBean implements BeanClassLoaderAware {
    
    

   @Override
   protected Object getObjectToExpose(ServiceLoader<?> serviceLoader) {
    
    
      return serviceLoader;
   }

   @Override
   public Class<?> getObjectType() {
    
    
      return ServiceLoader.class;
   }

}

Let's click on the ServiceLoader source code again, the first thing we see is META-INF/services/a path

public final class ServiceLoader<S>
    implements Iterable<S>
{
    
    

    private static final String PREFIX = "META-INF/services/";
 
    ......
}

It is used to configure the implementation class.
First, we need to create a services folder under META-INF, copy the full path of UserFactory, and create a file named UserFactory with a full path and no file suffix. Put the full path of DefalutUserFactory, which is the implementation class of UserFactory, into it.
~~~
Then we go back and look at ServiceLoaderFactoryBean. Since it is instantiated, we cannot avoid the create or Instance method. After searching carefully, the method is called createInstance in the inherited AbstractServiceLoaderBasedFactoryBean

public abstract class AbstractServiceLoaderBasedFactoryBean extends AbstractFactoryBean<Object>
      implements BeanClassLoaderAware {
    
    

   @Nullable
   private Class<?> serviceType;

   @Nullable
   private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();


   /**
    * Specify the desired service type (typically the service's public API).
    */
   public void setServiceType(@Nullable Class<?> serviceType) {
    
    
      this.serviceType = serviceType;
   }

   /**
    * Return the desired service type.
    */
   @Nullable
   public Class<?> getServiceType() {
    
    
      return this.serviceType;
   }

   @Override
   public void setBeanClassLoader(@Nullable ClassLoader beanClassLoader) {
    
    
      this.beanClassLoader = beanClassLoader;
   }


   /**
    * Delegates to {@link #getObjectToExpose(java.util.ServiceLoader)}.
    * @return the object to expose
    */
   @Override
   protected Object createInstance() {
    
    
      Assert.notNull(getServiceType(), "Property 'serviceType' is required");
      return getObjectToExpose(ServiceLoader.load(getServiceType(), this.beanClassLoader));
   }

   /**
    * Determine the actual object to expose for the given ServiceLoader.
    * <p>Left to concrete subclasses.
    * @param serviceLoader the ServiceLoader for the configured service class
    * @return the object to expose
    */
   protected abstract Object getObjectToExpose(ServiceLoader<?> serviceLoader);

}

In getObjectToExpose(ServiceLoader.load(getServiceType(), this.beanClassLoader)), it is not difficult to find that the instantiated object comes from getServiceType, so where does the value of serviceType come from?
The answer is: from the xml configuration

<bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean" >
    <property name="serviceType" value="org.example.factory.UserFactory"  />
</bean>

ServiceLoaderFactoryBean uses ServiceLoader, ServiceLoader reads the file under /META-INF/services/ by default, and value="org.example.factory.UserFactory" is just the file name, so the serviceType gets the file stored in the file The full path of all the implementation classes of UserFactory is loaded through the ServiceLoader.load(getServiceType(), this.beanClassLoader) method to get the bean object.

 public static void main(String[] args)
    {
    
    
        // 配置 XML 配置文件
        // 启动 Spring 应用上下文
        ClassPathXmlApplicationContext beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-service-loader-create.xml");
      //获取ServiceLoader对象
        ServiceLoader serviceLoader = beanFactory.getBean("userFactoryServiceLoader", ServiceLoader.class);
      
        Iterator<UserFactory> iterator = serviceLoader.iterator();
        while (iterator.hasNext()) {
    
    
            //遍历对象
            UserFactory userFactory = iterator.next();
            System.out.println(userFactory.createUser().toString());
        }
    }

Instantiate Bean through AutowireCapableBeanFactory

By calling the createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) method of AutowireCapableBeanFactory

public static void main(String[] args)
    {
    
    
        // 配置 XML 配置文件
        // 启动 Spring 应用上下文
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-service-loader-create.xml");
        //通过 AutowireCapableBeanFactory 创建 AutowireCapableBeanFactory 对象
        AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();

        // 创建 UserFactory 对象,通过 AutowireCapableBeanFactory 进行依赖注入
        UserFactory bean = beanFactory.createBean(DefaultUserFactory.class);

        System.out.println(bean.createUser());

    }

Note here:
UserFactory bean = beanFactory.createBean(DefaultUserFactory.class);
what needs to be created directly is the instance object DefaultUserFactory.class, not the UserFactory.class interface object, otherwise a BeanInstantiationException will be reported

Instantiate Bean through BeanDefinitionRegistry

By calling the registerBeanDefinition(String beanName, BeanDefinition beanDefinition) method of BeanDefinitionRegistry
DefaultListableBeanFactory is an implementation class of BeanDefinitionRegistry. Here we use the implementation class DefaultListableBeanFactory to instantiate beans.

public static void main(String[] args)
{
    
    
    //创建一个BeanFactory容器
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    //设置Bean中的参数
    MutablePropertyValues values=new MutablePropertyValues();
    values.add("id",1);
    values.add("name","my name is Java面试教程 ");
 
    //BeanDefinition定义了 定义bean所需要的基本属性
    BeanDefinition definition=new RootBeanDefinition(User.class,null,values);
 //把参数设置进去
    factory.registerBeanDefinition("user",definition);
    User user=(User)factory.getBean("user");
    System.out.print(user.toString());
}

conclusion

This is the end of the instantiation sharing of several Beans. Although the convenience of SpringBoot has made development no longer need to instantiate Beans by yourself, as a programmer, if you want to go further and further on this road, then the underlying It is necessary to understand the implementation method, otherwise once it is out of the framework, its own value will be worthless.

Guess you like

Origin blog.csdn.net/doublepg13/article/details/128330115