chapter03_Bean的实例化与策略模式

一、Bean的实例化

  • Spring中的获取的Bean,可能是原始对象,也可能是代理对象(JDK或CGLIB)
  • 所以我们应该至少提供两种实例化的方式,直接new或者是CGLIB

二、策略模式

由于实例化的方式很多,我们这里使用策略模式,便于以后不断地扩展

先扩展一下BeanFactory接口,获取bean的时候,可以传入参数,这样就可以使用带参数的构造器

java 复制代码
public interface BeanFactory {

    Object getBean(String name);

    Object getBean(String name, Object... args);
}

定义实例化策略接口

java 复制代码
public interface InstantiationStrategy {
    Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args);
}

改造doCreateBean方法,灵活切换对象实例化的方式

  • 此处使用最简单的逻辑,直接根据传入的参数数量,匹配对应的构造器
java 复制代码
/**
 * 负责创建Bean
 *
 * @Author 孤风雪影
 * @Email gitee.com/efairy520
 * @Date 2025/1/1 1:01
 * @Version 1.0
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {

    private final InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    /**
     * 实现父类未实现的createBean方法
     * @param beanName
     * @param beanDefinition
     * @return
     */
    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
        Object bean = doCreateBean(beanName, beanDefinition, args);
        addSingleton(beanName, bean);
        return bean;
    }

    protected Object doCreateBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
        Constructor constructorToUse = null;
        Class<?> beanClass = beanDefinition.getBeanClass();
        Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
        for (Constructor<?> ctor : declaredConstructors) {
            //简易逻辑,只比较数量
            if (null != args && ctor.getParameterTypes().length == args.length) {
                constructorToUse = ctor;
                break;
            }
        }
        return instantiationStrategy.instantiate(beanDefinition, beanName, constructorToUse, args);
    }
}

三、简单实例化策略

使用传入的构造器和传入的参数表,直接new对象

java 复制代码
/**
 * @Author 孤风雪影
 * @Email gitee.com/efairy520
 * @Date 2025/1/2 0:01
 * @Version 1.0
 */
public class SimpleInstantiationStrategy implements InstantiationStrategy {
    @Override
    public Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) {
        Class clazz = beanDefinition.getBeanClass();
        try {
            if (ctor != null) {
                return clazz.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args);
            } else {
                return clazz.getDeclaredConstructor().newInstance();
            }
        } catch (Exception e) {
            throw new RuntimeException("Failed to instantiate" + e);
        }
    }
}

四、CGLIB实例化策略

使用传入的构造器和传入的参数表,创建CGLIB代理对象

java 复制代码
/**
 * @Author 孤风雪影
 * @Email gitee.com/efairy520
 * @Date 2025/1/2 0:12
 * @Version 1.0
 */
public class CglibSubclassingInstantiationStrategy implements InstantiationStrategy{
    @Override
    public Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(beanDefinition.getBeanClass());
        enhancer.setCallback(new NoOp() {
            @Override
            public int hashCode() {
                return super.hashCode();
            }
        });
        if (null == ctor) return enhancer.create();
        return enhancer.create(ctor.getParameterTypes(), args);
    }
}

五、测试

给测试的Bean,新建空参构造器和有参构造器

java 复制代码
package cn.shopifymall.springframework.test.bean;

/**
 * @Author 孤风雪影
 * @Email gitee.com/efairy520
 * @Date 2025/2/6 23:15
 * @Version 1.0
 */
public class UserService {

    private String name;

    public UserService() {
        this.name = "undefined";
    }

    public UserService(String name) {
        this.name = name;
    }

    public void queryUserInfo() {
        System.out.println("查询用户信息:" + name);
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("");
        sb.append("").append(name);
        return sb.toString();
    }
}

测试代码

java 复制代码
public class ApiTest {

    @Test
    public void test_BeanFactory(){
        // 1.初始化 BeanFactory
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        // 2. 注入bean
        BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
        beanFactory.registerBeanDefinition("userService", beanDefinition);

        // 3.获取bean
        UserService userService = (UserService) beanFactory.getBean("userService", "abc");
        userService.queryUserInfo();
    }
}

测试以下四种场景

  • 简单策略空参
  • 简单策略带参
  • CGLIB策略空参
  • CGLIB策略带参
相关推荐
懒鸟一枚4 小时前
深入理解 Linux 内存、Swap 交换分区与分页机制的关系
java·linux·数据库
我命由我123456 小时前
执行 Gradle 指令报错,无法将“grep”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
考虑考虑6 小时前
Sentinel安装
java·后端·微服务
凤凰院凶涛QAQ8 小时前
《Java版数据结构 & 集合类剖析》栈与队列:“push/pop 是栈的灵魂,offer/poll 是队列的骨架——四组 API,两种人生”
java·开发语言·数据结构
掘金_答案8 小时前
上线那天,一个 ConcurrentHashMap 差点送走我的 AI 客服——3 天排查 JVM 血泪史
java·后端·架构
猿与禅9 小时前
CosId 分布式 ID 生成器完全教程:从架构原理到生产落地
java·shardingsphere·雪花算法·分布式id·高性能·cosid·号段模式
MindUp9 小时前
企业网盘权限模型解析:多层级访问控制与审计能力选型指南
java·linux·运维
NG4779 小时前
【软件设计与体系结构】-策略设计模式
java·设计模式·软件工程
程序员天天困10 小时前
优雅记录操作日志:从注解到 SpEL 的全链路实践与开源方案对比
java·后端
战血石LoveYY10 小时前
Integer类型超限,导致数据异常
java·算法