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策略带参
相关推荐
杨DaB16 分钟前
【SpringBoot】Swagger 接口工具
java·spring boot·后端·restful·swagger
YA33317 分钟前
java基础(九)sql基础及索引
java·开发语言·sql
桦说编程36 分钟前
方法一定要有返回值 \ o /
java·后端·函数式编程
小李是个程序1 小时前
登录与登录校验:Web安全核心解析
java·spring·web安全·jwt·cookie
David爱编程1 小时前
Java 创建线程的4种姿势,哪种才是企业级项目的最佳实践?
java·后端
ciku1 小时前
Spring AI 集成阿里云百炼平台
人工智能·spring·阿里云
hrrrrb2 小时前
【Java Web 快速入门】十一、Spring Boot 原理
java·前端·spring boot
Java微观世界2 小时前
Object核心类深度剖析
java·后端
MrSYJ2 小时前
为什么HttpSecurity会初始化创建两次
java·后端·程序员
hinotoyk2 小时前
TimeUnit源码分享
java