关于 Bean 对象在含有构造函数进行实例化?
UserService
public class UserService {
private String name;
public UserService() {
}
public UserService(String name) {
this.name = name;
}
}
报错如下:
Caused by: java.lang.InstantiationException: com.lino.springframework.test.bean.UserService
at java.lang.Class.newInstance(Class.java:427)
at com.lino.springframework.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:17)
... 26 more
beanDefinition.getBeanClass().newInstance()
。实例化方式并没有考虑构造函数的入参。技术设计需要考虑两部分?
Object getBean(String name, Object... args)
接口。
DeclaredConstructor
。spring-step-03
|-src
|-main
| |-java
| |-com.lino.springframework
| |-factory
| | |-config
| | | |-BeanDefinition.java
| | | |-SingletonBeanRegistry.java
| | |-support
| | | |-AbstractAutowireCapableBeanFactory.java
| | | |-AbstractBeabFactory.java
| | | |-BeanDefinitionRegistry.java
| | | |-CglibSubclassingInstantiationStrategy.java
| | | |-DefaultListableBeanFactory.java
| | | |-DefaultSingletonBeanRegistry.java
| | | |-InstantiationStrategy.java
| | | |-SimpleInstantiationStrategy.java
| | |-BeanFactory.java
| |-BeansException.java
|-test
|-java
|-com.lino.springframework.test
|-bean
| |-UserService.java
|-ApiTest.java
getBean
入参信息,让外部调用时可以传递构造函数的入参并顺利实例化。InstantiationStrategy.java
package com.lino.springframework.factory.support;
import com.lino.springframework.BeansException;
import com.lino.springframework.factory.config.BeanDefinition;
import java.lang.reflect.Constructor;
/**
* @description: Bean 实例化策略接口
*/
public interface InstantiationStrategy {
/**
* 实例化
*
* @param beanDefinition Bean 对象
* @param beanName 要检索的bean名称
* @param ctor 类信息
* @param args 构造函数入参
* @return 实例化后的对象
* @throws BeansException 不能获取 Bean 对象,抛出异常
*/
Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException;
}
beanDefinition、beanName、ctor、args
。java.lang.reflect
包下的 Constructor 类,里面包含了一些必要的类信息。
args
就是一个具体的入参信息,最终实例化时会用到。SimpleInstantiationStrategy.java
package com.lino.springframework.factory.support;
import com.lino.springframework.BeansException;
import com.lino.springframework.factory.config.BeanDefinition;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* @description: JDK实例化策略
*/
public class SimpleInstantiationStrategy implements InstantiationStrategy {
@Override
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 (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
throw new BeansException("Failed to instantiate [" + clazz.getName() + "]", e);
}
}
}
beanDefinition
获取 Class 信息,这个 Class 信息是在 Bean 定义的时候传递进去的。ctor
是否为空,如果为空则是无构造函数实例化,否则就是需要有构造函数的实例化。clazz.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args)
,把入参信息传递给 newInstance
进行实例化。CglibSubclassingInstantiationStrategy.java
package com.lino.springframework.factory.support;
import com.lino.springframework.BeansException;
import com.lino.springframework.factory.config.BeanDefinition;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;
import java.lang.reflect.Constructor;
/**
* @description: 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);
}
}
BeanFactory.java
package com.lino.springframework.factory;
import com.lino.springframework.BeansException;
/**
* @description: 定义 Bean 工厂接口
*/
public interface BeanFactory {
/**
* 返回 Bean 的实例对象
*
* @param name 要检索的bean的名称
* @return 实例化的 Bean 对象
* @throws BeansException 不能获取 Bean 对象,抛出异常
*/
Object getBean(String name) throws BeansException;
/**
* 返回含构造函数的 Bean 实例对象
*
* @param name 要检索的bean的名称
* @param args 构造函数入参
* @return 实例化的 Bean 对象
* @throws BeansException 不能获取 Bean 对象,抛出异常
*/
Object getBean(String name, Object... args) throws BeansException;
}
args
的 getBean
方法,这样就可以传递入参给构造函数实例化了。AbstractBeanFactory.java
package com.lino.springframework.factory.support;
import com.lino.springframework.BeansException;
import com.lino.springframework.factory.BeanFactory;
import com.lino.springframework.factory.config.BeanDefinition;
/**
* @description: 抽象的 Bean 工厂基类,定义模板方法
* @author: lingjian
* @createDate: 2022/11/22 14:34
*/
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, args);
}
protected <T> T doGetBean(final String name, final Object[] args) {
Object bean = getSingleton(name);
if (bean != null) {
return (T) bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return (T) createBean(name, beanDefinition, args);
}
/**
* 获取 Bean 对象
*
* @param beanName 要检索的bean的名称
* @return Bean 对象
*/
protected abstract BeanDefinition getBeanDefinition(String beanName);
/**
* 创建Bean对象
*
* @param beanName 要检索的bean的名称
* @param beanDefinition Bean对象
* @param args 构造函数入参
* @return 实例化的Bean对象
*/
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args);
}
getBean
方法。AbstractAutowireCapableBeanFactory.java
package com.lino.springframework.factory.support;
import com.lino.springframework.BeansException;
import com.lino.springframework.factory.config.BeanDefinition;
import java.lang.reflect.Constructor;
/**
* @description: 实现默认bean创建的抽象bean工厂超类
*/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
Object bean = null;
try {
bean = createBeanInstance(beanDefinition, beanName, args);
} catch (Exception e) {
throw new BeansException("Instantiation of bean failed", e);
}
registerSingletonBean(beanName, bean);
return bean;
}
protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, 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 getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
}
public InstantiationStrategy getInstantiationStrategy() {
return instantiationStrategy;
}
public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
this.instantiationStrategy = instantiationStrategy;
}
}
InstantiationStrategy instantiationStrategy
。这里选择 Cglib 的实现类。createBeanInstance
方法,在这个方法中需要注意 Constructor 代表了你有多少个构造函数,通过 beanClass.getDeclaredConstructors()
方式可以获取到你所有的构造函数,是一个集合。args
的匹配信息。
UserService.java
package com.lino.springframework.test.bean;
/**
* @description: 模拟用户 Bean 对象
*/
public class UserService {
private String name;
public UserService() {
}
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(name);
return sb.toString();
}
}
name
入参的构造函数。ApiTest.java
@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();
}
小零
的入参信息,这个信息的传递将会帮我们创建出含有 String
类型构造函数的 UserService 类,而不会再出现初始化报错的问题。测试结果
查询用户信息: 小零
ApiTest.java
@Test
public void test_newInstance() throws InstantiationException, IllegalAccessException {
UserService userService = UserService.class.newInstance();
System.out.println(userService);
}
测试结果
null
ApiTest.java
@Test
public void test_constructor() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<UserService> userServiceClass = UserService.class;
Constructor<UserService> declaredConstructor = userServiceClass.getDeclaredConstructor(String.class);
UserService userService = declaredConstructor.newInstance("小零");
System.out.println(userService);
}
getDeclaredConstructor
获取构造函数,之后通过传递参数进行实例化。测试结果
小零
ApiTest.java
@Test
public void test_parameterTypes() throws Exception {
Class<UserService> beanClass = UserService.class;
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
Constructor<?> constructor = declaredConstructors[1];
Constructor<UserService> declaredConstructor = beanClass.getDeclaredConstructor(constructor.getParameterTypes());
UserService userService = declaredConstructor.newInstance("小零");
System.out.println(userService);
}
beanClass.getDeclaredConstructors()
。测试结果
小零
ApiTest.java
@Test
public void test_cglib() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new NoOp() {
@Override
public int hashCode() {
return super.hashCode();
}
});
Object obj = enhancer.create(new Class[]{String.class}, new Object[]{"小零"});
System.out.println(obj);
}
测试结果
小零