spring-core-4-36 | 实例化Spring Bean:Bean实例化的姿势有多少种?

本文介绍了多种Spring框架中Bean的实例化方式,包括常规的构造器实例化、静态工厂方法实例化、Bean工厂方法实例化及FactoryBean实例化等,并展示了通过ServiceLoaderFactoryBean和服务加载API的特殊实例化方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实例化Spring Bean

Bean 实例化(Instantiation)

常规方式

• 通过构造器(配置元信息:XML、Java 注解和Java API )
不演示了, 例子太多

• 通过静态工厂方法(配置元信息:XML 和Java API )

• 通过Bean 工厂方法(配置元信息:XML和Java API )

• 通过FactoryBean(配置元信息:XML、Java 注解和Java API )

特殊方式

• 通过ServiceLoaderFactoryBean(配置元信息:XML、Java 注解和Java API )

• 通过AutowireCapableBeanFactory#createBean(java.lang.Class, int,
boolean)

• 通过BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)

代码示例

spring-core项目
搜索 36 | 实例化Spring Bean
常规方式
BeanInstantiationDemo.java
UserFactory.java
UserFactoryBean.java
bean-instantiation-context.xml

BeanInstantiationDemo.java

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.geekbang.thinking.in.spring.bean.definition;

import org.geekbang.thinking.in.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 36 | 实例化Spring Bean:Bean实例化的姿势有多少种?
 *
 * Bean 实例化示例, 这里实例化其实也包括初始化了
 *
 * • Bean 实例化(Instantiation)
 *      • 常规方式
 *          • 通过构造器(配置元信息:XML、Java 注解和Java API )
 *          • 通过静态工厂方法(配置元信息:XML 和Java API )
 *          • 通过Bean 工厂方法(配置元信息:XML和Java API ), 就是下面的 实例(Bean)方法实例化 Bean
 *          • 通过FactoryBean(配置元信息:XML、Java 注解和Java API )
 *      • 特殊方式
 *          • 通过ServiceLoaderFactoryBean(配置元信息:XML、Java 注解和Java API )
 *          • 通过AutowireCapableBeanFactory#createBean(java.lang.Class, int, boolean)
 *          • 通过BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition) 见 31 | 定义Bean: 什么是BeanDefinition?
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
public class BeanInstantiationDemo {

    public static void main(String[] args) {
        // 配置 XML 配置文件, 下面bean的id都去xml文件里面去找
        // 启动 Spring 应用上下文
        BeanFactory beanFactory
                = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-instantiation-context.xml");
        // 36.2 通过静态工厂方法实例化 Bean, 这里其实是一个静态工厂的模式, 可以看User类里面那个静态的工厂方法
        User userByStaticMethod = beanFactory.getBean("user-by-static-method", User.class);
        // 36.3 实例(Bean)方法实例化 Bean, 这里其实是一个代理工厂的模式, 看UserFactory和 DefaultUserFactory, 实现了代理工厂
        // UserFactory需要在配置文件中配置
        User userByInstanceMethod = beanFactory.getBean("user-by-instance-method", User.class);
        // 36.4 通过FactoryBean实例化 Bean
        User userByFactoryBean = beanFactory.getBean("user-by-factory-bean", User.class);

        System.out.println(userByStaticMethod);
        System.out.println(userByInstanceMethod);
        System.out.println(userByFactoryBean);

        // 相等性上应该是都不对等的, 都不是一种创建的方式
        System.out.println(userByStaticMethod == userByInstanceMethod);
        System.out.println(userByStaticMethod == userByFactoryBean);

    }
}

bean-instantiation-context.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 36 | 实例化Spring Bean:Bean实例化的姿势有多少种? -->
    <!-- 36.2 静态方法实例化 Bean -->
    <!-- 这里的意思就是通过一个静态方法来创建这个bean, 而这个方法定义在这个User类里面 -->
    <bean id="user-by-static-method" class="org.geekbang.thinking.in.spring.ioc.overview.domain.User"
          factory-method="createUser"/>

    <!-- 36.3 实例(Bean)方法实例化 Bean / 通过Bean 工厂方法 -->
    <!-- 这里其实是定义了一个UserFactory代理工厂类(有默认实现的接口), 然后DefaultUserFactory是实现类,
        createUser则是实现类的一个实例方法, 故而是一个Bean工厂方法实现的实例化Bean -->
    <bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser"/>
    <bean id="userFactory" class="org.geekbang.thinking.in.spring.bean.factory.DefaultUserFactory"/>


    <!-- 36.4 FactoryBean实例化 Bean -->
    <!-- 这个方式比较特殊在于并不会去定义这个bean, 而是一个factoryBean,
    那么这里不仅能实例化, 其实还能进行初始化, 看实现了哪些方法了 -->
    <bean id="user-by-factory-bean" class="org.geekbang.thinking.in.spring.bean.factory.UserFactoryBean"/>


</beans>

User.java

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.geekbang.thinking.in.spring.ioc.overview.domain;

import org.geekbang.thinking.in.spring.ioc.overview.enums.City;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.core.io.Resource;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

/**
 * 用户类
 * <p>
 * spring-core-2-17 | 传统IoC容器实现:JavaBeans也是IoC容器吗?
 * 这个类也用于JavaBeans作为IoC容器功能的演示
 * <p>
 * 常见叫法: Setter方法 / Getter 方法
 * Java Beans叫法: 可写方法(writable) / 可读方法(Readable)
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
public class User implements BeanNameAware {

    // 61 | 基础类型注入  有没有思考过配置文件里的属性值是字符串, 怎么转换成这的Long?
    private Long id;// 属性也称为Property

    private String name;

    // 61 | 基础类型注入, 枚举也可以注入
    private City city;

    // 62 | 集合类型注入, 数组类型注入
    private City[] workCities;

    // 62 | 集合类型注入, List类型注入
    private List<City> lifeCities;

    // 61 | 基础类型注入, spring的类型也可以注入
    // 其实在调用User 的 toString() 方法时, 对configFileLocation 的展示也是调了一个 toString(),
    // 可以看 org.springframework.core.io.ClassPathResource 的 父接口
    // org.springframework.core.io.AbstractResource, 有 toString() 方法,
    // 可以看到是使用 getDescription() 实现的, 那么再转回去:
    // org.springframework.core.io.ClassPathResource.getDescription, 就是这么来的
    private Resource configFileLocation;

    private Company company;

    private Properties context;

    private String contextAsText;

    /**
     * 当前 Bean 的名称
     */
    private transient String beanName;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public City getCity() {
        return city;
    }

    public void setCity(City city) {
        this.city = city;
    }

    public Resource getConfigFileLocation() {
        return configFileLocation;
    }

    public void setConfigFileLocation(Resource configFileLocation) {
        this.configFileLocation = configFileLocation;
    }

    public City[] getWorkCities() {
        return workCities;
    }

    public void setWorkCities(City[] workCities) {
        this.workCities = workCities;
    }

    public List<City> getLifeCities() {
        return lifeCities;
    }

    public void setLifeCities(List<City> lifeCities) {
        this.lifeCities = lifeCities;
    }

    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }

    /**
     * 36.2 静态的工厂方法, 用于bean的实例化
     * @return
     */
    public static User createUser() {
        User user = new User();
        user.setId(1L);
        user.setName("小马哥");
        return user;
    }

    @PostConstruct
    public void init() {
        System.out.println("User Bean [" + beanName + "] 初始化...");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("User Bean [" + beanName + "] 销毁中...");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    public Properties getContext() {
        return context;
    }

    public void setContext(Properties context) {
        this.context = context;
    }

    public String getContextAsText() {
        return contextAsText;
    }

    public void setContextAsText(String contextAsText) {
        this.contextAsText = contextAsText;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", city=" + city +
                ", workCities=" + Arrays.toString(workCities) +
                ", lifeCities=" + lifeCities +
                ", configFileLocation=" + configFileLocation +
                ", company=" + company +
                ", context=" + context +
                ", contextAsText='" + contextAsText + '\'' +
                ", beanName='" + beanName + '\'' +
                '}';
    }
}

DefaultUserFactory.java

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.geekbang.thinking.in.spring.bean.factory;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * 36 | 实例化Spring Bean:Bean实例化的姿势有多少种?
 * 36.3 默认 {@link UserFactory} 实现
 *
 * 37 | 初始化Spring Bean:Bean初始化有哪些方式?
 *
 * 39 | 销毁Spring Bean
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {

    // 37.1. 基于 @PostConstruct 注解
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct : UserFactory 初始化中...");
    }

    public void initUserFactory() {
        System.out.println("自定义初始化方法 initUserFactory() : UserFactory 初始化中...");
    }

    /**
     * 37.2 实现InitializingBean 接口的afterPropertiesSet() 方法
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean#afterPropertiesSet() : UserFactory 初始化中...");
    }

    /**
     * 39.1 @PreDestroy 标注方法
     */
    @PreDestroy
    public void preDestroy() {
        System.out.println("@PreDestroy : UserFactory 销毁中...");
    }

    /**
     * 39.2 实现DisposableBean 接口的destroy() 方法
     * @throws Exception
     */
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean#destroy() : UserFactory 销毁中...");
    }

    public void doDestroy() {
        System.out.println("自定义销毁方法 doDestroy() : UserFactory 销毁中...");
    }

    /**
     * 40 Spring Bean 覆盖的finalize() 方法
     * 垃圾回收时 ,finalize()会被java回调
     * @throws Throwable
     */
    @Override
    public void finalize() throws Throwable {
        System.out.println("当前 DefaultUserFactory 对象正在被垃圾回收...");
    }
}

UserFactoryBean.java

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.geekbang.thinking.in.spring.bean.factory;

import org.geekbang.thinking.in.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.FactoryBean;

/**
 * 36 | 实例化Spring Bean:Bean实例化的姿势有多少种?
 * 36.4  {@link User} Bean 的 {@link org.springframework.beans.factory.FactoryBean} 实现
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
public class UserFactoryBean implements FactoryBean {

    /**
     * 相当于我的实例方法, 静态方法以及 FactoryBean的实现均采用User类的静态方法createUser()来实现
     * @return
     * @throws Exception
     */
    @Override
    public Object getObject() throws Exception {
        return User.createUser();
    }

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

特殊方式
SpecialBeanInstantiationDemo.java
special-bean-instantiation-context.xml
META-INF\services\org.geekbang.thinking.in.spring.bean.factory.UserFactory

SpecialBeanInstantiationDemo.java

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.geekbang.thinking.in.spring.bean.definition;

import org.geekbang.thinking.in.spring.bean.factory.DefaultUserFactory;
import org.geekbang.thinking.in.spring.bean.factory.UserFactory;
import org.geekbang.thinking.in.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Iterator;
import java.util.ServiceLoader;

import static java.util.ServiceLoader.load;

/**
 * 36 | 实例化Spring Bean:Bean实例化的姿势有多少种?
 *
 * 特殊的 Bean 实例化示例
 * • 通过ServiceLoaderFactoryBean(配置元信息:XML、Java 注解和Java API )
 * • 通过AutowireCapableBeanFactory#createBean(java.lang.Class, int, boolean)
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
public class SpecialBeanInstantiationDemo {

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

        // 36.6 通过 ApplicationContext 获取 AutowireCapableBeanFactory
        // 这里有个意思的就是 beanFactory 就不能获取到 AutowireCapableBeanFactory, ApplicationContext是beanFactory的超类
        AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();

        // 创建 UserFactory 对象,通过 AutowireCapableBeanFactory
        // 这里我们在创建一个类的实体的时候, 一定要用实现类, 但是不要用接口, 会报错
        UserFactory userFactory = beanFactory.createBean(DefaultUserFactory.class);
        System.out.println(userFactory.createUser());

        // 36.5.2 serviceLoader的获取方式二, 通过spring的ServiceLoaderFactoryBean来获取 ServiceLoader, 这里有spring的参与了
        // 这里是通过ServiceLoaderFactoryBean 来创建一个 ServiceLoader , 并且这个 ServiceLoader 只关注 UserFactory,
        // 如果有多个对象, 与方式一相比这种方式不会逐一输出
        ServiceLoader<UserFactory> serviceLoader = beanFactory.getBean("userFactoryServiceLoader", ServiceLoader.class);

        displayServiceLoader(serviceLoader);

        // 36.5.1 ServiceLoader的获取方式一
        // 与方式二相比, 这里如果配置了多个类会逐一输出
//        demoServiceLoader();


    }

    public static void demoServiceLoader() {
        // ServiceLoader 是java1.6开始 提供的一个用于依赖注入的类, 其中
        //  private static final String PREFIX = "META-INF/services/";
        // 我们需要这么个路径, 里面的文件名是需要实例化的类的接口的全类名
        // 文件的内容则是接口实现类的全类名, 可以是一个或多个, 重复的话也会被去重, 这里就是jdk里面的反转控制/依赖查找

        // serviceLoader的获取方式一, 通过ServiceLoader的静态方法 load(), 这是纯jdk的方法
        ServiceLoader<UserFactory> serviceLoader = load(UserFactory.class, Thread.currentThread().getContextClassLoader());
        displayServiceLoader(serviceLoader);
    }

    private static void displayServiceLoader(ServiceLoader<UserFactory> serviceLoader) {
        // 可以看出这里允许实例化多个类
        Iterator<UserFactory> iterator = serviceLoader.iterator();
        while (iterator.hasNext()) {
            UserFactory userFactory = iterator.next();
            System.out.println(userFactory.createUser());
        }
    }
}

special-bean-instantiation-context.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 36 | 实例化Spring Bean:Bean实例化的姿势有多少种? -->
    <!-- 方式二, 通过ServiceLoaderFactoryBean, 这里通过spring来获取的ServiceLoader, 就需要用到 ServiceLoaderFactoryBean
            public class ServiceLoaderFactoryBean extends AbstractServiceLoaderBasedFactoryBean implements BeanClassLoaderAware {

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

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

            }

           这是spring提供的工厂类, 但是其中参数的注入怎么弄, 需要看下源码, 往父类找:
            org.springframework.beans.factory.config.AbstractFactoryBean.getObject()
            @Override
            public final T getObject() throws Exception {
                if (isSingleton()) {
                    return (this.initialized ? this.singletonInstance : getEarlySingletonInstance());
                }
                else {
                    return createInstance();
                }
            }

            其中 createInstance() 有很多种实现, 我们看其中的基础实现:
            org.springframework.beans.factory.serviceloader.AbstractServiceLoaderBasedFactoryBean.createInstance
            protected Object createInstance() {
                Assert.notNull(getServiceType(), "Property 'serviceType' is required");
                return getObjectToExpose(ServiceLoader.load(getServiceType(), this.beanClassLoader));
            }
            可以看出来其实和方式一是类似的, 还是需要配置一个 serviceType , 所以我们提供一个要实例化的接口的全类名

            我们再回来看 getObjectToExpose() 的实现
            org.springframework.beans.factory.serviceloader.ServiceFactoryBean.getObjectToExpose
            @Override
            protected Object getObjectToExpose(ServiceLoader<?> serviceLoader) {
                Iterator<?> it = serviceLoader.iterator();
                if (!it.hasNext()) {
                    throw new IllegalStateException(
                            "ServiceLoader could not find service for type [" + getServiceType() + "]");
                }
                return it.next();
            }
            发现它有且只返回一个实现

            有没有能返回多个的呢? 那是肯定的, AbstractServiceLoaderBasedFactoryBean 还有其他实现, 比如
            org.springframework.beans.factory.serviceloader.ServiceListFactoryBean
            public class ServiceListFactoryBean extends AbstractServiceLoaderBasedFactoryBean implements BeanClassLoaderAware {

                @Override
                protected Object getObjectToExpose(ServiceLoader<?> serviceLoader) {
                    List<Object> result = new LinkedList<>();
                    for (Object loaderObject : serviceLoader) {
                        result.add(loaderObject);
                    }
                    return result;
                }

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

            }
             就可以看出来他就是返回一个list

             -->
    <bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
        <property name="serviceType" value="org.geekbang.thinking.in.spring.bean.factory.UserFactory" />
    </bean>
</beans>

META-INF\services\org.geekbang.thinking.in.spring.bean.factory.UserFactory

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.geekbang.thinking.in.spring.bean.factory;

import org.geekbang.thinking.in.spring.ioc.overview.domain.User;

/**
 * 36 | 实例化Spring Bean:Bean实例化的姿势有多少种?
 * {@link User} 36.3 工厂类, 这里是一个代理工厂, 需要用jdk1.8的编译器, pom文件中需要修改编译级别
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
public interface UserFactory {
    // 1.8编译器支持的接口默认实现
    default User createUser() {
        return User.createUser();
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值