当前位置:网站首页>Chapter 4: emerging, class instantiation strategy with constructor based on cglib
Chapter 4: emerging, class instantiation strategy with constructor based on cglib
2022-07-19 16:18:00 【Bubble ^ bubble】
The goal is
The main goal of this chapter is to solve the hole we buried in the previous chapter , What kind of pit is that ? It's actually about Bean Object is instantiated in a pit containing a constructor .
In the last chapter we expanded Bean Functions of the container , Give the instantiated object to the container for unified processing , But in our code for instantiating objects, we don't consider whether the object class contains a constructor , In other words, if we instantiate an object with a constructor, we will throw an exception .
How to verify ? It's just a way of UserService Just add a constructor with parameter information , as follows :
ublic class UserService {
private String name;
public UserService(String name) {
this.name = name;
}
// ...
}
An error is as follows :
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)
...
The main reason for this phenomenon is that beanDefinition.getBeanClass().newInstance(); Instantiation does not take into account the input parameters of the constructor , So this pit is waiting for you ! So our goal is obvious , Come and fill this hole !
Design
The technical design of filling this pit mainly considers two parts , One is where the string process reasonably transfers the input parameter information of the constructor to the instantiation operation , The other is how to instantiate objects with constructors .
- Reference resources Spring Bean Implementation of container source code , stay BeanFactory Add Object getBean(String name, Object… args) Interface , So you can get Bean The input parameter information of the constructor is passed in .
- Another core issue is how to create a function with a constructor Bean What about objects? ? There are two ways to choose from , One is based on Java Its own method DeclaredConstructor, The other is to use Cglib To create dynamically Bean object .Cglib It's based on the bytecode framework ASM Realization , So you can also go directly through ASM Operate the script to create an object .
Realization
Engineering structure

Spring Bean Container class 
This chapter “ Filling pit ” It's mainly to add... To existing projects InstantiationStrategy Instantiate policy interface , And add the corresponding getBean Input information , Let the external call pass the input parameter of the constructor and instantiate it smoothly .
newly added getBean Interface
package com;
/** * Bean factory */
public interface BeanFactory {
Object getBean(String name) throws Exception;
Object getBean(String name,Object... args) throws Exception;
}
- BeanFactory In, we overloaded a function that contains input parameter information args Of getBean Method , In this way, the input parameters can be easily passed to the constructor instantiation .
package com;
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
@Override
public Object getBean(String name) throws Exception {
return doGetBean(name,null);
}
@Override
public Object getBean(String name,Object... args) throws Exception {
return doGetBean(name,args);
}
public <T> T doGetBean(String name, Object... args) throws Exception {
Object bean = getSingleton(name);
if(bean != null){
return (T)bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return (T)createBean(name,beanDefinition,args);
}
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws Exception;
protected abstract BeanDefinition getBeanDefinition(String beanName) throws Exception;
}
Define the instantiation policy interface
package com;
import java.lang.reflect.Constructor;
public interface InstantiationStrategy {
Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor,Object[] args) throws Exception;
}
- In instantiating interfaces instantiate Method to add the necessary input information , Include :beanDefinition、 beanName、ctor、args
- among Constructor You may be a little strange , It is java.lang.reflect Under bag Constructor class , It contains some necessary class information , The purpose of having this parameter is to get the constructor corresponding to the input parameter information .
- and args It's a specific parameter information , It will be used in the final instantiation .
JDK Instantiation
package com;
import java.lang.reflect.Constructor;
public class SimpleInstantiationStrategy implements InstantiationStrategy {
@Override
public Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws Exception {
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 [" + clazz.getName() + "]", e);
}
}
}
- First, through beanDefinition obtain Class Information , This Class Information is in Bean It's passed in when it's defined .
- Then judge ctor Is it empty , If it is empty, there is no constructor instantiation , Otherwise, you need to have an instantiation of the constructor .
- Here we focus on instantiation with constructors , The instantiation method is clazz.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args);, Pass the input information to newInstance instantiate .
Cglib Instantiation
package com;
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 Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanDefinition.getBeanClass());
enhancer.setCallback(new NoOp() {
@Override
public int hashCode() {
return super.hashCode();
}
});
if(ctor == null){
return enhancer.create();
}
return enhancer.create(ctor.getParameterTypes(),args);
}
}
- Actually Cglib Create... With a constructor Bean It's also very convenient , Here we simplify the process even more , If you read Spring The source code will also see CallbackFilter Such as implementation , But the way we're doing it doesn't affect creating .
Create policy calls
package com;
import java.lang.reflect.Constructor;
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
@Override
protected Object createBean(String name, BeanDefinition beanDefinition,Object[] args) throws Exception {
Object bean = null;
try {
bean = createBeanInstance(beanDefinition,name,args);
}catch (Exception e){
throw new RuntimeException("Instantiation of bean failed");
}
addSingleton(name,bean);
return bean;
}
/** * Find the corresponding constructor * @param beanDefinition * @param beanName * @param args * @return * @throws Exception */
protected Object createBeanInstance(BeanDefinition beanDefinition,String beanName,Object[] args) throws Exception{
Constructor constructorToUse = null;
Class<?> beanClass = beanDefinition.getBeanClass();
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for(Constructor ctor : declaredConstructors){
if(args != null && ctor.getParameterTypes().length == args.length){
constructorToUse = ctor;
break;
}
}
return getInstantiationStrategy().instantiate(beanDefinition,beanName,constructorToUse,args);
}
public InstantiationStrategy getInstantiationStrategy() {
return instantiationStrategy;
}
}
- First, in the AbstractAutowireCapableBeanFactory The abstract class defines an instantiation policy property class for creating objects InstantiationStrategy instantiationStrategy, Here we chose Cglib Implementation class of .
- Next, extract createBeanInstance Method , In this method, we need to pay attention to Constructor Represents how many constructors you have , adopt beanClass.getDeclaredConstructors() Method can get all your constructors , It's a collection .
- Next, we need to compare the constructor set with the input parameter information args The matching condition of , The way we compare here is relatively simple , It's just a quantitative comparison , But actually Spring The source code also needs to compare the input parameter type , Otherwise, the same number of different input parameter types , It's going to be abnormal .
test
package com;
public class UserService {
private String name;
public UserService() {
}
public UserService(String name) {
this.name = name;
}
public void queryUserInfo(){
System.out.println(" Query user information :"+name);
}
}
package com;
import org.junit.Test;
public class UTest
{
@Test
public void test_BeanFactory() throws Exception {
//1. initialization BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//2. Registration Bean
BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
beanFactory.registerBeanDefinition("userService",beanDefinition);
//3. obtain Bean
UserService userService = (UserService)beanFactory.getBean("userService"," Xiao Zhang ");
userService.queryUserInfo();
}
}

边栏推荐
- Ch549/ch548 Learning Notes 6 - read chip ID
- Liquibase learning - problem solving: start error reporting
- HCIA -- OSPF experimental report
- 【单片机仿真项目】广告灯(proteus原理图+keil代码)
- Dynamic adding method and property modification of object extensions in typescript
- Learning notes of JUC source code 2 - AQS sharing and semaphore, countdownlatch
- Fiddler:增加IP列
- 数据处理Numpy的基本使用方法
- Liquibase学习1 - 安装、简单使用
- 解决MATLAB安装后出现 “License Manager Error -8”(亲测有效)
猜你喜欢

Ugui source code analysis - rectmask2d

Fiddler:增加IP列

Ch549/ch548 learning notes 8 - USB device interrupt processing

CH549/CH548学习笔记4 - Timer

Liquibase learning 2 - Introduction to the extension plug-in liquibase data

Liquibase learning - problem solving: start error reporting

PwnTheBox,Web:Double-S

干货!综合的公平冷启动推荐系统

论文阅读 TEMPORAL GRAPH NETWORKS FOR DEEP LEARNING ON DYNAMIC GRAPHS

Opencv image transparent area clipping imagecroppingtrn
随机推荐
Use ZVS to drive wireless charging coil
力扣 565. 数组嵌套
Ch549/ch548 learning notes 3 - UART
Mathematical modeling -- the road from nature to Rationality -- Introduction to mathematical modeling (learning note 1)
Liquibase学习3 - logLevel日志等级、常用命令
同花顺炒股安全吗?
Pwnthebox, Web: Double - S
MySQL - adjust column constraints
CH549/CH548学习笔记7 - USB Device初始化
CH549/CH548学习笔记8 - USB Device中断处理
PwnTheBox,Web:Double-S
await后面的所有类型代码直接扔到微任务队列中,稍后执行
ArrayList source code analysis I
解决MATLAB安装后出现 “License Manager Error -8”(亲测有效)
openresty lua-resty-lrucache缓存
Ffifdyop bypasses MD5 for SQL injection
CH549/CH548学习笔记6 - 读取芯片ID
Ch549 / ch548 notes d'apprentissage 9 - procédure de traitement des paramètres du périphérique USB
手写简易Promise代码注释
The solution that Google browser chrome cannot be upgraded