做者:小傅哥
博客:https://bugstack.cnhtml
沉淀、分享、成长,让本身和他人都能有所收获!😄
技术成长,是对场景设计细节不断的雕刻!
java
你以为本身的技术何时获得了快速的提升,是CRUD写的多了之后吗?想都不要想,绝对不可能!CRUD写的再多也只是能知足你做为一个搬砖工具人,敲击少逻辑流水代码的速度而已,而编程能力这一块,除了最开始的从不熟练到熟练之外,就不多再有其余提高了。面试
那你可能会想什么才是编程能力提高?其实更多的编程能力的提高是你对复杂场景的架构把控以及对每个技术实现细节点的不断用具备规模体量的流量冲击验证时,是否能保证系统稳定运行从而决定你见识了多少、学到了多少、提高了多少!算法
最终当你在接一个产品需求时,开始思考程序数据结构的设计
、核心功能的算法逻辑实现
、总体服务的设计模式使用
、系统架构的搭建方式
、应用集群的部署结构
,那么也就是的编程能力真正提高的时候!spring
这一章节的目标主要是为了解决上一章节咱们埋下的坑
,那是什么坑呢?其实就是一个关于 Bean 对象在含有构造函数进行实例化的坑。编程
在上一章节咱们扩充了 Bean 容器的功能,把实例化对象交给容器来统一处理,但在咱们实例化对象的代码里并无考虑对象类是否含构造函数,也就是说若是咱们去实例化一个含有构造函数的对象那么就要抛异常了。设计模式
怎么验证?其实就是把 UserService 添加一个含入参信息的构造函数就能够,以下:缓存
public class UserService { private String name; public UserService(String name) { this.name = name; } // ... }
报错以下:数据结构
java.lang.InstantiationException: cn.bugstack.springframework.test.bean.UserService at java.lang.Class.newInstance(Class.java:427) at cn.bugstack.springframework.test.ApiTest.test_newInstance(ApiTest.java:51) ...
发生这一现象的主要缘由就是由于 beanDefinition.getBeanClass().newInstance();
实例化方式并无考虑构造函数的入参,因此就这个坑就在这等着你了!那么咱们的目标就很明显了,来把这个坑填平!架构
填平这个坑的技术设计主要考虑两部分,一个是串流程从哪合理的把构造函数的入参信息传递到实例化操做里,另一个是怎么去实例化含有构造函数的对象。
Object getBean(String name, Object... args)
接口,这样就能够在获取 Bean 时把构造函数的入参信息传递进去了。DeclaredConstructor
,另一个是使用 Cglib 来动态建立 Bean 对象。Cglib 是基于字节码框架 ASM 实现,因此你也能够直接经过 ASM 操做指令码来建立对象small-spring-step-03 └── src ├── main │ └── java │ └── cn.bugstack.springframework.beans │ ├── factory │ │ ├── factory │ │ │ ├── BeanDefinition.java │ │ │ └── SingletonBeanRegistry.java │ │ ├── support │ │ │ ├── AbstractAutowireCapableBeanFactory.java │ │ │ ├── AbstractBeanFactory.java │ │ │ ├── BeanDefinitionRegistry.java │ │ │ ├── CglibSubclassingInstantiationStrategy.java │ │ │ ├── DefaultListableBeanFactory.java │ │ │ ├── DefaultSingletonBeanRegistry.java │ │ │ ├── InstantiationStrategy.java │ │ │ └── SimpleInstantiationStrategy.java │ │ └── BeanFactory.java │ └── BeansException.java └── test └── java └── cn.bugstack.springframework.test ├── bean │ └── UserService.java └── ApiTest.java
工程源码:公众号「bugstack虫洞栈」,回复:Spring 专栏,获取完整源码
Spring Bean 容器类关系,如图 4-2
本章节“填坑”
主要是在现有工程中添加 InstantiationStrategy 实例化策略接口,以及补充相应的 getBean 入参信息,让外部调用时能够传递构造函数的入参并顺利实例化。
cn.bugstack.springframework.beans.factory.BeanFactory
public interface BeanFactory { Object getBean(String name) throws BeansException; Object getBean(String name, Object... args) throws BeansException; }
cn.bugstack.springframework.beans.factory.support.InstantiationStrategy
public interface InstantiationStrategy { Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException; }
cn.bugstack.springframework.beans.factory.support.SimpleInstantiationStrategy
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 | InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new BeansException("Failed to instantiate [" + clazz.getName() + "]", e); } } }
clazz.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args);
,把入参信息传递给 newInstance 进行实例化。cn.bugstack.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy
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); } }
cn.bugstack.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory { private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy(); @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) { 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); } }
InstantiationStrategy instantiationStrategy
,这里咱们选择了 Cglib 的实现类。createBeanInstance
方法,在这个方法中须要注意 Constructor 表明了你有多少个构造函数,经过 beanClass.getDeclaredConstructors() 方式能够获取到你全部的构造函数,是一个集合。args
的匹配状况,这里咱们对比的方式比较简单,只是一个数量对比,而实际 Springcn.bugstack.springframework.test.bean.UserService
public class UserService { private String name; 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(); } }
cn.bugstack.springframework.test.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(); }
查询用户信息:小傅哥 Process finished with exit code 0
SimpleInstantiationStrategy
、CglibSubclassingInstantiationStrategy
这里咱们再把几种不一样方式的实例化操做,放到单元测试中,方便你们比对学习。
@Test public void test_newInstance() throws IllegalAccessException, InstantiationException { UserService userService = UserService.class.newInstance(); System.out.println(userService); }
@Test public void test_constructor() throws Exception { Class<UserService> userServiceClass = UserService.class; Constructor<UserService> declaredConstructor = userServiceClass.getDeclaredConstructor(String.class); UserService userService = declaredConstructor.newInstance("小傅哥"); System.out.println(userService); }
getDeclaredConstructor
获取构造函数,以后在经过传递参数进行实例化。@Test public void test_parameterTypes() throws Exception { Class<UserService> beanClass = UserService.class; Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors(); Constructor<?> constructor = declaredConstructors[0]; Constructor<UserService> declaredConstructor = beanClass.getDeclaredConstructor(constructor.getParameterTypes()); UserService userService = declaredConstructor.newInstance("小傅哥"); System.out.println(userService);
beanClass.getDeclaredConstructors()
@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); }