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

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

添加依赖



    UTF-8
    UTF-8
    1.8
    5.2.6.RELEASE
    4.13



    
        
        
            org.springframework
            spring-context
            ${spring.version}
        
        
        
            junit
            junit
            ${junit.version}
            test
        
    

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 {
    public Color getObject() throws Exception {
        return new Color();
    }

    public Class getObjectType() {
        return Color.class;
    }
}

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

你可能感兴趣的:(Spring 注解驱动开发--- 组件注册)