Spring 容器注册组件几种方式

总共有四种

1、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component) --局限于自己写的类
2、@Bean 导入第三方包里的组件
3、@Import 快速给容器中导入一个组件
   1) @Import(要导入到容器中的组件),容器中会自动注册这个组件,id默认是全类名
   2)ImportSelector:返回需要导入的组件的全类名数组
   3) ImportBeanDefinitionRegistrar  手动注册Bean到容器中
4、使用Spring提供的 FactoryBean (工厂Bean)
   1) 默认获取到的是工厂Bean调用getObject创建的对象
   2)要获取工厂bean本身,需要在id前面加个前缀标识 &

1、包扫描+组件标注注解(@Controller @Servuce @Repostiory @Component) --局限自己写的类

1)配置文件的方式
在application.xml中配置,配置包扫描路径

<context:component-scan base-package="com.spring"></context:component-scan>

在 com.spring 包下的并使用 @Controller @Servuce @Repostiory @Component 注解的类会被加载到 spring容器中。
也可以在配置文件中通过 <bean></bean>标签注入,注入方式有set方法注入,构造器注入,如下面的是set方法注入

<bean id="person" class="com.spring.bean.Person">
        <property name="age" value="27"></property>
        <property name="name" value="spring"></property>
</bean>

2)注解方式
首先创建一个配置类(相当于之前的配置文件),并使用
@Configuration 修饰类 让spring容器知道该类是个配置类
@ComponentScan 包扫描 可以配置排除和包含逻辑
①excludeFilters = Filter[] 指定扫描时排除哪些组件
②includeFilters = Filter[] 指定扫描时包含哪些组件,注意这里要让其生效,需要配置 useDefaultFilters = false


@Configuration
@ComponentScan(value = "com.spring",includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = BookService.class),
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})},useDefaultFilters = false)
public class MainConfig {
 
   
}

2.@Bean 导入第三方包里的组件


/**
     * 默认是单实例
     * @Scope
     *  prototype 多实例 ioc容器启动并不会去调用方法创建对象放到容器中,每次获取的时候才会调用方法创建对象
     *  singleton 单实例(默认) ioc容器启动会调用方法创建对象放到ioc容器中,后面的获取,直接从容器中拿
     *
     *  懒加载 单实例bean,容器启动不创建对象,第一次使用(获取)Bean创建对象,并初始化
     *
     * @Conditional 按照一定的条件进行判断,满足条件给容器中注册bean
     *
     * @return
     */
    @Scope("prototype")
    @Lazy
    @Bean("person")
    public Person person() {
        System.out.println("给容器中添加Person...");
        return new Person("张三", 11);
    }
 
 
/**
     * @Conditional 按照一定的条件进行判断,满足条件给容器中注册bean
     *
     * 如果是windows系统,给容器中注册Bill
     * 如果是linux系统,给容器中注册Gates
     *
     */
 
    @Conditional({WindowsConditon.class})
    @Bean("Bill")
    public Person person01() {
        return new Person("Bill Gates", 62);
    }
 
    @Conditional({LinuxConditon.class})
    @Bean("Linux")
    public Person person02() {
        return new Person("Linux", 50);
    }
 
public class LinuxConditon implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        if (property.contains("linux")) {
            return true;
        }
        return false;
    }
}
 
public class WindowsConditon implements Condition {
 
    /**
     * ConditionContext 判断条件能使用的上下文环境
     * AnnotatedTypeMetadata 注释信息
     * @param context
     * @param metadata
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 1.能获取到ioc使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // 2.类加载器
        ClassLoader classLoader = context.getClassLoader();
        // 3.环境信息
        Environment environment = context.getEnvironment();
        // 4.bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();
 
        String property = environment.getProperty("os.name");
        if (property.contains("Windows")) {
            return true;
        }
        return false;
    }
}

3.@Import 快速给容器导入一个组件

1)@Import(要导入到容器中的组件),容器会自动注册该组件,id默认是全类名
2)ImportSelector 返回需要导入的组件的全类名数组
3)ImportBeanDefinitonRegistrar 手动注册bean到容器中

@Configuration
@Import({Color.class,Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig2 {}
 
/**
 *自定义逻辑需要导入的组件
 *
 */
public class MyImportSelector implements ImportSelector {
 
    /**
     * AnnotationMetadata 当前标注@Import注解的类的所有注释信息
     *
     * @param importingClassMetadata
     * @return 返回值就是导入到容器中的组件的全类名
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.spring.bean.Blue", "com.spring.bean.Yellow"};
    }
}
 
 
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     * AnnotationMetadata 当前类的注释信息
     * BeanDefinitionRegistry BeanDefinition注册类
     *      把所有需要添加到容器中的Bean 调用BeanDefinitionRegistry.registerBeanDefiniton手动注册
     *
     * @param importingClassMetadata  当前类的注解信息
     * @param registry  BeanDefinition注册类
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean definition = registry.containsBeanDefinition("com.spring.bean.Red");
        boolean definition2 = registry.containsBeanDefinition("com.spring.bean.Blue");
        if (definition && definition2) {
            // 指定Bean定义信息 Bean的类型,Bean...
            RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
            // 注册一个Bean,指定bean名
            registry.registerBeanDefinition("rainBow", beanDefinition);
        }
    }
}

4.使用spring提供的工厂bean(FactoryBean)

1)默认获取到的是工厂bean 调用 getObject创建的对象
2)要想获取工厂bean本身,需要在id前面加个前缀标识符 &


/**
 * Spring定义的FactoryBean
 *
 */
public class ColorFactoryBean implements FactoryBean<Color> {
 
    /**
     * 返回一个Color对象,将对象添加到容器中
     *
     * @return
     * @throws Exception
     */
    @Override
    public Color getObject() throws Exception {
        System.out.println("ColorFactoryBean ... getObject...");
        return new Color();
    }
 
    @Override
    public Class<?> getObjectType() {
        return null;
    }
 
    /**
     * 是单例?
     * true 单例,在容器中存储一个
     * false 多实例,每次获取都会创建一个bean
     *
     * @return
     */
    @Override
    public boolean isSingleton() {
        return false;
    }
}
 
public class IOCTest {
 
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
 
    @Test
    public void testImport() {
        printBeans(context);
 
        // 工厂Bean获取的是调用getObject创建的对象
        Object bean = context.getBean("colorFactoryBean");
        Object bean2 = context.getBean("colorFactoryBean");
        System.out.println("bean的类型:" + bean.getClass());
        System.out.println(bean == bean2);
 
        Object bean3 = context.getBean("&colorFactoryBean");
        System.out.println(bean3.getClass());
    }
}

输出结果:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
com.spring.bean.Color
com.spring.bean.Red
com.spring.bean.Blue
com.spring.bean.Yellow
person
Bill
colorFactoryBean
rainBow
ColorFactoryBean ... getObject...
ColorFactoryBean ... getObject...
bean的类型:class com.spring.bean.Color
false
class com.spring.bean.ColorFactoryBean
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容