Spring 加载Bean的方式(8种)

  关于bean的加载方式,spring提供了各种各样的形式。因为spring管理bean整体上来说就是由spring维护对象的生命周期,所以bean的加载可以从大的方面划分成2种形式。已知类并交给spring管理,和已知类名并交给spring管理。有什么区别?一个给.class,一个给类名字符串。内部其实都一样,都是通过spring的BeanDefinition对象初始化spring的bean。如果前面这句话看起来有障碍,可以去复习一下spring的相关知识。

总的来说,梳理归纳,Spring有如下8中加载bean的方式

1. xml + <bean/>
2. xml:context + 注解(@Component+4个@Bean)
3. 配置类+扫描 + 注解(@Component+4个@Bean),这里也包括用@ImportResource 导入xml配置的bean 
4. @Import导入bean的类  @Import导入配置类
5. AnnotationConfigApplicationContext调用register方法
6. @Import导入ImportSelector接口
7. @Import导入ImportBeanDefinitionRegistrar接口
8. @Import导入BeanDefinitionRegistryPostProcessor接口

 下面详细展开详细的分享。

方式一:配置文件+<bean/>标签

(1)普通的java类文件

package com.hao.bean;

public class Dog {
}

 

package com.hao.bean;

public class Cat {
    public Cat(){
    }

    int age;
    public Cat(int age){
        this.age = age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "age=" + age +
                '}';
    }
}

 

(2)xml配置文件(<bean>标签配置定义bean)

applicationCOntext1.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">
    <!--xml方式声明自己开发的bean-->
    <bean id="cat" class="com.hao.bean.Cat"/>
    <bean class="com.hao.bean.Dog"/>

    <!--xml方式声明第三方开发的bean-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"/>
    <bean class="com.alibaba.druid.pool.DruidDataSource"/>
    <bean class="com.alibaba.druid.pool.DruidDataSource"/>
</beans>

 

(3)测试Spring加载结果

  1)加载代码

package com.hao.app;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App1 {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationCOntext1.xml");
//        Object cat = ctx.getBean("cat");
//        System.out.println(cat);
//        Dog dog = ctx.getBean(Dog.class);
//        System.out.println(dog);
        String[] names = ctx.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

  2)运行结果

 

方式二:配置文件扫描+注解定义bean

  由于方式一种需要将spring管控的bean全部写在xml文件中,对于程序员来说非常不友好,所以就有了第二种方式。哪一个类要受到spring管控加载成bean,就在这个类的上面加一个注解,还可以顺带起一个bean的名字(id)。这里可以使用的注解有@Component以及三个衍生注解@Service、@Controller、@Repository。
 (1)java类文件

       方式1:使用@Component及其衍生注解@Controller 、@Service、@Repository定义bean

package com.hao.bean;

import org.springframework.stereotype.Component;

@Component("tom")
public class Cat {
    public Cat(){
    }

    int age;
    public Cat(int age){
        this.age = age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "age=" + age +
                '}';
    }
}

 

package com.hao.bean;

import org.springframework.stereotype.Service;

@Service("jerry")
public class Mouse {
}

 

  当然,由于我们无法在第三方提供的技术源代码中去添加上述4个注解,因此当你需要加载第三方开发的bean的时候可以使用下列方式定义注解式的bean。
      @Bean定义在一个方法上方,当前方法的返回值就可以交给spring管控,记得这个方法所在的类一定要定义在@Component修饰的类中,有人会说不是@Configuration吗?建议把spring注解开发相关课程学习一下,就不会有这个疑问了。

        方式2:使用@Bean定义第三方bean,并将所在类定义为配置类或Bean

package com.hao.config;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import com.alibaba.druid.pool.DruidDataSource;

@Component
// @Component和@Configuration 均可以,但是企业级应用中推荐使用@Configuration,可以明确为配置类
public class DbConfig { @Bean public DruidDataSource dataSource(){ DruidDataSource ds = new DruidDataSource(); return ds; } }

 

  上面提供的仅仅是bean的声明,spring并没有感知到这些东西,像极了上课积极回答问题的你,手举的非常高,可惜老师都没有往你的方向看上一眼。想让spring感知到这些积极的小伙伴,必须设置spring去检查这些类,看他们是否贴标签,想当积极分子。可以通过下列xml配置设置spring去检查哪些包,发现定了对应注解,就将对应的类纳入spring管控范围,声明成bean。 

(2)xml配置文件(context:component-scan 指定spring扫描并注册组件的位置)

applicationCOntext2.xml
<?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
    ">

    <!--指定加载bean的位置,component-->
    <context:component-scan base-package="com.hao.bean,com.hao.config"/>
</beans>

 

  方式二声明bean的方式是目前企业中较为常见的bean的声明方式,但是也有缺点。方式一中,通过一个配置文件,你可以查阅当前spring环境中定义了多少个或者说多少种bean,但是方式二没有任何一个地方可以查阅整体信息,只有当程序运行起来才能感知到加载了多少个bean。

(3)测试Spring加载结果

  1)加载代码

package com.hao.app;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App2 {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationCOntext2.xml");
        String[] names = ctx.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

 

  2)运行结果

 

方式三:注解方式声明配置类

  方式二已经完美的简化了bean的声明,以后再也不用写茫茫多的配置信息了。仔细观察xml配置文件,会发现这个文件中只剩了扫描包这句话,于是就有人提出,使用java类替换掉这种固定格式的配置,所以下面这种格式就出现了。严格意义上讲不能算全新的方式,但是由于此种开发形式是企业级开发中的主流形式,所以单独独立出来做成一种方式。 

  定义一个类并使用@ComponentScan替代原始xml配置中的包扫描这个动作,其实功能基本相同。为什么说基本,还是有差别的。
 (1)注解配置类

package com.hao.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;

import com.alibaba.druid.pool.DruidDataSource;

// @Configuration 配置项如果不用于被扫描可以省略 @ComponentScan({
"com.hao.bean","com.hao.config"}) public class SpringConfig3 { @Bean public DruidDataSource dataSource(){ DruidDataSource ds = new DruidDataSource(); return ds; } }

  注意: SpringConfig3上面的@Configuration 可写可不写。但是记得,如果用AnnotationConfigApplicationContext对象加载这个类,那@Configuration可以不写;但是如果不是加载,而是被别人加载,那一定要加上@Configuration,否则它就不是配置类,不会生效了。

  但是一般企业级中,像 SpringConfig3 是一个总配置类,总配置类中只需要做一些最基础、最顶层的设计工作就可以了。  @Bean 定义的类应该被单独放到一个@Configuration配置类中。

(2)测试Spring加载结果

  1)加载代码

package com.hao.app;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.hao.config.SpringConfig3;

public class App3 {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig3.class);
        String[] names = ctx.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

    }
}

 

  2)运行结果

 

注:注解格式导入XML格式配置的bean

  再补充一个小知识,由于早起开发的系统大部分都是采用xml的形式配置bean,现在的企业级开发基本上不用这种模式了。但是如果你特别幸运,需要基于之前的系统进行二次开发,这就尴尬了。新开发的用注解格式,之前开发的是xml格式。这个时候可不是让你选择用哪种模式的,而是两种要同时使用。spring提供了一个注解可以解决这个问题,@ImportResource,在配置类上直接写上要被融合的xml配置文件名即可,算的上一种兼容性解决方案,没啥实际意义。

(1)注解配置类

package com.hao.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.stereotype.Component;

@Configuration
@ImportResource("applicationContext1.xml")
public class SpringConfig32 {
}

 

(2)测试Spring加载结果

  1)加载代码

 

package com.hao.app;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.hao.config.SpringConfig3;

public class App3 {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig3.class);
        String[] names = ctx.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

    }
}

 

  2)运行结果

 

方式四:使用@Import注解注入bean

使用扫描的方式加载bean是企业级开发中常见的bean的加载方式,但是由于扫描的时候不仅可以加载到你要的东西,还有可能加载到各种各样的乱七八糟的东西,万一没有控制好得不偿失了。

有人就会奇怪,会有什么问题呢?比如你扫描了com.hao.service包,后来因为业务需要,又扫描了com.hao.dao包,你发现com.hao包下面只有service和dao这两个包,这就简单了,直接扫描com.hao就行了。但是万万没想到,十天后你加入了一个外部依赖包,里面也有com.itheima包,这下就热闹了,该来的不该来的全来了。

所以我们需要一种精准制导的加载方式,使用@Import注解就可以解决你的问题。它可以加载所有的一切,只需要在注解的参数中写上加载的类对应的.class即可。有人就会觉得,还要自己手写,多麻烦,不如扫描好用。对呀,但是他可以指定加载啊,好的命名规范配合@ComponentScan可以解决很多问题,但是@Import注解拥有其重要的应用场景。有没有想过假如你要加载的bean没有使用@Component修饰呢?这下就无解了,而@Import就无需考虑这个问题。

 

被@Import进的bean的名字,是全路径类名。


 (1)注解配置类

package com.hao.bean;

public class Dog {
}

 

package com.hao.config;

import org.springframework.context.annotation.Import;

import com.hao.bean.Dog;

@Import({Dog.class})
// 被导入的为普通的Class就行,无需使用注解声明为bean
public class SpringConfig4 { }

 

此种方式的优势:1)此形式可以有效的降低源代码与Spring技术的耦合度,在spring技术底层及诸多框架的整合中大量使用。  2)使用别人的第三方代码时,除了@Bean, 还可以直接@Import,然后按类型get就行。

 

(2)测试Spring加载结果

  1)加载代码

package com.itheima.app;

import com.itheima.config.SpringConfig4;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App4 {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig4.class);
        String[] names = ctx.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        System.out.println("----------------------");
    }
}

 

 

  2)运行结果

 

 

注:注解格式导入注解配置bean

  除了加载bean,还可以使用@Import注解加载配置类。其实本质上是一样的。  但是注意,这种@Import方式加载进spring的配置Bean的名字(全路径类名)和前面扫描加载进spring的配置bean的名字(类名小写)不同,具体可见方式二中和本方式的测试代码的运行效果。

(1)注解配置类

package com.hao.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration
// 实际山,当被使用@Import 方式导入时, 无论 @Configuration 注解是否有,都可以将 DbConfig和dataSource 加载到Spring容器中
public class DbConfig {
    @Bean
    public DruidDataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        return ds;
    }

}

 

package com.hao.config;

import org.springframework.context.annotation.Import;

import com.hao.bean.Dog;

@Import({Dog.class,DbConfig.class})
public class SpringConfig4 {

}

 

 

(2)测试Spring加载结果

  1)加载代码

 

package com.hao.app;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.hao.config.SpringConfig3;

public class App3 {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig3.class);
        String[] names = ctx.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

    }
}

 

  2)运行结果

 

方式五:编程形式注册bean

前面介绍的加载bean的方式都是在容器启动阶段完成bean的加载,下面这种方式就比较特殊了,可以在容器初始化完成后手动加载bean。通过这种方式可以实现编程式控制bean的加载。这种方式平时应用开发中不常用,但是在框架开发中会使用。


 (1)注解配置类

package com.hao.bean;


public class Cat {
    public Cat(){
    }

    int age;
    public Cat(int age){
        this.age = age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "age=" + age +
                '}';
    }
}

 

package com.hao.bean;

public class Mouse {
}

 

package com.hao.app;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.hao.config.SpringConfig4;

public class App5 {
    public static void main(String[] args) {
        // ApplicationContext对象做不了,只能用AnnotationConfigApplicationContext对象
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig4.class);
        //上下文容器对象已经初始化完毕后,手工加载bean
        ctx.registerBean("tom", Cat.class,0);
        ......
        ctx.register(Mouse.class);
......
} }

 

(2)测试Spring加载结果

  1)加载代码

package com.hao.app;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.hao.bean.Cat;
import com.hao.bean.Mouse;
import com.hao.config.SpringConfig4;

public class App5 {
    public static void main(String[] args) {
        // ApplicationContext对象做不了,只能用AnnotationConfigApplicationContext对象
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig4.class);
        //上下文容器对象已经初始化完毕后,手工加载bean
        ctx.registerBean("tom", Cat.class,0);
        ctx.registerBean("tom", Cat.class,1);
        ctx.registerBean("tom", Cat.class,2);
        ctx.register(Mouse.class);
        String[] names = ctx.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        System.out.println("----------------------");
        System.out.println(ctx.getBean(Cat.class));
    }
}

 

  2)运行结果

 

方式六:导入实现了ImportSelector接口的类

在方式五种,我们感受了bean的加载可以进行编程化的控制,添加if语句就可以实现bean的加载控制了。但是毕竟是在容器初始化后实现bean的加载控制,那是否可以在容器初始化过程中进行控制呢?答案是必须的。实现ImportSelector接口的类可以设置加载的bean的全路径类名,记得一点,只要能编程就能判定,能判定意味着可以控制程序的运行走向,进而控制一切。

现在又多了一种控制bean加载的方式,或者说是选择bean的方式。

在Spring源码中大量使用,通过导入实现了ImportSelector接口的类,实现对导入源的编程式处理

 (1)注解配置类

package com.hao.bean;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
//        System.out.println("================");
//        System.out.println("提示:"+metadata.getClassName());
//        System.out.println(metadata.hasAnnotation("org.springframework.context.annotation.Configuration"));
//        Map<String, Object> attributes = metadata.getAnnotationAttributes("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.hao.bean.Dog"};
        }
        return new String[]{"com.hao.bean.Cat"};
    }
}

 

package com.hao.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import com.hao.bean.MyImportSelector;

@Configuration
//@ComponentScan(basePackages = "com.hao")
@Import(MyImportSelector.class)
public class SpringConfig6 {
}

(2)测试Spring加载结果

  1)加载代码

package com.hao.app;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.hao.config.SpringConfig6;

public class App6 {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig6.class);
        String[] names = ctx.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        System.out.println("----------------------");
    }
}

 

      2)运行结果

 

 

 

方式七:导入实现了ImportBeanDefinitionRegistrar接口的类

方式六中提供了给定类全路径类名控制bean加载的形式,如果对spring的bean的加载原理比较熟悉的小伙伴知道,其实bean的加载不是一个简简单单的对象,spring中定义了一个叫做BeanDefinition的东西,它才是控制bean初始化加载的核心。BeanDefinition接口中给出了若干种方法,可以控制bean的相关属性。说个最简单的,创建的对象是单例还是非单例,在BeanDefinition中定义了scope属性就可以控制这个。如果你感觉方式六没有给你开放出足够的对bean的控制操作,那么方式七你值得拥有。我们可以通过定义一个类,然后实现ImportBeanDefinitionRegistrar接口的方式定义bean,并且还可以让你对bean的初始化进行更加细粒度的控制,不过对于新手并不是很友好。忽然给你开放了若干个操作,还真不知道如何下手。

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

 (1)注解配置类

package com.hao.bean;

import com.hao.bean.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 implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //1.使用元数据去做判定

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

 

package com.hao.config;

import com.hao.bean.MyRegistrar;
import org.springframework.context.annotation.Import;

@Import(MyRegistrar.class)
public class SpringConfig7 {
}

 

 

(2)测试Spring加载结果

  1)加载代码

package com.hao.app;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.hao.config.SpringConfig7;

public class App7 {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig7.class);
        String[] names = ctx.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        System.out.println("----------------------");
    }
}

 

     2)运行结果

 

 

方式八:导入实现了BeanDefinitionRegistryPostProcessor接口的类

上述七种方式都是在容器初始化过程中进行bean的加载或者声明,但是这里有一个bug。这么多种方式,它们之间如果有冲突怎么办?谁能有最终裁定权?这是个好问题,当某种类型的bean被接二连三的使用各种方式加载后,在你对所有加载方式的加载顺序没有完全理解清晰之前,你还真不知道最后谁说了算。即便你理清楚了,保不齐和你一起开发的猪队友又添加了一个bean,得嘞,这下就热闹了。

spring挥舞它仲裁者的大刀来了一个致命一击,都别哔哔了,我说了算,BeanDefinitionRegistryPostProcessor,看名字知道,BeanDefinition意思是bean定义,Registry注册的意思,Post后置,Processor处理器,全称bean定义后处理器,干啥的?在所有bean注册都折腾完后,它把最后一道关,说白了,它说了算,这下消停了,它是最后一个运行的。

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

 

(1)

package com.hao.bean.service;

public interface BookSerivce {
    void check();
}

 

package com.hao.bean.service.impl;

import com.hao.bean.service.BookSerivce;
import org.springframework.stereotype.Service;

@Service("bookService")
public class BookServiceImpl1 implements BookSerivce {
    @Override
    public void check() {
        System.out.println("book service 1..");
    }
}

 

package com.hao.bean.service.impl;

import com.hao.bean.service.BookSerivce;

public class BookServiceImpl2 implements BookSerivce {
    @Override
    public void check() {
        System.out.println("book service 2....");
    }
}

 

package com.hao.bean.service.impl;

import com.hao.bean.service.BookSerivce;

public class BookServiceImpl3 implements BookSerivce {
    @Override
    public void check() {
        System.out.println("book service 3......");
    }
}

......

package com.hao.bean;

import com.hao.bean.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 MyRegistrar2 implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //1.使用元数据去做判定

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

 

package com.hao.bean;

import com.hao.bean.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 beanFactory) throws BeansException {

    }
}

 

package com.hao.config;

import org.springframework.context.annotation.Import;

import com.hao.bean.MyPostProcessor;
import com.hao.bean.MyRegistrar;
import com.hao.bean.MyRegistrar2;
import com.hao.bean.service.impl.BookServiceImpl1;

@Import({BookServiceImpl1.class, MyPostProcessor.class, MyRegistrar2.class, MyRegistrar.class})
public class SpringConfig8 {
}

 

(2)测试Spring加载结果

  1)加载代码

package com.hao.app;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.hao.bean.service.BookSerivce;
import com.hao.config.SpringConfig8;

public class App8 {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig8.class);
        BookSerivce bookService = ctx.getBean("bookService", BookSerivce.class);
        bookService.check();
    }
}

 

      2)运行结果

 

 

附注:以下讲解使用到的demo代码结构

 

总结

  1. bean的定义由前期xml配置逐步演化成注解配置,本质是一样的,都是通过反射机制加载类名后创建对象,对象就是spring管控的bean

  2. @Import注解可以指定加载某一个类作为spring管控的bean,如果被加载的类中还具有@Bean相关的定义,会被一同加载

  3. spring开放出了若干种可编程控制的bean的初始化方式,通过分支语句由固定的加载bean转成了可以选择bean是否加载或者选择加载哪一种bean

 

 

posted on 2022-07-30 18:53  郝志锋  阅读(4726)  评论(0编辑  收藏  举报