首页 > 编程语言 > 详细

Spring(1) 之 容器及实例化

时间:2021-07-10 21:57:35      阅读:21      评论:0      收藏:0      [点我收藏+]

Spring 之 容器及实例化

1 spring容器

The org.springframework.context.ApplicationContext interface represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans.

翻译

  • Spring IOC容器就是一个org.springframework.context.ApplicationContext的实例化对象
  • 这个容器负责实例化配置以及装配一个bean

从代码层次来看:Spring容器就是一个实现了ApplicationContext接口的对象;

从功能上来看: Spring 容器是 Spring 框架的核心,是用来管理Spring bean的。容器将创建对象,把它们连接在一起配置它们,并管理他们的整个生命周期从创建到销毁。

技术分享图片

Spring容器通过我们提交的pojo类以及配置元数据产生一个充分配置的可以使用的系统

这里说的配置元数据,实际上我们就是我们提供的XML配置文件,或者通过注解方式提供的一些配置信息

2 Spring实例化

这里的Spring实例化是指根据每个java类文件所生成的对应的BeanDefinition完成java bean的创建过程,这里的java bean是一个半成品,不能当作spring bean进行使用。

官网 1.3.2. Instantiating Beans

  • Instantiation with a Constructor (通过使用java类的构造器进行实例化)
  • Instantiation with a Static Factory Method(通过静态工厂方法进行实例化)
  • Instantiation by Using an Instance Factory Method(通过实例工厂方法进行实例化)

2.1 Spring进行实例化所在的类和方法

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

技术分享图片

2.2 实例化方法源码分析

 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
     
     // 1 获取要实例化的这个bean的class属性,确保beanDefinition中的beanClass属性已经完成解析
        Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
     
     // 对这个beanClass进行异常判断(跳过)
        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());
        } 
     
     	else {
            // 2 使用beanDefinition中的supplier实例化这个bean(基本不使用)
            Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
            if (instanceSupplier != null) {
                return this.obtainFromSupplier(instanceSupplier, beanName);
            } 
            
            // 3 使用工厂方法(可能是静态工厂,也可能是实例工厂)实例化这个bean
            else if (mbd.getFactoryMethodName() != null) {
                return this.instantiateUsingFactoryMethod(beanName, mbd, args);
            } 
            
            // 4 通过构造函数实例化这个bean
            else {
                // 有参无参标识位
                boolean resolved = false;
                boolean autowireNecessary = false;
                if (args == null) {
                    synchronized(mbd.constructorArgumentLock) {
                        if (mbd.resolvedConstructorOrFactoryMethod != null) {
                            resolved = true;
                            autowireNecessary = mbd.constructorArgumentsResolved;
                        }
                    }
                }

                // false,无参,使用无参构造器
                if (resolved) {
                    return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd);
                } 
                
                // true,有参,使用InstantiationAwareBeanPostProcessor#determineConstructorsFromBeanPostProcessors选择合适的有参构造器
                else {
                    Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);
                    if (ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args)) {
                        ctors = mbd.getPreferredConstructors();
                        return ctors != null ? this.autowireConstructor(beanName, mbd, ctors, (Object[])null) : this.instantiateBean(beanName, mbd);
                    } else {
                        return this.autowireConstructor(beanName, mbd, ctors, args);
                    }
                }
            }
        }
    }

2.3 实例化过程验证

2.3.1 @compent,@Service,@Configuration、@Bean等注解的类进行实例化

@Configuration
@ComponentScan("pojo")
public class Config {
}
@Data
@Component
public class User {
    int id;
    String name;
}
public class ComponentMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
        User user = applicationContext.getBean(User.class);
        System.out.println(user);
    }
}

debug:

return ctors != null ? this.autowireConstructor(beanName, mbd, ctors, (Object[])null) : this.instantiateBean(beanName, mbd);   // ctors == null

可以发现,代码执行的最后一行,当没有进行特殊的处理的时候,默认会使用无参构造函数进行对象的实例化

2.3.2 默认xml文件进行实例化

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user" class="pojo.User">
        <property name="id" value="28"></property>
        <property name="name" value="mjoe"></property>
    </bean>
</beans>
@Data
@Component
public class User {
    int id;
    String name;
}
public class SpringMain {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        User user = (User) context.getBean("user");
        System.out.println(user);
    }
}

打断点:

技术分享图片

debug:

技术分享图片

可以发现,beanName已经是xml文件中定义的id,此时ctors==null,将使用this.instantiateBean(beanName, mbd)调用无参构造函数进行实例化。

2.3.3 通过静态工厂进行实例化

public class MyUserFactory {
    public static User getUser(){
        User user = new User();
        return user;
    }
}
@Data
public class User {
    int id;
    String name;
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
<!--    通过静态工厂方法创建对象-->
    <bean id="factoryUser" class="factory.MyUserFactory" factory-method="getUser"></bean>

</beans>
public class SpringMain {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        User factoryUser = (User) context.getBean("factoryUser");
        System.out.println(factoryUser);
    }
}

debug:

技术分享图片

可以发现,Spring底层是通过factoryMethod的方法进行实例化对象的。Spring会在我们需要实例化的这个对象对应的BeanDefinition中记录factoryBeanName是什么(MyUserFactory),同时会记录这个factoryBean中创建对象的factoryMethodName是什么(getUser()),最后通过factoryBeanName获取一个Bean然后反射调用factoryMethod实例化一个对象(User)

这里所说的通过静态工厂方式通过factoryBeanName获取一个Bean,注意,这个Bean,不是一个FactoryBean。也就是说不是一个实现了org.springframework.beans.factory.FactoryBean接口的Bean

通过静态工厂方法这种方式特殊之处在于:包含这个静态方法的类(MyUserFactory)不需要实例化,不需要被Spring管理。Spring的调用逻辑大概是:

  • 通过标签中的class属性得到一个Class对象
  • 通过Class对象获取到对应的方法名称的Method对象
  • 最后反射调用Method.invoke(null,args)
  • 因为是静态方法,方法在执行时,不需要一个对象。

2.3.4 通过实例工厂方法进行实例化

public class MyUserFactory {
    public static User getUser(){
        User user = new User();
        return user;
    }

    public User get(){
        User user = new User();
        user.setName("mjoeboyae");
        return user;
    }
}
@Data
public class User {
    int id;
    String name;
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myFactoryBean" class="factory.MyUserFactory"></bean>
<!--    通过实例工厂方法创建对象-->
    <bean id="user" factory-bean="myFactoryBean" factory-method="get"></bean>

</beans>
public class SpringMain {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        User user = (User) context.getBean("user");
        System.out.println(user);
    }
}

debug:

技术分享图片

经过默认构造器。

3 总结

技术分享图片

Spring(1) 之 容器及实例化

原文:https://www.cnblogs.com/mjoe/p/14994436.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!