3、实现含构造函数的类实例化策略

101 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第19天,点击查看活动详情

基于策略模式实现两种用于实例化对象的方法,如 JDK、Cglib,并基于此方法实现含邮带入参信息的构造函数的类实例化策略

如果之前的代码实例化有入餐信息的构造函数的类,就会报错。原因是:beanDefinition.getBeanClass().newInstance() 的实例化方法并没有考虑类中含有带入参信息的构造函数,所以会报异常。

实例化策略设计

1.如何将构造函数的入参信息合理地传递到实例化中

2.如何将入参信息的构造函数的类实例化

使用什么方式可以创建包含构造函数的Bean 对象?

1.基于Java 本身自带的方法 DeclaredConstructor

2.使用 Cglib 动态创建 Bean 对象

ps:Cglib 是基于 ASM 字节码框架实现。

核心

在上一节的基础上 添加 InstantiationStrategy 实例化策略接口、开发 JDK 和 Cglib 实例化方法,以此来实现带入参信息的构造函数的实例化

代码实现

pom - cglib 实例化添加代码

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

BeanFactory - 重写 带参数的 getBean 方法

public interface BeanFactory {
    /**
     * @Author: Take-off
     * @Description: //TODO 返回Bean 的实例对象
     * @Date: 10:01 AM 2022/12/12
     * @Param: [name]
     * @return: java.lang.Object
     **/
    Object getBean(String name) throws BeansException;
​
​
    Object getBean(String name,Object... args) throws BeansException;
}

InstantiationStrategy - 实例化策略 接口

public interface InstantiationStrategy {
​
    /**
     * @Author: Take-off
     * @Description: //TODO
     * @Date: 8:57 PM 2022/12/13
     * @Param: [beanDefinition, beanName, ctor, args] :ctor - 获取与入参信息相对应的构造函数
     * @return: java.lang.Object
     **/
    Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException;
​
}

Constructor - 获取与入参信息相对应的构造函数

SimpleInstantiationStrategy - JDK实例化实现

public class SimpleInstantiationStrategy implements InstantiationStrategy{
    @Override
    public Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException {
        Class beanClass = beanDefinition.getBeanClass();
        try {
            if (Optional.ofNullable(ctor).isPresent()){
                //传递构造函数的入参、信息进行实例化
                //将入参信息传递给 newInstance 进行实例化
                return beanClass.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args);
            }else {
                //无构造函数
                return beanClass.getDeclaredConstructor().newInstance();
            }
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            throw new BeansException("Failed to instantiate [" + beanClass.getName() + "]", e);
        }
    }
}

CglibSubclassingInstantiationStrategy - Cglib 实例化

public class CglibSubclassingInstantiationStrategy implements InstantiationStrategy{
    @Override
    public Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException {
        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);
    }
}

测试类

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","居头小刘");
        userService.queryUserInfo();
    }
​
}
public class UserService {
​
    private String name;
​
    public UserService(String name) {
        this.name = name;
    }
​
    public void queryUserInfo(){
        System.out.println("查询用户信息" + name);
    }
}

总结

完善了实例化策略,增加了 InstantiationStrategy 实例化策略。