一、XML方式声明bean

配置文件

1.在xml中声明自定义的bean

<?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">

    <!--xml方式声明自定义的bean-->
    <bean id="cat" class="com.huangzx.bean.Cat"></bean>  <!--命名id-->
    <bean class="com.huangzx.bean.Dog"></bean>  <!--未命名id-->
    <bean class="com.huangzx.bean.Dog"></bean>
    <bean class="com.huangzx.bean.Dog"></bean>

指定bean输出 

Spring bean加载机制 spring中bean的加载_java

 输出所有的bean

Spring bean加载机制 spring中bean的加载_xml_02

输出自定义bean结果

Spring bean加载机制 spring中bean的加载_加载_03

 

2.在xml中声明第三方bean

# 首先在pom.xml中导入第三方bean坐标
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.9</version>
</dependency>
<!--在配置文件中  xml方式声明第三方bean-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"></bean>
    <bean class="com.alibaba.druid.pool.DruidDataSource"></bean>
    <bean class="com.alibaba.druid.pool.DruidDataSource"></bean>

输出所有bean结果 

Spring bean加载机制 spring中bean的加载_加载_04

 

 二、XML+注解方式声明bean

进行包扫描,查找需要加载的bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--xml方式声明自己开发的bean-->
    <!--指定加载bean的位置,component-->
    <context:component-scan base-package="com.huangzx.bean,com.huangzx.config"></context:component-scan>


</beans>

 对需要加载的bean进行注解,使用@Component及其衍生注解@Controller 、@Service、@Repository,@Configuration定义bean

 

Spring bean加载机制 spring中bean的加载_xml_05

Spring bean加载机制 spring中bean的加载_spring_06

Spring bean加载机制 spring中bean的加载_加载_07

 

Spring bean加载机制 spring中bean的加载_java_08

三、注解方式声明配置类

 

Spring bean加载机制 spring中bean的加载_加载_09

 @Configuration配置项如果不用于被扫描可以省略

这里使用的是AnnotationConfigApplicationContext加载配置 

Spring bean加载机制 spring中bean的加载_加载_10

1.拓展1 初始化实现FactoryBean接口的类,实现对bean加载到容器之前的批处理操作

 

Spring bean加载机制 spring中bean的加载_spring_11

使用@ComponentScan进行包扫描加载配置bean 

 

Spring bean加载机制 spring中bean的加载_Spring bean加载机制_12

输出返回的bean不是DogFactoryBean,而是dog 

 输出加载bean结果

Spring bean加载机制 spring中bean的加载_xml_13

 重写FactoryBean<>中的isSingleleton方法,返回false,所以生成的对象非单例

Spring bean加载机制 spring中bean的加载_xml_14

 2.扩展2  加载配置类并加载配置文件

 用于使用注解加载bean时,如何加载之前使用xml文件配置的bean

使用@ImportResource加载xml配置文件

Spring bean加载机制 spring中bean的加载_java_15

 

Spring bean加载机制 spring中bean的加载_java_16

 3.扩展3 proxyBeanMethods

使用proxyBeanMethods=true可以保障调用此方法得到的对象是从容器中获取的而不是重新创建的 

Spring bean加载机制 spring中bean的加载_Spring bean加载机制_17

Spring bean加载机制 spring中bean的加载_java_18

 当proxyBeanMethods=false时输出结果 

Spring bean加载机制 spring中bean的加载_xml_19

Spring bean加载机制 spring中bean的加载_xml_20

 

  当proxyBeanMethods=true时输出结果。proxyBeanMethodtrue

Spring bean加载机制 spring中bean的加载_xml_21

 

 四、使用@Import注解导入要注入的bean

被导入的bean无需使用注解声明为bean

此形式可以有效的降低源代码与Spring技术的耦合度,在spring技术底层及诸多框架的整合中大量使用

 

Spring bean加载机制 spring中bean的加载_加载_22

Spring bean加载机制 spring中bean的加载_xml_23

 输出bean的全路径类名

Spring bean加载机制 spring中bean的加载_Spring bean加载机制_24

 扩展  使用@Import注解导入其他配置类,配置类无需使用注解,也可加载出来

Spring bean加载机制 spring中bean的加载_加载_25

 

Spring bean加载机制 spring中bean的加载_xml_26

 五、使用上下文对象在容器初始化完毕后注入bean

使用 AnnotationConfigApplicationContext,在上下文对象初始化完毕后,手工加载bean

Spring bean加载机制 spring中bean的加载_spring_27

输出结果,相同的bean,后面的会把前面的覆盖

Spring bean加载机制 spring中bean的加载_Spring bean加载机制_28

 

六、@Import导入ImportSelector接口

Spring bean加载机制 spring中bean的加载_xml_29

Spring bean加载机制 spring中bean的加载_spring_30

 

 结果

Spring bean加载机制 spring中bean的加载_spring_31

 在某类上@Import导入ImportSelector配置类,可以检查该类的某些属性

Spring bean加载机制 spring中bean的加载_加载_32

 

package com.huangzx.bean;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.MultiValueMap;

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata Metadata) {
        System.out.println("--------------------------");
        //检查加载该配置的类
        System.out.println(Metadata.getClassName());
        //检测加载该配置的类是否有注解@Configuration
        System.out.println(Metadata.hasAnnotation("org.springframework.context.annotation.Configuration"));
        //检查加载该配置的类是否有@ComponentScan属性
        MultiValueMap<String, Object> attributes = Metadata.getAllAnnotationAttributes("org.springframework.context.annotation.ComponentScan");
        System.out.println(attributes);
        System.out.println("--------------------------");

        //完成条件检查后,加载指定的bean
        boolean flag = Metadata.hasAnnotation("org.springframework.context.annotation.Configuration");
        if(flag){
            return new String[] {"com.huangzx.bean.Dog"};
        }
        return new String[] {"com.huangzx.bean.Cat"};
    }
}

 结果

--------------------------
com.huangzx.config.SpringConfig6
true
{basePackageClasses=[[Ljava.lang.Class;@53f65459], basePackages=[[Ljava.lang.String;@3b088d51], excludeFilters=[[Ljava.util.LinkedHashMap;@1786dec2], includeFilters=[[Ljava.util.LinkedHashMap;@74650e52], lazyInit=[false], nameGenerator=[interface org.springframework.beans.factory.support.BeanNameGenerator], resourcePattern=[**/*.class], scopeResolver=[class org.springframework.context.annotation.AnnotationScopeMetadataResolver], scopedProxy=[DEFAULT], useDefaultFilters=[true], value=[[Ljava.lang.String;@15d0c81b]}
--------------------------
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
springConfig6
com.huangzx.bean.Dog

Process finished with exit code 0

七、@Import导入ImportBeanDefinitionRegistrar接口

 导入实现了ImportBeanDefinitionRegistrar接口的类,通过BeanDefinition的注册器注册实名bean,实现对容器中bean的裁定,例如对现有bean的覆盖,进而达成不修改源代码的情况下更换实现的效果

package com.huangzx.bean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        //首先使用元数据做判定,然后再导入需要的bean
        BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Dog.class).getBeanDefinition();
        registry.registerBeanDefinition("yyf",beanDefinition);
    }
}

 

Spring bean加载机制 spring中bean的加载_xml_33

结果

Spring bean加载机制 spring中bean的加载_加载_34

 

 八、@Import导入BeanDefinitionRegistryPostProcessor接口

 导入实现了BeanDefinitionRegistryPostProcessor接口的类,通过BeanDefinition的注册器注册实名bean, 实现对容器中bean的最终裁定

Service接口:BookService

Service实现:BookServiceImpl1、BookServiceImpl2、BookServiceImpl3、BookServiceImpl4

Spring bean加载机制 spring中bean的加载_spring_35

 1.@Import导入BookServiceImpl1.class

Spring bean加载机制 spring中bean的加载_xml_36

结果

 

Spring bean加载机制 spring中bean的加载_spring_37

 2.创建配置类定义bean BookServiceImpl2,并导入该类

package com.huangzx.bean;
import com.huangzx.service.impl.BookServiceImpl2;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyRegistrar_PostProcessor1 implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl2.class).getBeanDefinition();
        registry.registerBeanDefinition("bookService",beanDefinition);
    }
}

 

Spring bean加载机制 spring中bean的加载_spring_38

 结果

Spring bean加载机制 spring中bean的加载_xml_39

 3.创建配置类定义bean BookServiceImpl3,并导入该类

package com.huangzx.bean;
import com.huangzx.service.impl.BookServiceImpl3;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyRegistrar_PostProcessor2 implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl3.class).getBeanDefinition();
        registry.registerBeanDefinition("bookService",beanDefinition);
    }
}

Spring bean加载机制 spring中bean的加载_spring_40

 结果        MyRegistrar_PostProcessor1和MyRegistrar_PostProcessor2的导入顺序,决定了执行这两个中的哪个实现类,后导入的会覆盖之前导入的

Spring bean加载机制 spring中bean的加载_spring_41

4.定义后配置类MyPostProcessor,并定义bean  BookServiceImpl4

package com.huangzx.bean;

import com.huangzx.service.impl.BookServiceImpl4;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;

public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl4.class).getBeanDefinition();
        registry.registerBeanDefinition("bookService",beanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}

 @Import导入MyPostProcessor

package com.huangzx.config;
import com.huangzx.bean.MyPostProcessor;
import com.huangzx.bean.MyRegistrar_PostProcessor1;
import com.huangzx.bean.MyRegistrar_PostProcessor2;
import com.huangzx.service.impl.BookServiceImpl1;
import org.springframework.context.annotation.Import;

@Import({BookServiceImpl1.class, MyRegistrar_PostProcessor1.class, MyRegistrar_PostProcessor2.class, MyPostProcessor.class})
public class SpringConfig8 {

}

结果      执行BookServiceImpl4  与是否最后导入无关

Spring bean加载机制 spring中bean的加载_spring_42

 

 

能够选择性加载控制bean的方式是:

AnnotationConfigApplicationContext调用register方法 

@Import导入ImportSelector接口 

@Import导入ImportBeanDefinitionRegistrar接口 

@Import导入BeanDefinitionRegistryPostProcessor接口 

以ImportSelector为例

1.根据任意条件确认是否加载bean

Spring bean加载机制 spring中bean的加载_java_43

2. 使用@Conditional注解的派生注解设置各种组合条件控制bean的加载

          使用@ConditionalOn***注解为bean的加载设置条件

package com.huangzx.config;
import com.huangzx.bean.Cat;
import com.huangzx.bean.Mouse;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

//@Import(MyImportSelector.class)
@Import(Mouse.class)
public class SpringConfig {

    @Bean
    //@ConditionalOnClass(Mouse.class)  一般不使用这种方式
    //@ConditionalOnClass(name = "com.huangzx.bean.Mouse") //有Mouse时加载
    //@ConditionalOnMissingClass("com.huangzx.bean.Wolf")  //没有Wolf时加载

    @ConditionalOnBean(name = "jerry")  //有Mouse  bean,且Mouse的名字是jerry时加载
    @ConditionalOnMissingClass("com.huangzx.bean.Dog") //有Mouse  bean,且Mouse的名字是jerry时加载,且没有Dog时加载

    @ConditionalOnWebApplication //是web程序时加载
    public Cat tom(){
        return new Cat();
    }
}

3. 指定类上根据条件选择性加载

Spring bean加载机制 spring中bean的加载_xml_44

 后续可以单独配置bean,当有某种环境时,加载某些bean

这里当有mysql数据库连接时,加载Druid数据源

public class SpringConfig {
    @Bean
    @ConditionalOnClass(name = "com.mysql.jdbc.Driver")
    public DruidDataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        return ds;
    }
}