当前位置:网站首页>2021-03-06 - play with the application of reflection in the framework

2021-03-06 - play with the application of reflection in the framework

2022-07-08 01:17:00 Mengqi D Xiaowu

Play with the application of reflection in the framework

Preface : Talking about reflection , You have to mention bytecode , From bytecode to reflection class loading , To apply in the framework , To handwriting IOC and DI The implementation of the

Catalog

1、 Bytecode

2、 Reflection

2.1 Advantages and disadvantages of reflection

2.2 from JVM Level understanding reflection

2.3 Summarize the reasons for slow reflection performance

3、 Class loading process

3.1 load

3.2 Connect

3.3 initialization

3.4 When the class completes initialization

3.5 Class How to get objects

4、 To explore the Class Internal elements

5、 The singleton pattern

6、Spring IOC and DI

6.1 Application of reflection in framework

6.2 Handwriting Spring IOC、DI

6.3  Handwriting Testing Framework

7、Spring Core container class structure

7.1 BeanFactory

7.2 BeanDefinition


1、 Bytecode

Bytecode files are a series 8 Binary stream of bits and bytes , The data items it contains are composed in a fixed order , And there is no interval between adjacent items .—— Because every structure is strictly standardized , So it can be parsed smoothly .

This use Java Language to describe the structure of byte files . If you don't say much, put the picture first , as follows :

For 16 Base code , Except for the beginning cafe babe, The rest can be roughly translated into : What the hell is this ......

Don't panic, hero , We will learn from what we can know "cafe babe" Let's talk about it . At the beginning of the document 4 Bytes are called magic number , Only with “cafe babe” At the beginning class The file can be accepted by the virtual machine , this 4 One byte is the identification of bytecode file . Shift your eyes to the right ,0000 It's a compiler jdk The minor version number of the version 0,0034 Convert to decimal yes 52, It's the main version number ,java The version number of is from 45 Start , except 1.0 and 1.1 Is to use 45.x Outside , Every large version in the future , Version number plus one . in other words , Compile and generate the class Of documents jdk Version is 1.8.0. adopt java -version The command is slightly verified , But it turns out .

Java(TM) SE Runtime Environment (build 1.8.0_131-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

The result is verified .

Continuing down is the constant pool .

Constant pool capacity meter value (constant_pool_count), What is special is , And java Different habits , This capacity count is from 1 instead of 0 Start , For other sets , Include interface index set 、 Field table set 、 The capacity count of method table set is the same as the general habit , It's from 0 At the beginning .

……

...... Bytecode is not the focus of this article , Interested students can learn more about ......

2、 Reflection

In layman's terms , utilize JDK Reflections provided API Make a reflection call .

Reflection is more flexible than the ordinary way of creating instances —— Good scalability .

Through comparison, we found that , Reflection takes longer . Performance analysis of reflection mechanism :

@sun.reflect.CallerSensitive
public static native java.lang.Class<?> getCallerClass();
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
// call native Method to get the caller's Class
Class<?> caller = Reflection.getCallerClass();
// call native Methods according to the className Find bytecode object , And load it 、 analysis 
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
/** Called after security check for system loader access checks have been made. */
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
@CallerSensitive
public T newInstance()
throws InstantiationException, IllegalAccessException
{
// When instantiating through reflection , If you have configuration SecurityManager Safety verification is required first , Ordinary instantiation does not require 
if (System.getSecurityManager() != null) {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
}
// NOTE: the following code may not be strictly correct under
// the current Java memory model.
// Constructor lookup
if (cachedConstructor == null) {
if (this == Class.class) {
throw new IllegalAccessException(
"Can not call newInstance() on the Class for java.lang.Class"
);
}
try {
Class<?>[] empty = {};
final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
// Disable accessibility checks on the constructor
// since we have to do the security check here anyway
// (the stack depth is wrong for the Constructor's
// security check to work)
// Safety verification for the first time 
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
c.setAccessible(true);
return null;
}
});
// Cache the constructor , Improve performance the next time you create an object through reflection 
cachedConstructor = c;
} catch (NoSuchMethodException e) {
throw (InstantiationException)
new InstantiationException(getName()).initCause(e);
}
}
Constructor<T> tmpConstructor = cachedConstructor;
// Security check (same as in java.lang.reflect.Constructor)
// The second safety verification , This modifier stay JDK Inside is a int Value to represent the ,
int modifiers = tmpConstructor.getModifiers();
if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
if (newInstanceCallerCache != caller) {
Reflection.ensureMemberAccess(caller, this, null, modifiers);
newInstanceCallerCache = caller;
}
}
// Run constructor
try {
// Instantiate objects through constructors 
return tmpConstructor.newInstance((Object[])null);
} catch (InvocationTargetException e) {
Unsafe.getUnsafe().throwException(e.getTargetException());
// Not reached
return null;
}
}

2.1 Advantages and disadvantages of reflection

advantage

  • Increase the flexibility of the program , Avoid writing down inherent logic
  • The code is concise , High readability , Increase code reuse rate

shortcoming

  • Compared with direct call , In the case of a large number of visits , Reflection will lead to a significant decline in system performance
  • Breaking the encapsulation of classes , There is a certain security risk

2.2 from JVM Level understanding reflection

JVM adopt Class Find the class name of Class Bytecode file , And then through ClassLoader The class loading mechanism of allocates objects in heap memory ( Don't consider that the object is on the stack ,TLAB Distribution on ).

2.3 Summarize the reasons for slow reflection performance

  1. Reflection calls will perform a series of security checks
  2. Reflection requires calling a series of nativenative Method to implement
  3. seek ClassClass Bytecode process , Such as through CClassNamelassName Find the corresponding bytecode, find the corresponding bytecode CClasslass, Then load 、 analysis , This will also be slower , And this will be slower , and new There is no need to look for , Because the symbolic reference has been converted to direct reference in the parsing phase of the connection
  4. Input verification

3、 Class loading process

Class loading trilogy , load 、 Connect 、 initialization

3.1 load

  1. • load .class file , There are mainly the following ways :
  2. • Load from the local file system
  3. • Download... Over the Internet
  4. • from zip.jar Package to load .class file
  5. • Load from the storage middleware ( database 、 cache …)
  6. • stay JVM Dynamic bytecode recombination during operation (ASM)

3.2 Connect

  1. Connection is to merge the binary data of the class that has been read into memory into JVM In the runtime environment of , There are three main stages in the connection process
  2. • Class validation , Check the class file ( Version number 、 modulus ) In order to make sure .class accord with JVM standard
  3. • Class preparation , Allocate constant pool space , Parsing constant pool , Allocation of static variables , But it will not initialize , Only default values will be given
  4. • Class parsing , Parse parent class , Parsing interface , analysis Filed, List of parsing methods ( Include stack 、 Byte code table 、 Anomaly table 、 Local variable table 、 Run pointer ), Convert binary like symbolic references into direct references

3.3 initialization

  1. JVM Execute the initial statement of the class , Assign a value to the static variable of the class
  2. • If the class has not been loaded and connected yet , Then load and connect first
  3. • If this class has a parent , And the parent class has no initial words , Then initialize the parent class first
  4. • If there is an initialization statement in the class (Static block ), Execute initialization statements in turn

3.4 When the class completes initialization

  1. • Create an instance of a class new xxxClass() || Class.newInstance() || constructor.newInstance()
  2. • Accessing a static variable of a , Or assign values to static variables
  3. • Calling static methods of a class
  4. •Class.forName(" Package class name "), because forName There's one in it init Parameter is true
  5. • Complete the initialization of subclasses , It will also complete the initialization of this class ( Except for the interface )
  6. • This class is the program boot entry (main entrance perhaps test entrance )

3.5 Class How to get objects

  1. •Class clazz = xxxClass.class;// Initialization process is not completed
  2. •Class class = instanceObj.getClass;// Object generated , Complete the initialization process
  3. •Class clazz = xxxClassLoader.loadClass(" Package class name ");// Initialization process not completed
  4. •Class clazz = Class.forName(" Package class name ");// Complete the initialization process

4、 To explore the Class Internal elements

Class clazz = Class.forName(XXXX);

clazz.newInstance();

clazz.newInstance(); What is the essence ?

http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/1c6e1f187fdc/src/share/vm/classfile/javaClasses.cpp

The essence :JDK→constructor

JVM→instanceKlass→instanceOop   OopDesc→Object(Java)

5、 The singleton pattern

• Privatization constructor

• Globally unique public access point

The singleton mode can be broken through the reflection mechanism . The singleton pattern , Please move to another article in design patterns : Single case mode in JDK as well as Spring How to concatenate in the source code

6、Spring IOC and DI

IOC There are three ways to create :

  • How it was created 1: Empty parameter construction creation
  • How it was created 2: Static factory creation
  • How it was created 3: Instance factory creation

DI There are three ways to create :

  • How it was created 1: Parametric construction creates
  • How it was created 2:setter establish
  • How it was created 3:field establish (very few usage)

6.1 Application of reflection in framework

stay Sping Medium IOC Instance creation

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
// Instantiation Bean Methods 
return instantiateBean(beanName, mbd);
}
/**
* Instantiate the given bean using its default constructor.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return a BeanWrapper for the new instance
*/
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, null, modifiers);
}
}
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
if (ca == null) {
ca = acquireConstructorAccessor();
}
@SuppressWarnings("unchecked")
T inst = (T) ca.newInstance(initargs);
return inst;
}
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
return (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}

analysis Bean Of class spring Is used through classLoader The way

@Nullable
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
throws ClassNotFoundException {
ClassLoader beanClassLoader = getBeanClassLoader();
ClassLoader dynamicLoader = beanClassLoader;
boolean freshResolve = false;
if (!ObjectUtils.isEmpty(typesToMatch)) {
// When just doing type checks (i.e. not creating an actual instance yet),
// use the specified temporary class loader (e.g. in a weaving scenario).
ClassLoader tempClassLoader = getTempClassLoader();
if (tempClassLoader != null) {
dynamicLoader = tempClassLoader;
freshResolve = true;
if (tempClassLoader instanceof DecoratingClassLoader) {
DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
for (Class<?> typeToMatch : typesToMatch) {
dcl.excludeClass(typeToMatch.getName());
}
}
}
}
String className = mbd.getBeanClassName();
if (className != null) {
Object evaluated = evaluateBeanDefinitionString(className, mbd);
if (!className.equals(evaluated)) {
// A dynamically resolved expression, supported as of 4.2...
if (evaluated instanceof Class) {
return (Class<?>) evaluated;
}
else if (evaluated instanceof String) {
className = (String) evaluated;
freshResolve = true;
}
else {
throw new IllegalStateException("Invalid class name expression result: " + evaluated);
}
}
if (freshResolve) {
// When resolving against a temporary class loader, exit early in order
// to avoid storing the resolved Class in the bean definition.
if (dynamicLoader != null) {
try {
return dynamicLoader.loadClass(className);
}
catch (ClassNotFoundException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
}
}
}
return ClassUtils.forName(className, dynamicLoader);
}
}
// Resolve regularly, caching the result in the BeanDefinition...
return mbd.resolveBeanClass(beanClassLoader);
}

Set instance properties

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
// Inject... By name 
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
// Inject... According to type 
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// adopt @Resource @Autowre  Of  BeanPostProcessor
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
/**
* Either this or {@link #getResourceToInject} needs to be overridden.
*/
// Injecting attributes through reflection 
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}

6.2 Handwriting Spring IOC、DI

Dynamically create object instances
Methods for dynamically manipulating instance objects 、 attribute

1. First create IOC、DI class

public class A {

    public A() {
        System.out.println("A whitout parameters Constructor invoke!");
    }

    public static B createBObj() { //factory-method
        System.out.println("A static function createBObj() invoke!");
        return new B();
    }

    public C createCObj() { //instance-method
        System.out.println("a's createCObj() invoke!");
        return new C();
    }

}

public class B {

}

public class C {

}

public class D {

    private A a;

    private B b;

    public D() {
        System.out.println("D without parameters Constructor invoke!");
    }

    public D(A a, B b) {
        System.out.println("D constructor with parameters invoke!");
        this.a = a;
        this.b = b;
    }
}

public class E {

    private A a;
    private B b;


    public void setA(A a) {
        System.out.println("E setA() invoke!");
        this.a = a;
    }

    public void setB(B b) {
        System.out.println("E setB() invoke!");
        this.b = b;
    }

}

2.BeanConfig

public class BeanConfig {  //spring-ioc.xml spring-di.xml

    private String id;
    private String clazz;
    private String factoryMethod;
    private String factoryBean;

    private HashMap dependencyHashMap = new HashMap<String, List<String>>();

    private List<String> constructBeans = new ArrayList<>();

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getClazz() {
        return clazz;
    }

    public void setClazz(String clazz) {
        this.clazz = clazz;
    }

    public String getFactoryMethod() {
        return factoryMethod;
    }

    public void setFactoryMethod(String factoryMethod) {
        this.factoryMethod = factoryMethod;
    }

    public String getFactoryBean() {
        return factoryBean;
    }

    public void setFactoryBean(String factoryBean) {
        this.factoryBean = factoryBean;
    }


    public void addConstructBeanId(String beanId){
        constructBeans.add(beanId);
    }

    public List<String> getConstructBeans() {
        return constructBeans;
    }

    public void putDependcyBeanId(String propName,String beanId){
        dependencyHashMap.put(propName,beanId);
    }

    public HashMap<String, String> getDependencyHashMap(){
        return dependencyHashMap;
    }

}

3.BootStrap

public class BootStrap {

    public static void main(String[] args) throws Exception {

        //   Simulation analysis xml    Get  beanConfigs
        List<BeanConfig> beanConfigs = parseXmltoBeanConfig();

        // loop 
        for (BeanConfig tmpconfig : beanConfigs) {

            if (null != tmpconfig.getClazz()) {

                // Get clazz
                Class clazz = Class.forName(tmpconfig.getClazz());


                if (null != tmpconfig.getFactoryMethod())
                {

                    // be based on Class Object acquisition method object 
                    Method method = clazz.getDeclaredMethod(tmpconfig.getFactoryMethod());


                    IOCContainer.putBean(tmpconfig.getId(), method.invoke(null));

                } else {
                    // hold the bean reference
                    //  Parameter construction 
                    if(tmpconfig.getConstructBeans().size()>0) {
                        List<String> contructBeanIds = tmpconfig.getConstructBeans();
                        Object[] constructorParams = new Object[contructBeanIds.size()];
                        Class[] contructorClasses = new Class[contructBeanIds.size()];
                        for (int i = 0; i < contructBeanIds.size(); i++) {
                            Object parami = IOCContainer.getBean(contructBeanIds.get(i));
                            if (parami == null) {
                                System.out.println("init error,");
                                throw new Exception("init-err");
                            }
                            constructorParams[i] = parami;
                            contructorClasses[i] = parami.getClass();
                        }
                        Constructor c = clazz.getConstructor(contructorClasses);// Get the structure with parameters 
                        IOCContainer.putBean(tmpconfig.getId(), c.newInstance(constructorParams));
                    }else {
                        IOCContainer.putBean(tmpconfig.getId(), clazz.newInstance());
                    }
                    //DI
                    if(tmpconfig.getDependencyHashMap().size()>0){
                        for(Map.Entry<String,String> entry : tmpconfig.getDependencyHashMap().entrySet()){
                            Object bean = IOCContainer.getBean(tmpconfig.getId());
                            String methodKey = entry.getKey();
                            String beanId = entry.getValue();
                            Object[] params = new Object[1];
                            params[0] = IOCContainer.getBean(beanId);
                            Class[] paramTypes = new Class[1];
                            paramTypes[0] = params[0].getClass();
                            String methodName
                                    = "set"
                                    + methodKey.substring(0,1).toUpperCase()
                                    + (methodKey.length()>1?methodKey.substring(1,methodKey.length()-1):"");

                            Method setx = bean.getClass().getMethod(methodName,paramTypes);
                            setx.invoke(bean,params);
                        }
                    }
                }

            } else if(null != tmpconfig.getFactoryBean()) {

                // Get the entity from the container bean
                Object obj = IOCContainer.getBean( tmpconfig.getFactoryBean());


                Method method = obj.getClass().getDeclaredMethod(tmpconfig.getFactoryMethod());


                IOCContainer.putBean(tmpconfig.getId(),  method.invoke(obj));

            }else{
                System.out.println("Configuration is required!");
            }

        }

        //IOC  test 
        A a = IOCContainer.getBean("a",A.class);
        B b = IOCContainer.getBean("b",B.class);
        C c = IOCContainer.getBean("c",C.class);
        D d = IOCContainer.getBean("d",D.class);
        E e = IOCContainer.getBean("e", E.class);


    }


    public void doDependencyInjection(){
        // IOCContainer get  Object
        //  Reflection  get Method
        //  Resolve the relationship of dependency injection  DependencyHashMap
        //  Reflection call  3 Kind of  Object Constructor, setter  Method to set the dependencies between objects  field(very few usage)
    }

    /**
     *  Simulate an analysis XML The process 
     *
     * @return
     */
    private static List<BeanConfig> parseXmltoBeanConfig() {

        //TODO
        List<BeanConfig> beanConfigs = new ArrayList<BeanConfig>();
        BeanConfig beanConfig1 = new BeanConfig();
        beanConfig1.setClazz("com.iocdi.A");
        beanConfig1.setId("a");
        beanConfigs.add(beanConfig1);


        BeanConfig beanConfig2 = new BeanConfig();
        beanConfig2.setClazz("com.iocdi.A");
        beanConfig2.setId("b");
        beanConfig2.setFactoryMethod("createBObj");
        beanConfigs.add(beanConfig2);


        BeanConfig beanConfig3 = new BeanConfig();
        beanConfig3.setId("c");
        beanConfig3.setFactoryBean("a");
        beanConfig3.setFactoryMethod("createCObj");
        beanConfigs.add(beanConfig3);

        BeanConfig beanConfig4 = new BeanConfig();
        beanConfig4.setId("d");
        beanConfig4.setClazz("com.iocdi.D");
        beanConfig4.addConstructBeanId("a");
        beanConfig4.addConstructBeanId("b");
        beanConfigs.add(beanConfig4);

        BeanConfig beanConfig5 = new BeanConfig();
        beanConfig5.setId("e");
        beanConfig5.setClazz("com.iocdi.E");
        beanConfig5.putDependcyBeanId("a","a");
        beanConfig5.putDependcyBeanId("b","b");
        beanConfigs.add(beanConfig5);

        return beanConfigs;
    }
}

4.IOCContainer

public class IOCContainer {

    private static HashMap IoContainer = new HashMap();

    public static void putBean(String id,Object object){
        IoContainer.put(id,object);
    }

    public static Object getBean(String id){
        return IoContainer.get(id);
    }

    public static <T> T getBean(String id,Class<T> clazz){
        return (T)IoContainer.get(id);
    }
}

6.3  Handwriting Testing Framework

1. annotation Test

/**
 * Indicates that the annotated method is a test method.
 * This annotation should be used only on parameterless static methods.
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD})
public @interface Test {
    // method
    // normal
    // single element
}

2.OrderTestCase

//@Test
public class OrderTestCase {

    @Test
    public static void m1() {System.out.println("m1 is ok."); }

    public static void m2() { }

    @Test
    public static void m3() {
        throw new RuntimeException("Boom");
    }

    public static void m4() { }

    @Test
    public static void m5() { System.out.println("m5 is ok."); }

    public static void m6() { }

    @Test
    public static void m7() {
        throw new RuntimeException("Crash");
    }

    public static void m8() { }

}

3.MainTest

public class MainTest {

    public static void main(String[] args) {
        int passed=0, failed=0;

        try{
            // hard code to get TestCase Classes

            //TODO  scan package to get all of TestCase Classes
            Method[] methods = Class.forName(args[0]).getMethods(); // how many methods?

            for(Method m : methods){
                if (m.isAnnotationPresent(Test.class)){
                    try{
                        m.invoke(null);
                        passed++;
                    }catch (Throwable ex){
                        System.out.printf("Test %s failed: %s %n", m, ex.getCause());
                        failed++;
                    }
                }
            }
        }catch (ClassNotFoundException ex){
            ex.printStackTrace();
        }

        System.out.printf("Passed: %d, Failed %d%n", passed, failed);
    }


}

7、Spring Core container class structure

7.1 BeanFactory

Spring Bean The creation of is a typical factory model , This series of Bean factory , That is to say IOC Container provides a lot of convenience and basic services for developers to manage the dependency relationship between objects , stay Spring There are many of them IOC The implementation of container is for users to choose and use , The relationship between them is as follows :

among
BeanFactory As an interface class at the top level , It defines the IOC Basic functional specification of the container , BeanFactory There are three subcategories : ListableBeanFactory 、 Hierarc hicalBeanFactory and AutowireCapableBeanFactory .
But from the above figure, we can find that the final default implementation class is DefaultListableBeanFactory , He implements all the interfaces . Then why define so many levels of interfaces ? Check the source code and description of these interfaces and find , Each interface has its own occasion , It is mainly to distinguish between Spring In the process of internal operation, the transfer and transformation of objects , Restrictions on data access to objects . for example ListableBeanFactory Interfaces represent these Bean It is listable , and HierarchicalBeanFactory It means these Bean It's a matter of inheritance , That is, every one of them Bean There may be a father Bean .AutowireCapableBeanFactory Interface definition Bean Automatic assembly rules . These four interfaces define Bean Set 、 Bean The relationship between 、 as well as Bean Behavior is the most basic IOC Container interface BeanFactory

public interface BeanFactory { 
// Yes FactoryBean Definition of escape , Because if you use bean Name search for FactoryBean The resulting object is a factory generated object , 
// If you need to get the factory itself , Need to escape  
String FACTORY_BEAN_PREFIX = "&"; 
// according to bean Name , To get in IOC Get... In the container bean example  
Object getBean(String name) throws BeansException; 
// according to bean And Class Type to get bean example , Added type security verification mechanism . 
<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException; 
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException; 
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException; 
// Provide right bean Search for , See if it's in IOC The container has the name bean 
boolean containsBean(String name); 
// according to bean The name gets bean example , And judge this at the same time bean Is it a single case  
boolean isSingleton(String name) throws NoSuchBeanDefinitionException; 
boolean isPrototype(String name) throws NoSuchBeanDefinitionException; 
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; 
boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException; 
// obtain bean Example of Class type  
@Nullable 
Class<?> getType(String name) throws NoSuchBeanDefinitionException; 
// obtain bean Another name for , If you search by alias , Then its original name will also be retrieved  
String[] getAliases(String name); }

stay BeanFactory It's only for IOC The basic behavior of the container is defined , I don't care about you at all Bean How to define how to load . Just as we only care about what we get in the factory , As for how the factory produces these objects , This basic interface doesn't care .

And you need to know how the factory generates objects , We need to look at specific IOC Container implementation , Spring Offers many IOC Implementation of container . such as XmlBeanFactoryClasspathXmlApplicationContext etc. . among XmlBeanFactory It is aimed at the most basic IOC Implementation of container , This IOC The container can read XML File defined BeanDefinition XML In the document bean Description of ) if XmlBeanFactory It's the cock in the container , ApplicationContext It should be counted as Gao Shuaifu in the container .

ApplicationContext yes Spring An advanced IOC Containers , In addition to providing IOC In addition to the basic functions of the container , The following additional services are also provided for users .

from ApplicationContext Interface implementation , We can see its characteristics :
1. Supporting information sources , Internationalization can be achieved .( Realization MessageSource Interface )
2. Access resources . Realization ResourcePatternResolver Interface , Later chapters will talk about
3. Support application events . Realization ApplicationEventPublisher Interface

7.2 BeanDefinition

SpringIOC Containers manage all kinds of things that we define Bean Objects and their relationships , Bean The object is Spring The realization is based on BeanDef inition To describe the , Under its inheritance system :

Bean The process of parsing is very complicated , The functions are divided in detail , Because there are a lot of things that need to be expanded here , There has to be enough flexibility , In response to possible changes . Bean The main purpose of the analysis is to Spring Profile resolution . This parsing process is mainly completed by the class in the figure below :

 

原网站

版权声明
本文为[Mengqi D Xiaowu]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202130545511408.html