spring注解方式向IOC容器中注册组件

本文详细介绍了Spring框架中如何通过@Bean、包扫描、@Import及自定义导入策略来注册和获取组件,包括工厂bean和定制化注册方式,以提升开发效率和解耦设计。

前言:为了简化开发的步骤和降低设计的耦合性,在spring框架中引入了IOC容器这一概念。IOC理论提出的观点大体是这样的:借助于"第三方"实现具有依赖关系的对象之间的解耦。因此,在spring中,对象的创建与赋值均借助于IOC容器由框架来实现。初始化时,我们将组件放置与IOC容器中儿不具体指定使用该组件的对象,当某一具体对象需要使用组件时,直接从容器中获取即可。


目录:

一、通过@Bean方式添加

通常会通过在配置类中方法上添加@bean将对象注册到容器中。在spring整合其他框架场景中,为了降低模块之间的耦合性,需要考虑使用工厂bean来添加组件
1.1 @bean添加组件
示例1:将person实例化并注册到容器中,最后在测试类中从容器中取出person对象。
I) 创建实体类Person.java
package com.allin.pojo;

public class Person {
    private String userName;

    private Integer age;

    private String sex;

    public Person(String userName, Integer age, String sex) {
        this.userName = userName;
        this.age = age;
        this.sex = sex;
    }
    
    public String getUserName(){
        return userName;
    }

    @Override
    public String toString() {
        return "Person{" +
                "userName='" + userName + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}
II) 创建配置类MyConfig,在类上使用@Configuration注解标注为配置类,在类中方法上使用@bean注解将对象注册到容器中。

默认注册到容器中的组件名为注册组件时方法名,可通过@bean(value=“XXX”)修改组件名

package com.allin.config;

import com.allin.pojo.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfig {

    @Bean
    public Person person(){
        return new Person("miaowu",22,"male");
    }
}
III) 创建测试类,在测试类中根据组件名将对象从IOC容器中取出
    @Test
    public void test02(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        String[] definitionNames = applicationContext.getBeanDefinitionNames();
        //查询容器中有哪些组件
        for(String name : definitionNames){
            System.out.println(name);
        }
        Person person = (Person) applicationContext.getBean("person");
        System.out.println(person.getUserName());
    }
IV) 测试结果:容器中包含MyConfig和person组件,将person对象按组件名取出并打印person对象中属性值

请添加图片描述

1.2 使用工厂bean添加组件
当项目中存在多个相同类型实体类,我们不需要将所有实体类实例化并注册到容器中,可以使用工厂bean进行动态选择项目所需要的实体类进行初始化并注册到容器中,以提高项目运行的效率和提高程序设计的灵活性
示例2:项目中包含有多种颜色的实体类(Blue,Yellow),选择Blue实体类进行实例化并注册到容器中,测试类将对象取出并进行测试。
I) 创建实体类Blue和Yellow

entity:Blue:

package com.allin.pojo;

public class Blue {

    public String description = "this is blue color";

}

entity:Yellow:

package com.allin.pojo;

public class Yellow {

    private String discription = "this is yellow color";

}
II) 创建工厂bean类ColorFactoryBean实现FactoryBean,getObject类返回Blue对象
package com.allin.pojo;

import org.springframework.beans.factory.FactoryBean;

public class ColorFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new Blue();
    }

    @Override
    public Class<?> getObjectType() {
        return Blue.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}
III) 创建配置类MyConfig02注册工厂bean
package com.allin.config;

import com.allin.pojo.ColorFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfig02 {

    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }
}
IV) 创建测试类
    @Test
    public void test06(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig02.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for(String name : beanDefinitionNames){
            System.out.println(name);
        }
        //工厂bean获取的是调用getObject创建的对象
        Object bean = applicationContext.getBean("colorFactoryBean");
        System.out.println("bean的类型:" + bean.getClass());

        Blue bean1 = (Blue) applicationContext.getBean("colorFactoryBean");
        System.out.println(bean1.description);
    }
v) 测试结果:将colorFactoryBean对象注册入容器中,实际存储在IOC容器中的为以colorFactory为组件名的,由ColorFactory类中getObject()方法实例化的Blue对象

在这里插入图片描述

二、通过包扫描方式添加

spring中定义了 @Component、@Service、@Controller、@Repository注释来声明组件,通过在配置类中使用包扫描@ComponentScan将组件添加到容器中
示例3:创建实体类User,包含uesrName和password属性,使用@Component注解标注;创建应用类Service,定义add方法,使用@Service标注。在配置类Config01类中将组件注册到容器中,在测试类中将组件从容器中取出进行测试
I) 创建实体类User,使用@Component注解标注
package com.allin.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class User {

    @Value("miaowu")
    private String userName;

    @Value("5201024")
    private String password;

    @Override
    public String toString() {
        return "User{" +
                "userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
II) 创建应用类MyService,使用@Service标注注解
package com.allin.service;


import org.springframework.stereotype.Service;

@Service
public class MyService {

    public void add(){
        System.out.println("service……add……execute!");
    }
}
III) 创建配置类MyConfig01,使用包扫描将被@Component、@Service注解标注的类注册到容器中。

被标注的类以类名为组件名被注册到容器中

package com.allin.config;


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

@Configuration
@ComponentScan(value = {"com.allin.pojo", "com.allin.service"})
public class MyConfig01 {
}
IV) 创建测试类,将组件从容器中取出并进行测试
    @Test
    public void test05(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig01.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for(String name : beanDefinitionNames){
            System.out.println(name);
        }
        User user = (User)applicationContext.getBean("user");
        System.out.println(user);
        MyService service = (MyService) applicationContext.getBean("myService");
        service.add();
    }
V) 测试结果:User、MyService类以类名为组件名注册到容器中

在这里插入图片描述

三、通过@Import方式添加

使用@Import方式可以方便注册第三方包到容器中

示例4:将User类通过@Import注册到容器中,User类中包含内容同上示例3
I) 创建实体类User,同上示例3
II) 在配置类Config03上使用@Import导入User类

使用@Import注册的组件名为全类名

package com.allin.config;

import com.allin.pojo.User;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(User.class)
public class MyConfig03 {
}
III) 创建测试类将组件取出
    @Test
    public void test07(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig03.class);
        User bean = (User)applicationContext.getBean("com.allin.pojo.User");
        System.out.println(bean);
    }
IV) 测试结果:@Import将实体类以全类名为组件名注册到组件中

在这里插入图片描述


3.1 ImportSelector接口
ImportSelector接口中含有两个方法:

String[] selectImports(AnnotationMetadata importingClassMetadata);

  • 返回值:导入到容器中的组件全类名
  • AnnotationMetadata:当前标注@Import注解的类的所有注释信息

default Predicate getExclusionFilter();

相当于给selectImports返回的String加一个过滤器,如果Predicate返回为True,则过滤,不进行注册

示例5:将示例2中的Yellow、Blue通过ImportSelector接口导入到容器中,通过getExclusionFilter()过滤掉Blue对象
I) 创建Yellow、Blue对象,同上示例2
II) 实现ImportSelector接口,在selectImports方法将要导入的组件全类名返回,在getExclusionFilter()方法中过滤全类名中含有Blue的组件
package com.allin.importselector;

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

import java.util.function.Predicate;

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com/allin/pojo/Blue","com/allin/pojo/Yellow"};
    }

    @Override
    public Predicate<String> getExclusionFilter() {
        return className->className.contains("Blue");
    }
}
III) 创建配置类ImportSelectorConfig,将MyImportSelector接口导入
package com.allin.config;

import com.allin.importselector.MyImportSelector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import(MyImportSelector.class)
@Configuration
public class ImportSelectorConfig {
}
IV) 创建测试类,测试容器中包含哪些组件
    @Test
    public void test08(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ImportSelectorConfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for(String beanName : beanDefinitionNames){
            System.out.println("beanName:" + beanName + "===" + "bean对象:" + applicationContext.getBean(beanName));
        }
    }
V) 测试结果:容器中包含Yellow组件,不含Blue组件

在这里插入图片描述

3.2 ImportBeanDefinitionRegistrar接口
ImportBeanDefinitionRegistrar支持我们自己写的代码封装成 BeanDefinition对象;实现此接口的类会回调 postProcessBeanDefinitionRegistry方法注册到spring容器中
实例6:將Blue实体类通过ImportBeanDefinitionRegistrar注册到容器中
I) 创建实体类Blue,Bean类中内容同上示例2
II) 创建MyImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口,在registerBeanDefinitions方法中自定义组件名,并将Blue实体类转为组件注册到容器中
package com.allin.registor;

import com.allin.pojo.Blue;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean definition = registry.containsBeanDefinition("red");
        if(!definition){
            RootBeanDefinition beanDefinition = new RootBeanDefinition(Blue.class);
            registry.registerBeanDefinition("Blue",beanDefinition);
        }
    }
}
III) 创建配置类将ImportBeanDefinitionRegistrar接口导入
package com.allin.config;

import com.allin.registor.MyImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class MyConfig04 {
}
IV) 创建测试类,查看Blue组件是否注册到容器中
    @Test
    public void test09(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig04.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for(String name : beanDefinitionNames){
            System.out.println(name);
        }
    }
V) 测试结果:

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值