spring(注解版)将组件加入到容器

本文介绍了如何使用注解在Spring中将自定义的JavaBean和第三方jar的JavaBean加入到容器中。对于自定义Bean,通过@ComponentScan配合@Component进行包扫描。对于第三方库的Bean,可以利用@Configuration结合@Bean注解,或者使用@import注解导入@Configuration类或组件。

一、将javaBean装载到容器中的方式(注解版)

一、自定义的javabean装载到容器中

1.1、@ComponentScan+@Component

  对于我们自己创建(自定义)的javabean,将它加入到Spring容器中,我们一般使用@ComponentScan+@Component注解的方式将它加到组件中。@ComponentScan的value属性指定包扫描路径,指定包及其子包下标注了@Component注解的Javabean会被加到容器中(注意:@Controller、@Service、@Repository本质上也是@Component,他们的作用本质是一样的
示例:
1、配置类

/**
 *
 * @ComponentScan注解包扫描,会将指定包下标注了@Component、@Controller、@Service、@Resposity的组件加载到容器中去。
 * 它有以下常用属性:
 *      1、basePackages属性:指定要扫描的包
 *      2、useDefaultFilters:是否使用默认的过滤器,默认是true。想自己指定过滤规则时要将该属性设置为false
 *      3、includeFilters属性:指定满足被扫描的包下的组件要满足哪些条件才能被加到容器中,它是一个@Filter集合
 *                    @Filter过滤注解。它的常用属性如下:
 *                    1、type属性指定根据什么条件过滤 1)FilterType.ANNOTATION根据注解类型过滤
 *                                               2)FilterType.ASSIGNABLE_TYPE根据组件的类型过滤
 *                                               3)FilterType.ASPECTJ根据ASPECTJ表达式过滤
 *                                               4)FilterType.REGEX根据正则表达式过滤(基本不用、我也不太会)
 *                                               5)FilterType.CUSTOM自定义过滤规则
 *      4、excludeFilters属性:指定不将哪些包加入到容器中,用法和includeFilters属性差不多
 */
@ComponentScan(
basePackages={"com.tellhow.review.spring_annotation.componenttocontainer"},
useDefaultFilters=false,
includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})}
)
@Slf4j
@Configuration//标注了@Configuration注解的类,Spring会将它识别为配置类。标注了@Configuration注解的类也会当做组件加到容器中
public class SpringAnnotationAddComponent {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
           log.info(beanDefinitionName);
        }
    }
}




//自定义类型过滤器,用来过滤不需要加到容器的组件
class MyTypeFilter implements TypeFilter {
    /**
     * 确定此筛选器是否与给定元数据所描述的类匹配。
     * @param metadataReader 目标类(被扫描类扫描的类)的元数据读取器
     * @param metadataReaderFactory 为其他类(如超类和接口)获取元数据读取器的工厂
     * @throws IOException
     * return  返回值为trues时才会被加到容器中
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) {
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        if (classMetadata.getClassName().contains("Service")){//如果被加到容器中的类名包括Service,就不添加到容器中
            return false;
        }
        return true;
    }
}

2、组件类(这个类在指定扫描包下并标注了@Controller注解,且这个类没有过滤掉,所以这个类是实例会被加到容器中)

package com.tellhow.review.spring_annotation.componenttocontainer.controller;
import org.springframework.stereotype.Controller;
/**
 * @author wujianghao
 * @date 2022年10月28日 10:27
 */
@Controller
public class ComponentController {
}

二、将第三方jar的javaBean作为组件加到容器中

  从第三方引入的类,由于不是我们编写的。这些类上一般不会标@Component注解。而且我们是通过导入jar包的方式导入这些javabean的,导入的是class文件,无法对这些javabean添加@Component注解(实际上即使可以添加也不会添加,因为不方便管理),所以不适合用上面包扫描的方式,我们可以使用下面这些方式向Spring容器注入这个javabean作为组件。

2.1、@Configuration+@Bean

1)、@Configuration注解标注在类上,说明这个类是一个配置类。@Configuration注解有一个属性proxyBeanMethods,它用来指定是否应该代理@Bean方法以强制执行bean生命周期行为,例如,即使在用户代码中直接调用@Bean方法的情况下,也要返回共享的单例bean实例。
2)、在配置类的方法上标注@Bean,那么这个会以这个方法名作为组件名以方法的返回值作为组件值。

/**
  * @Configuration注解用来标识这是一个配置类 他有一个重要的属性proxyBeanMethods属性是用来设置MyConfig配置类是否被代理。
  *     true的话通过调用MyConfig方法获取对象时(非从容器中取),每次取出来的都是同一个。
  *     false的话通过调用MyConfig方法获取对象时(非从容器中取),每次取出来的都不是同一个。
  *     当配置类的中的bean之间存在依赖关系时,用proxyBeanMethods设置为true,没依赖关系设置为false,默认值是true
 */
@Configuration(proxyBeanMethods = true)
@Slf4j
public class MyConfig {

   /**
   * 在配置类中@Bean注解标识在方法上,这个的返回值会被当做组件加载到容器中,组件的名字是默认是方法名。也可与通过@Bean注解的value属性指定组件名称
   */
    @Bean("spiritsBranch")
    public AvenueBranchPojo spiritsBranch() {
        log.info("---------鬼神道avenueBranchPojo单例对象开始创建----------");
        return new AvenueBranchPojo();
    }
    
   /**
     * @Scope注解:用来指定组件的作用域,通过value属性指定
     *      ConfigurableBeanFactory.SCOPE_PROTOTYPE//多例模式(每次从容器中获取的对象都不是相同的),在调用该对象时,才会创建对象
     *      ConfigurableBeanFactory.SCOPE_SINGLETON //单例模式(每次从容器中获取的对象都是相同的),项目在开始运行的时侯,就会创建对象
     *      org.springframework.web.context.WebApplicationContext.SCOPE_REQUEST//同一个请求域下(不用该作用域)
     *      org.springframework.web.context.WebApplicationContext.SCOPE_SESSION//同一个Session下(不用该作用域)
     */
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)//多例模式
    @Bean("worldPojo")
    public WorldPojo worldPojo() {
        log.info("--------传武世界WorldPojo(多例)对象开始创建---------");
        WorldPojo worldPojo = new WorldPojo();
        worldPojo.setName("传武世界");
        return worldPojo;
    }

    @Lazy//懒加载,bean的作用域为单例时,项目开始运行就调用下面的方法并创建出该对象。我们想在用到该对象才创建,只需要加一个@Lazy注解。作用域为多例在调用的时才会创建对象。所以这个注解对于多例模式没有用
    @Bean("creationBranch")
    @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)//这个bean的作用域
    @Conditional(value = {MyCondition.class})//条件装配注解,这个组件满足条件的才会被装载到容器中
    public AvenueBranchPojo creationBranch() {
        log.info("----------万物道AvenueBranchPojo单例对象开始创建(懒加载)----------");
        return new AvenueBranchPojo();
    }


  /**
  *我们向容器添加BeanFactory类型的组件,我们从容器中取,取出来的不是BeanFactory组件本身。而是FactoryBean的getObject()方法的返回值对象
  *
  */
   @Bean("myFactoryBean")
    public MyFactoryBean myFactoryBean() {
        log.info("--------传武世界myFactoryBean(多例)对象开始创建---------");
        MyFactoryBean myFactoryBean = new MyFactoryBean();
        return myFactoryBean;
    }
}

//实现FactoryBean 的bean不能作为普通bean使用。FactoryBean是以bean样式定义的,但是为bean引用公开的对象(getObject())始终是它所创建的对象
 class MyFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        WorldPojo worldPojo = new WorldPojo();
        worldPojo.setName("斗罗大陆");
        worldPojo.setWId("10086");
        return worldPojo;
    }
    @Override
    public Class<?> getObjectType() {
        return WorldPojo.class;
    }
}

/**
* 条件装配类,可以给组件指定满足条件的才会被装配到容器中
*/
class MyCondition implements Condition {
    /**
     *
     * @param context 环境条件
     * @param metadata 被检查的类的方法或元数据
     * @return 是否满足匹配条件
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getRegistry().containsBeanDefinition("worldPojo")?true:false;
    }
}

2.1、@import注解

  @import注解提供等同于Spring XML中的元素的功能。允许导入@Configuration类、ImportSelector和importbeandefinitionregistry实现,以及常规组件类(从4.2开始;类似于AnnotationConfigApplicationContext.register)。

1、使用@import注解组件到容器中

1、将@import注解标在配置类中(不一定非是配置类,只要是组件类都可以)

@Configuration
@Import(value = {UnitedPojo.class,MyImportSector.class,MyImportBeanDefinitionRegistrar.class})
public class MyConfig {
}

2、自定义ImportSector类

public class MyImportSector implements ImportSelector {
    //根据导入的@Configuration类的AnnotationMetadata选择并返回应该导入的类的名称。
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        String className = PersonPojo.class.getName();
        return new String[]{className};
    }
}

3、自定义MyImportBeanDefinitionRegistrar

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
//根据导入的@Configuration类的给定注释元数据,根据需要注册bean定义。注意,由于与@Configuration类处理相关的生命周期约束,这里可能没有注册BeanDefinitionRegistryPostProcessor类型。默认实现是空的。Params: importingClassMetadata -导入类注册表的注释元数据-当前bean定义注册表
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
       //注册bean的定义信息
       registry.registerBeanDefinition("commonController",new RootBeanDefinition(CommonController.class));
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值