Bean实例化(Instantiation)多种方式

常规方式

通过构造器

(配置元信息:使用XML设置、通过Java注解设置和 调用Java API配置)

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>

通过构造器实例化是最简单的,在xml里配置个bean,设置好属性就可以通过beanFactory.getBean(String)获取出来了。

通过静态工厂方法

(配置元信息:使用XML设置和 Java API配置)
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>

在xml中定义一个Bean,id叫user-java,对应的实体是User,创建的方式是使用静态方法来创建Bean对象,该方法必须是静态的且存在与User实体类中。
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;
    }


}

在User中创建静态方法createUser,返回类型为User。
然后就可以初始化Bean了。
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());

    }

}

通过Bean工厂方法

(配置元信息:使用XML设置)
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>

在原先的基础中新增实例方法实例化。
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);

    }

}

由于在xml中,这是两个不同的id,所以它们并不相等,是不同的两个bean。
静态方法和实例方法其实没有什么太大的区别,通常很少有人会这么去实现。

通过FactoryBean

(配置元信息:使用XML设置、通过Java注解设置和 Java API配置)

创建一个class,实现FactoryBean类

public interface FactoryBean<T> {

     String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

     @Nullable
     T getObject() throws Exception;


     @Nullable
     Class<?> getObjectType();

 
     default boolean isSingleton() {
        return true;
     }

}

由于Spring5之后是用Java8,所以这个时候的FactoryBean里的isSingleton方法有了default来修饰,默认是单例的,所以我们只需要重新实现getObject和getObjectType方法即可。

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

意味着我的实例方法、静态方法以及FactoryBean的实现都是用createUser这个静态方法来实现。
bean-definition-create.xml

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

这个时候xml只需要加这么一句即可,不是直接定义User对象,而是直接会定一个FactoryBean。
之后只需要通过id来获取这个bean就可以了

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

特殊方式

通过ServiceLoaderFactoryBean实现Bean

通过继承ServiceLoaderFactoryBean
点开ServiceLoaderFactoryBean源码,我们会发现这么一个类ServiceLoader,ServiceLoader是java1.6之后就有的。

public class ServiceLoaderFactoryBean extends AbstractServiceLoaderBasedFactoryBean implements BeanClassLoaderAware {

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

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

}

我们再点开ServiceLoader源码,第一眼看到的就是META-INF/services/一个路径

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

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

它这个是用来配置实现类的。
首先我们需要再META-INF下创建services文件夹,复制UserFactory的全路径,创建一个名为UserFactory的全路径,没有文件后缀的文件。将作为UserFactory的实现类DefalutUserFactory的全路径放到里面去。
~~~
然后我们再回过去看ServiceLoaderFactoryBean,既然是实例化就避不开create或者Instance方法,仔细找了一下,方法在继承的AbstractServiceLoaderBasedFactoryBean中,名为createInstance

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

}

getObjectToExpose(ServiceLoader.load(getServiceType(), this.beanClassLoader))中不难发现,实例化的对象来自于getServiceType,那么serviceType的值从哪里来的呢?
答案是:从xml配置里来

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

ServiceLoaderFactoryBean使用的是ServiceLoader,ServiceLoader默认读取的是/META-INF/services/下的文件,而value="org.example.factory.UserFactory"刚好就是文件名,从而serviceType获取到的是文件内存储的UserFactory的所有实现类全路径,通过ServiceLoader.load(getServiceType(), this.beanClassLoader)方法加载得到了bean对象。

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

通过AutowireCapableBeanFactory实例化Bean

通过调用AutowireCapableBeanFactory的createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck)方法

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

    }

这里要注意的是:
UserFactory bean = beanFactory.createBean(DefaultUserFactory.class);
需要直接创建的是实例对象DefaultUserFactory.class,而不是UserFactory.class接口对象,否则会报BeanInstantiationException异常

通过BeanDefinitionRegistry实例化Bean

通过调用BeanDefinitionRegistry的registerBeanDefinition(String beanName, BeanDefinition beanDefinition)方法
DefaultListableBeanFactory是BeanDefinitionRegistry的一个实现类,这里我们使用DefaultListableBeanFactory这个实现类来实例化Bean。

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

结束语

几种Bean的实例化分享就到此结束了,虽然SpringBoot的便利已经让开发不再需要自己去实例化Bean了,但是身为程序员,若想在这条路上越走越远,那么底层的实现方法就有去了解的必要,否则一旦脱离了框架,自身的价值便一文不值了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值