Spring注解开发(一):组件注册

本文是Spring注解开发系列的第一篇,主要介绍了如何使用注解进行组件注册,包括@Configuration、@ComponentScan、@Scope、@Lazy、@Conditional、@Import等。@Configuration用于定义配置类,@ComponentScan自动扫描组件,@Scope定义Bean的作用域,@Lazy实现懒加载,@Conditional按条件注册Bean,@Import快速导入组件。文章结合代码示例详细解析了每个注解的使用方法。
摘要由CSDN通过智能技术生成

一、前言

本文章是在学习尚硅谷雷丰阳老师的Spring注解驱动的教程视频中,所记录的简单笔记以及代码实现!

雷丰阳老师的视频很赞,建议大家可以去学习一下!

小伙伴在学习Spring框架的时候,有没有被各种xml配置文件所烦扰呢?比如:组件的注册,依赖的注入,组件的生命周期,属性赋值等等…

相关博客:

  1. Spring注解开发(一):组件注册
  2. Spring注解开发(二):组件生命周期
  3. Spring注解开发(三):属性赋值
  4. Spring注解开发(四):自动装配

二、注解的基本知识与代码示例

(一)@Configuration

用于定义配置类,即配置类相当于xml配置文件,只是一个是通过xml标签来写配置,一个是通过Java代码的形式来定义配置,被注解的类的内部可以包含一个或多个@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

1. 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">

    <!--注册一个类型为Person,id为person的组件-->
    <bean class="com.study.bean.Person" id="person">
        <property name="name" value="zhangsan"/>
        <property name="age" value="20"/>
    </bean>
</beans>
2. @Configuration注解注册组件
@Configuration
public class ContextConfig {

    @Bean
    public Person person(){
        return new Person("zhangsan", 20);
    }
}

@Bean的注解相当于xml文件中的bean标签。在方法上使用@Bean注解注册Bean对象,Bean类型是方法类型,Bean的id默认为方法名;若修改则在@Bean注解加上value属性,@Bean(value=“xxx”)。

(二)@ComponentScan

  1. 用于包扫描,只要标注了@Controller、@Service、@Repository、@Component的组件,都会自动扫描加入到容器中。作用在配置类上。

  2. value:指定要扫描的package;

  3. includeFilters=Filter[]:指定只包含的组件

  4. excludeFilters=Filter[]:指定需要排除的组件;

  5. useDefaultFilters=true/false:指定是否需要使用Spring默认的扫描规则:被@Component, @Repository, @Service, @Controller或者已经声明过@Component自定义注解标记的组件;

在过滤规则Filter中:

  • FilterType:指定过滤规则,支持的过滤规则有
  • ANNOTATION:按照注解规则,过滤被指定注解标记的类;
  • ASSIGNABLE_TYPE:按照给定的类型;
  • ASPECTJ:按照ASPECTJ表达式;
  • REGEX:按照正则表达式
  • CUSTOM:自定义规则;
    value:指定在该规则下过滤的表达式;
1. 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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--自动包扫描-->
    <context:component-scan base-package="com.study"></context:component-scan>


</beans>
2. @ComponetScan自动包扫描
@Configuration
@ComponentScan(value = "com.study")
public class ContextConfig {


    @Bean
    public Person person(){
        return new Person("lisi", 20);
    }
}

=================================================
//可以定义一些controller、service、dao来测试一下是否真的能够扫描到容器中
    
public class MainTest {


    public static void main(String[] args) {

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ContextConfig.class);

        //获取容器中定义的组件
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();

        for (String name: beanDefinitionNames) {
            System.out.println(name);
        }
    }
}

结果:
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
contextConfig
personController
personDao
personService
person //说明:person在容器中,并不是自动扫描到容器中的,而是在配置类中使用了@Bean注解,注册到了容器中。

分析:在前五个是ioc容器中需要使用的组件,后五个则是自定义的组件,可以看到contextConfig配置类也被自动扫描进入到容器中,显然说明其也使用了@Component注解。

源码:
在这里插入图片描述

(三)@Scope

用于定义Bean的作用域,默认是单例的,在 Spring IoC 容器是指其创建的 Bean 对象相对于其他 Bean 对象的请求可见范围。在 Spring IoC 容器中具有以下几种作用域:基本作用域(singleton、prototype),Web 作用域(reqeust、session、globalsession),自定义作用域。

各个作用域的解释:

scope说明
singleton单例模式全局有且仅有一个实例,容器被创建时bean就会创建并被放入到容器中。以后每次获取该bean时,都直接在容器中获取到该bean。
prototype原型模式每次获取bean的时候会有一个新的实例,每次获取该bean时才会被创建并将该bean放入到容器中。
request每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效
session每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效
global sessionglobal session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个 portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用。
1. 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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--注册一个类型为Person,id为person的组件,定义组件的作用域为多例的-->
    <bean class="com.study.bean.Person" id="person" scope="prototype">
        <property name="name" value="zhangsan"/>
        <property name="age" value="20"/>
    </bean>

</beans>
2. @Scope注解设置组件的作用域
@Configuration
@ComponentScan(value = "com.study")
public class ContextConfig {


    @Bean
    @Scope("prototype")
    public Person person(){
        return new Person("lisi", 20);
    }
}

(四)@Lazy

懒加载,作用于单例的Bean,在创建容器的时候,不立刻创建单例的Bean并加入到容器中。而是在其获取时才创建Bean并加入到容器中。

@Bean
@Scope("singleton")
@Lazy
public Person person(){
    return new Person("lisi", 20);
}

(五)@Conditional

按照一定的条件给容器中注册组件bean!作用是根据某个条件创建特定的Bean,通过实现Condition接口,并重写matches接口方法来构造判断条件。总的来说,就是根据特定条件来控制Bean的创建行为,这样我们可以利用这个特性进行一些自动的配置。可以作用于类和方法上!@Conditional注解放在类上时,对类中的所有的bean可以进行一个统一的管理,是否统一注册到容器中!

在这里插入图片描述

@Conditional注解需要一个Condition的类来作为参数!一般这个条件类是要自己创建的!

源码:
在这里插入图片描述

Condition是一个接口,接口中有个匹配条件的方法,参数var1为条件上下文,参数var2为当前标注了@Conditional注解的类的所有的注释信息!

例子:以不同的操作系统为条件,通过实现Condition接口,并重写其matches方法来构造判断条件。若在Windows系统下运行程序,则输出列表命令为dir;若在Linux系统下运行程序,则输出列表命令为ls。

//window判断条件
public class WindowsCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty("os.name").contains("Windows");
    }
}

//Linux判断条件
public class LinuxCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty("os.name").contains("Linux");
    }
}


//按照条件进行Bean注册
@Bean
@Conditional(WindowsCondition.class)
public String window() {
    return "dir";
}

@Bean
@Conditional(LinuxCondition.class)
public String linux() {
    return "ls";
}

(六)@Import

快速导入一个组件加入到IoC容器中,而不需要在配置类中声明一个方法使用@Bean注解进行初始化操作来加入到容器中。其id默认为全类名,容器会自动注册!@Import(value=“xxx.class”),其value也可以是一个数组的形式!

源码:

在这里插入图片描述

还可以进行多个组件的快速加入,@Import({xxx.class, aaa.class})。

1. ImportSelector

导入自定义的选择器,进行一个组件的批量选择导入!返回值为:导入容器中的组件的全类名数组!

源码:
在这里插入图片描述

示例:测试容器中是否存在使用选择器返回全类名返回的方式的bean

//定义一个Color类
public class Color {
}

//定义一个选择器,实现了ImportSelector接口
public class MySelector implements ImportSelector {

    /**
     *
     * @param importingClassMetadata 当前标注@Imoprt注解的类的全部注解数据
     * @return 返回加入到容器中的bean的全类名
     */
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //返回了Color的全类名
        return new String[]{"com.study.bean.Color"};
    }
}


//配置类中使用@Import注解,但value并不是Color.class而是MySelector.class
@Configuration
@ComponentScan(value = "com.study")
@Import(MySelector.class)
public class ContextConfig {


    @Bean
    @Scope("singleton")
    @Lazy
    public Person person(){
        return new Person("lisi", 20);
    }
}

//打印中容器中的bean
public class MainTest {


    public static void main(String[] args) {

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ContextConfig.class);

        //获取容器中定义的组件
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();

        for (String name: beanDefinitionNames) {
            System.out.println(name);
        }
    }
}

结果:
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
contextConfig
personController
personDao
personService
com.study.bean.Color //存在color组件
person

2. ImportBeanDefinitionRegistrar

手动注册bean加入到容器中,自定义一个类实现ImportBeanDefinitionRegistrar接口,来进行相应的逻辑注册!

在这里插入图片描述

//定义一个bean
public class Dog {
}



// 自定义一个ImportBeanDefinitionRegistrar实现类
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        //判断容器中是否包含person字段的bean
        boolean flag = registry.containsBeanDefinition("person");

        //如果存在,则注册一个dog的组件
        if (flag) {
            //当我想用BeanDefinition创建对象时,发现并没有有参构造,所以选用了其子类
            //BeanDefinition beanDefinition = new BeanDefinition();

            RootBeanDefinition beanDefinition = new RootBeanDefinition(Dog.class);
            //注册需要两个参数{s:bean的名称,beanDefinition:bean的信息--类型,作用域...}
            registry.registerBeanDefinition("dog", beanDefinition);
        }
    }
}

//在配置类注解@Import参数中加入MyImportBeanDefinitionRegistrar.class
@Configuration
@ComponentScan(value = "com.study")
@Import({MySelector.class, MyImportBeanDefinitionRegistrar.class})
public class ContextConfig {


    @Bean
    @Scope("singleton")
    @Lazy
    public Person person(){
        return new Person("lisi", 20);
    }
}


//测试容器中是否存在dog组件
public class MainTest {


    public static void main(String[] args) {

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ContextConfig.class);

        //获取容器中定义的组件
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();

        for (String name: beanDefinitionNames) {
            System.out.println(name);
        }
    }
}


结果:
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
contextConfig
personController
personDao
personService
com.study.bean.Color
person
dog  //容器中存在dog组件,手动注册成功! 

(七)工厂模式注册组件

使用Spring提供的FactoryBean(工厂方法)来创建对象!将工厂加入到IoC容器中时,bean的名称时beanFactory但是其类型是bean的实体类型!

在这里插入图片描述

(八)@Profile

  1. 指定组件在哪个环境的情况下才能被注册到容器中。不指定的情况下,任何环境下都能注册这个组件到容器中。
  2. 添加了@Profile注解的组件,只有在指定环境被激活的时候才能注册到容器中。默认是default环境。
  3. @Profile作用在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效。
  4. 没有标注@Profile注解的组件,在任何环境都是加载到容器中的。
//代码解释@Profile注解

//在配置类中,注册不同环境下的组件
@Configuration
public class MainConfigOfProfile {

    @Bean
    @Profile("test") //test环境才被注册
    public Color color(){
        return new Color();
    }

    @Bean
    @Profile("dev") //dev环境下才被注册
    public Dog dog() {
        return new Dog();
    }

}


======================================================
//运行类
public class MainTest {


    public static void main(String[] args) {

		//创建applicationContex容器对象
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
		
		//设置当前激活环境值
        applicationContext.getEnvironment().setActiveProfiles("dev");
        //注册配置类
        applicationContext.register(MainConfigOfProfile.class);
        //刷新容器
        applicationContext.refresh();

        //获取容器中注册的组件
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();

        for (String name: beanDefinitionNames) {
            System.out.println(name);
        }

    }
}

结果:
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
mainConfigOfProfile
dog //dog组件在容器中


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值