美文网首页
Spring 注解驱动开发--- 组件注册

Spring 注解驱动开发--- 组件注册

作者: 一生逍遥一生 | 来源:发表于2020-04-29 19:45 被阅读0次

    在开发的过程中,大多数程序员都在使用Spring Boot开发,这样将配置工作量减少了很多,本文就是介绍一下使用注解开发,
    Spring 的版本为5.2.6.RELEASE。

    添加依赖

    <!---要表明jdk的版本以及依赖的版本号-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring.version>5.2.6.RELEASE</spring.version>
        <junit.version>4.13</junit.version>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <!--添加spring-context依赖-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <!--添加junit依赖-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    

    Configuration & @Bean

    @Configuration这个注解是将这个类当作一个配置类,类似Spring的配置文件;
    @Bean是往容器中注册一个Bean。

    创建一个Person

    package com.edu.spring.bean;
    // 可以在idea中添加lombok组件,省略了get/set、toString方法
    public class Person {
        private String name;
        private Integer age;
    }
    

    配置类

    package com.edu.spring.config;
    
    import com.edu.spring.bean.Person;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class MainConfig {
        @Bean
        public Person person(){
            Person person = new Person("xiaoyao",20);
            return person;
        }
    }
    

    编写测试类

    package com.edu.spring;
    import com.edu.spring.bean.Person;
    import com.edu.spring.config.MainConfig;
    import org.junit.Test;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    public class MainTest {
         // 可以正常输出person这个类的属性值,表示注册成功。
        @Test
        public void annotationConfig(){
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
            Person person = context.getBean(Person.class);
            System.out.println(person.getName()+" "+ person.getAge());
        }
    }
    

    CompnonentScan

    @ComponentScan这个注解是在配置文件中需要制定要扫描的包。
    @CompnonentScan参数介绍:

    • value制定要扫描的包
    • excludeFilters 指定扫描的时候按照规则排除哪些组件
    • includeFilters 制定扫描的时候只需要哪些组件
    • ComponentScans 可以设置多个ComponentScan。
    package com.edu.spring.config;
    
    import com.edu.spring.bean.Person;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.ComponentScan.Filter;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.FilterType;
    import org.springframework.stereotype.Controller;
    
    /**
     * 配置类
     * Componentscan
     * value制定要扫描的包
     * excludeFilters 指定扫描的时候按照规则排除哪些组件
     * includeFilters 制定扫描的时候只需要哪些组件
     * ComponentScans 可以设置多个ComponentScan。
     */
    @Configuration
    @ComponentScan(value = "com.edu.spring")
    public class MainConfig {
        @Bean
        public Person person(){
            Person person = new Person("xiaoyao",20);
            return person;
        }
    }
    

    创建其他类

    package com.edu.spring.controller;
    import org.springframework.stereotype.Controller;
    @Controller
    public class BookController {
    }
    
    package com.edu.spring.dao;
    import org.springframework.stereotype.Repository;
    @Repository
    public class BookDao {
    }
    
    package com.edu.spring.service;
    import org.springframework.stereotype.Service;
    @Service
    public class BookService {
    }
    

    使用测试方法componentScan,输出结果为:

    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
    mainConfig
    bookController
    bookDao
    bookService
    person
    

    如果添加了excludeFilters = {@Filter(type = FilterType.ANNOTATION,classes = {Controller.class})},就会输出如下所示,
    就是在扫描的时候,将使用@Controller的类排除在外

    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
    mainConfig
    bookDao
    bookService
    person
    

    FilterType

    • ANNOTATION:按照指定注解进行过滤
    • ASSIGNABLE_TYPE: 按照给定的类型进行过滤
    • ASPECTJ: 使用aspectj表达式进行过滤
    • REGEX: 使用正则表达式进行过滤
    • CUSTOM: 使用自定义规则进行过滤。

    自定义Filter

    package com.edu.spring.service;
    import org.springframework.core.io.Resource;
    import org.springframework.core.type.AnnotationMetadata;
    import org.springframework.core.type.ClassMetadata;
    import org.springframework.core.type.classreading.MetadataReader;
    import org.springframework.core.type.classreading.MetadataReaderFactory;
    import org.springframework.core.type.filter.TypeFilter;
    import java.io.IOException;
    public class CustomFilter implements TypeFilter {
        /**
         * 如果符合要求就过滤,如果不符合要求不过滤。
         * @param metadataReader 读取到当前正在扫描的类信息
         * @param metadataReaderFactory 获取其他类信息
         * @return
         * @throws IOException
         */
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
            // 获取当前注解信息
            AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
            // 获取当前类的元数据
            ClassMetadata classMetadata = metadataReader.getClassMetadata();
            // 获取当前资源信息
            Resource resource = metadataReader.getResource();
            String className = classMetadata.getClassName();
            System.out.println("--->"+className);
            return false;
        }
    }
    

    测试

    需要修改配置类:
    @ComponentScan(value = "com.edu.spring",excludeFilters = {
    //@Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
    @Filter(type = FilterType.CUSTOM,classes = {CustomFilter.class})
    })

    输出结果为:

    --->com.edu.spring.MainTest
    --->com.edu.spring.bean.Person
    --->com.edu.spring.controller.BookController
    --->com.edu.spring.dao.BookDao
    --->com.edu.spring.service.BookService
    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
    mainConfig
    bookController
    bookDao
    bookService
    person
    

    @Scope

    @Scope 用来定义类的类型,是单实例形式还是多实例的形式。

    • SCOPE_PROTOTYPE 每次使用的时候,都会创建一个新的对象
    • SCOPE_SINGLETON 容器内单例,默认值
    • SCOPE_REQUEST 每次发送请求都会创建
    • SCOPE_SESSION 每次请求都会创建一个session

    编写新的配置类

    package com.edu.spring.config;
    
    import com.edu.spring.bean.Person;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Scope;
    @Configuration
    public class MainConfig2 {
        @Bean
        @Scope
        //@Scope(value = "prototype")
        public Person person(){
            Person person = new Person("xiaoyao",20);
            return person;
        }
    }
    

    测试方法

    @Test
    public void scope(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
        Person bean = context.getBean(Person.class);
        Person bean1 = context.getBean(Person.class);
        System.out.println(bean == bean1);
    }
    

    @Conditional

    @Conditional 按照条件进行注册Bean。

    自定义Condition

    package com.edu.spring.condition;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.env.Environment;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    public class WindowCondition implements Condition {
        /**
         * 根据条件进行比较
         * @param context 判断条件使用的上下文
         * @param metadata 注释信息
         * @return
         */
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            //可以获取 beanfactory
            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
            //获取类加载信息
            ClassLoader classLoader = context.getClassLoader();
            // 获取环境变量
            Environment environment = context.getEnvironment();
            //获取bean定义的注册类
            BeanDefinitionRegistry registry = context.getRegistry();
            String property = environment.getProperty("os.name");
            if (property.contains("Windows")){
                return true;
            }
            return false;
        }
    }
    
    package com.edu.spring.condition;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.env.Environment;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    public class MacCondition implements Condition {
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            //可以获取 beanfactory
            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
            //获取类加载信息
            ClassLoader classLoader = context.getClassLoader();
            // 获取环境变量
            Environment environment = context.getEnvironment();
            //获取bean定义的注册类
            BeanDefinitionRegistry registry = context.getRegistry();
            String property = environment.getProperty("os.name");
            if (property.contains("Mac")){
                return true;
            }
            return false;
        }
    }
    

    配置文件

    package com.edu.spring.config;
    import com.edu.spring.bean.Person;
    import com.edu.spring.condition.MacCondition;
    import com.edu.spring.condition.WindowCondition;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Scope;
    @Configuration
    public class MainConfig2 {
        @Bean
        @Scope(value = "prototype")
        public Person person() {
            Person person = new Person("xiaoyao",20);
            return person;
        }
        @Conditional( {WindowCondition.class})
        @Bean("bill")
        public Person person1() {
            return new Person("Bill Gates", 65);
        }
        @Conditional({MacCondition.class})
        @Bean("linus")
        public Person person2() {
            return new Person("linus", 48);
        }
    }
    

    @Import

    给容器中注册组件:
    1.包扫描 + 组件标注组件(@Controller/@Service/@Repository/@Component)
    2.@Bean 导入第三方包里面的组件
    3.@Import 快速给容器中导入一个组件 id为全类名
    @ImportSelector:返回需要导入的组件的全类名数组;
    @ImportBeanDefinitionRegistrar: 手动注册bean到容器中
    4.使用Spring提供的FactoryBean
    默认获取具体的bean
    如果想要获取工厂bean本身,需要添加&。

    Import

    package com.edu.spring.config;
    
    import com.edu.spring.bean.*;
    import com.edu.spring.condition.MacCondition;
    import com.edu.spring.condition.WindowCondition;
    import com.edu.spring.registrar.CustomBeanDefinitionRegistrar;
    import com.edu.spring.selector.CustomImportSelector;
    import org.springframework.context.annotation.*;
    
    /**
     * @author xiaoyao.
     * @date 2020/4/29.
     * @time 4:46 PM.
     */
    @Configuration
    @Import({Color.class})
    public class MainConfig2 {
        @Bean
        @Scope(value = "prototype")
        public Person person() {
            Person person = new Person("xiaoyao",20);
            return person;
        }
    
        @Conditional( {WindowCondition.class})
        @Bean("bill")
        public Person person1() {
            return new Person("Bill Gates", 65);
        }
    
        @Conditional({MacCondition.class})
        @Bean("linus")
        public Person person2() {
            return new Person("linus", 48);
        }
    
    }
    

    测试方法:

    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] definitionNames = context.getBeanDefinitionNames();
    for (String name:definitionNames){
        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
    mainConfig2
    com.edu.spring.bean.Color
    person
    linus
    

    ImportSelector

    需要实现自定义的ImportSelector

    import org.springframework.context.annotation.ImportSelector;
    import org.springframework.core.type.AnnotationMetadata;
    import java.util.Set;
    /**
     * 自定义逻辑返回需要导入的组件
     */
    public class CustomImportSelector implements ImportSelector {
        /**
         * 返回值,就是导入到容器中的组件全类名
         * @param importingClassMetadata 当前标注@Import注解的类的所有注解信息
         * @return
         */
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{"com.edu.spring.bean.Red"};
        }
    }
    

    配置文件为:

    package com.edu.spring.config;
    
    import com.edu.spring.bean.*;
    import com.edu.spring.condition.MacCondition;
    import com.edu.spring.condition.WindowCondition;
    import com.edu.spring.registrar.CustomBeanDefinitionRegistrar;
    import com.edu.spring.selector.CustomImportSelector;
    import org.springframework.context.annotation.*;
    
    /**
     * @author xiaoyao.
     * @date 2020/4/29.
     * @time 4:46 PM.
     */
    @Configuration
    @Import({Color.class, CustomImportSelector.class})
    public class MainConfig2 {
        @Bean
        @Scope(value = "prototype")
        public Person person() {
            Person person = new Person("xiaoyao",20);
            return person;
        }
    
        @Conditional( {WindowCondition.class})
        @Bean("bill")
        public Person person1() {
            return new Person("Bill Gates", 65);
        }
    
        @Conditional({MacCondition.class})
        @Bean("linus")
        public Person person2() {
            return new Person("linus", 48);
        }
    
    }
    

    结果为:

    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
    mainConfig2
    com.edu.spring.bean.Color
    com.edu.spring.bean.Red
    person
    linus
    

    ImportBeanDefinitionRegistrar

    实现自定义的ImportBeanDefinitionRegistrar。

    package com.edu.spring.registrar;
    
    import com.edu.spring.bean.Blue;
    import com.edu.spring.bean.RainBow;
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.beans.factory.support.BeanNameGenerator;
    import org.springframework.beans.factory.support.RootBeanDefinition;
    import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
    import org.springframework.core.type.AnnotationMetadata;
    public class CustomBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        /**
         * 手动注册bean
         * @param importingClassMetadata 当前类的注解信息
         * @param registry bean定义饿的注册类
         * @param importBeanNameGenerator 产生bean的名字
         */
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
            boolean blue = registry.containsBeanDefinition("com.edu.spring.bean.Blue");
            boolean red = registry.containsBeanDefinition("com.edu.spring.bean.Red");
            if (red && blue){
                RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
                rootBeanDefinition.setBeanClass(RainBow.class);
                registry.registerBeanDefinition("rainbow",rootBeanDefinition);
            }
        }
    }
    

    配置文件:

    package com.edu.spring.config;
    
    import com.edu.spring.bean.*;
    import com.edu.spring.condition.MacCondition;
    import com.edu.spring.condition.WindowCondition;
    import com.edu.spring.registrar.CustomBeanDefinitionRegistrar;
    import com.edu.spring.selector.CustomImportSelector;
    import org.springframework.context.annotation.*;
    
    /**
     * @author xiaoyao.
     * @date 2020/4/29.
     * @time 4:46 PM.
     */
    @Configuration
    @Import({Color.class, CustomImportSelector.class,CustomBeanDefinitionRegistrar.class})
    public class MainConfig2 {
        @Bean
        @Scope(value = "prototype")
        public Person person() {
            Person person = new Person("xiaoyao",20);
            return person;
        }
    
        @Conditional( {WindowCondition.class})
        @Bean("bill")
        public Person person1() {
            return new Person("Bill Gates", 65);
        }
    
        @Conditional({MacCondition.class})
        @Bean("linus")
        public Person person2() {
            return new Person("linus", 48);
        }
    }
    

    输出结果为:

    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
    mainConfig2
    com.edu.spring.bean.Color
    com.edu.spring.bean.Red
    com.edu.spring.bean.Blue
    person
    linus
    rainbow
    

    FactoryBean

    添加创建bean的工厂:

    package com.edu.spring.bean;
    import org.springframework.beans.factory.FactoryBean;
    public class ColorFactoryBean implements FactoryBean<Color> {
        public Color getObject() throws Exception {
            return new Color();
        }
    
        public Class<?> getObjectType() {
            return Color.class;
        }
    }
    

    通过colorFactoryBean获取到的对象是Color,如果想要获取ColorFactoryBean,需要在名字之前添加&, 这样在获取的时候,Spring才会判断出想要的是
    工厂类,而不是具体的类。

    相关文章

      网友评论

          本文标题:Spring 注解驱动开发--- 组件注册

          本文链接:https://www.haomeiwen.com/subject/fhonwhtx.html