实现有参构造的实例化
简介
在上一篇根据 Bean 的Class对象通过反射创建实例,实际上是通过调用无参构造实例化的,如果只有有参构造就会有问题,本篇先讲解两种方式实现有参构造的实例化,然后是如何将两种实例化方式融入 Bean 的生命周期中
源码:small-spring03
阅读前建议先了解一下代理模式,链接:proxy
实例化
由于不止一种实例化方法,所以可以创建一个接口用来规范方法的实现,下面是接口的代码
InstantiationStrategy
package com.meteor.factory.support;
import com.meteor.BeansException; import com.meteor.factory.config.BeanDefinition;
import java.lang.reflect.Constructor;
public interface InstantiationStrategy { Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException; }
|
JDK
JDK依然是通过反射创建实例,不过现在要判断是否有入参,根据参数的有无调用不同的方法,代码如下:
SimpleInstantiationStrategy
package com.meteor.factory.support;
import com.meteor.BeansException; import com.meteor.factory.config.BeanDefinition;
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;
public class SimpleInstantiationStrategy implements InstantiationStrategy{
public Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException { Class clazz = beanDefinition.getBeanClass(); try{ if(null!=ctor){ return clazz.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args); } else{ return clazz.getDeclaredConstructor().newInstance(); } } catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException e) { throw new BeansException("Failed to instantiate ["+clazz.getName()+"]",e); } } }
|
Cglib
Cglib是通过生成子类的方式实例化的,即创建从外界传入 Bean 的Class对象的子类,代码如下:
CglibSubclassingInstantiationStrategy
package com.meteor.factory.support;
import com.meteor.BeansException; import com.meteor.factory.config.BeanDefinition; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.NoOp;
import java.lang.reflect.Constructor;
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); } }
|
融合Bean实例化
接下来就是将实例化融入到 Bean 的生命周期中,在目前存在的类中,AbstractAutowireCapableBeanFactory 类负责创建 Bean,也包括 Bean 的实例化,因此要将实例化融入到这个类中。
由于之前已经创建了一个接口 InstantiationStrategy 来管理所有的实例化策略,所以可以在 AbstractAutowireCapableBeanFactory 内添加一个 InstantiationStrategy 类型的字段,利用多态自由的切换不同的实例化策略
AbstractAutowireCapableBeanFactory
package com.meteor.factory.support;
import com.meteor.BeansException; import com.meteor.factory.config.BeanDefinition;
import java.lang.reflect.Constructor;
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory { private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
public InstantiationStrategy getInstantiationStrategy() { return instantiationStrategy; }
public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) { this.instantiationStrategy = instantiationStrategy; }
@Override protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException { Object bean = null; try { bean = createBeanInstance(beanDefinition, beanName, args); } catch (Exception e) { throw new BeansException("Instantiation of bean failed", e); } addSingleton(beanName, bean); return bean; }
protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) throws BeansException { 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 getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args); }
}
|
测试
要测试有参构造能顺利获取到Bean,还是先创建一个UserService,而且只提供了有参构造
UserService
package com.meteor.bean;
public class UserService { private final String name;
public UserService(String name){ this.name = name; } public void queryUserInfo(){ System.out.println("查询用户信息:"+name); }
}
|
开始测试
package com.meteor;
import com.meteor.bean.UserService; import com.meteor.factory.config.BeanDefinition; import com.meteor.factory.support.DefaultListableBeanFactory; import org.junit.Test;
public class AppTest { @Test public void testBeanFactory() { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); BeanDefinition beanDefinition = new BeanDefinition(UserService.class); beanFactory.registerBeanDefinition("userService", beanDefinition); UserService userService = (UserService) beanFactory.getBean("userService", "meteor"); userService.queryUserInfo(); } }
|
输出结果
查询用户信息:meteor
Process finished with exit code 0
|
没有问题,可以顺利获得Bean
总结
本文增加了对有参构造对象的实例化处理,当然,处理的过程做了简化。不过实际使用时,在配置文件中,有时还会配置 Bean 的属性信息,因此下文将会添加属性填充功能
目录结构
相较于上一篇更新的类标注update,新增的类标注为new
src ├── main │ └── java │ └── com.meteor │ ├── factory │ │ ├── config │ │ │ ├── BeanDefinition.java │ │ │ └── SingletonBeanRegistry.java │ │ ├── support │ │ │ ├── AbstractAutowireCapableBeanFactory.java (update) │ │ │ ├── AbstractBeanFactory.java (update) │ │ │ ├── BeanDefinitionRegistry.java │ │ │ ├── CglibSubclassingInstantiationStrategy.java │ │ │ ├── DefaultListableBeanFactory.java (update) │ │ │ └── DefaultSingletonBeanRegistry.java │ │ │ └── InstantiationStrategy.java │ │ │ └── SimpleInstantiationStrategy.java │ │ └── BeanFactory.java (update) │ └── BeansException.java └── test └── java └── com.meteor ├── bean │ └── UserService.java(update) └── MainTest.java
|
依赖
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>RELEASE</version> <scope>test</scope> </dependency> </dependencies>
|