Spring:注解组件注册

@Configuration&@Bean

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.12.RELEASE</version>
    </dependency>
@Configuration
public class MainConfig {
    @Bean
    public Person person(){
        return new Person("aaa",19);
    }
}

public class MainTest {
    public static void main(String[] args) {

        ApplicationContext applicationContext  = new AnnotationConfigApplicationContext(MainConfig.class);
        Person bean = applicationContext.getBean(Person.class);
        System.out.println(bean);

        String[] names = applicationContext.getBeanNamesForType(Person.class);
        System.out.println(Arrays.toString(names));
    }
}

image-20201215170413368

@ComponentScan自动扫描组件&指定扫描规则

image-20201215171020541

    @Test
    public void test(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] names = applicationContext.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }

image-20201215171049669

指定排除规则:

@ComponentScan(value = "com.wj", excludeFilters = {
        //按照注解类型去排除(排除标注Controller和Repository的类)
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class,Repository.class})
})
@ComponentScan(value = "com.wj", includeFilters = {
        //按照注解类型去扫描(只扫描标注Controller和Repository的类)
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class,Repository.class})
},useDefaultFilters=false)

多组规则:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {

	ComponentScan[] value();

}

此外,ComponentScan是一个可重复注解(jdk8),这也就意味着可以在一个类上可以标注多个ComponentScan来制定多组规则

TypeFilter指定过滤规则

按照指定的类型

public enum FilterType {
	//按照注解
	ANNOTATION,
    //按照给定类型
	ASSIGNABLE_TYPE,
    //ASPECTJ表达式
	ASPECTJ,
    //正则指定
	REGEX,
    //自定义规则
	CUSTOM
}

按照指定类型去扫描

@ComponentScan(value = "com.wj", includeFilters = {
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = BookService.class)
},useDefaultFilters=false)

image-20201215173807290

自定义filter:我们需要实现TypeFilter接口

	/** Filter candidates using a given custom
	 * {@link org.springframework.core.type.filter.TypeFilter} implementation.
	 */
	CUSTOM

public class MyTypeFilter implements TypeFilter {

    /**
     *
     * @param metadataReader 读取到当前正在扫描的类的信息
     * @param metadataReaderFactory 可以获取到其他任何类信息
     */
    @Override
    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-->"+className);
        return false;
    }
}
@ComponentScan(value = "com.wj", includeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = MyTypeFilter.class)
},useDefaultFilters=false)
image-20201215175419347

组件设置作用域@Scope

一般来说,放入IOC容器的bean都是单实例的

	/**
	 * Specifies the name of the scope to use for the annotated component/bean.
	 * <p>Defaults to an empty string ({@code ""}) which implies
	 * {@link ConfigurableBeanFactory#SCOPE_SINGLETON SCOPE_SINGLETON}.
	 * @since 4.2
	 * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE 多实例的
	 * @see ConfigurableBeanFactory#SCOPE_SINGLETON 单实例的
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST 同一次请求创建一个实例
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION 同一个Session创建一个实例
	 * @see #value
	 */

单实例:ioc容器启动会调用方法创建对象放到ioc容器中,以后每次获取就是直接从容器中获取。

多实例:ioc容器启动并不会去调用方法创建对象放在容器中,每次获取的时候才会调用方法创建对象。

@Lazy懒加载

因为单实例对象默认在容器启动的时候创建对象。

使用@Lazy懒加载会在容器启动的时候不创建对象,需要使用的时候再创建对象

    @Bean
    @Lazy
    public Person person(){
        System.out.println("person实例创建了。。。。");
        return new Person("aaa",19);
    }

@Conditional按照条件注册

按照一定的条件进行判断,满足条件才注册bean。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
//该注解可以加在类上和方法上
public @interface Conditional {

	/**
	 * All {@link Condition}s that must {@linkplain Condition#matches match}
	 * in order for the component to be registered.
	 */
	Class<? extends Condition>[] value();

}
    @Bean("bbb")
    @Conditional(WindowsCondition.class)
    public Person person01(){
        return new Person("bbb",20);
    }

    @Bean("ccc")
    @Conditional(LinuxCondition.class)
    public Person person02(){
        return new Person("ccc",21);
    }

public class LinuxCondition implements Condition  {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        return property.contains("linux");
    }
}

public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        return property.contains("Windows");
    }
}

我目前使用的是windows,进行测试:

    @Test
    public void test02(){
        String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
        for (String s : beanNamesForType) {
            System.out.println(s);
        }
    }

image-20201216093417844

@Import导入组件

@Configuration
//向IOC容器中导入Color组件,bean的id默认是组件的全类名
@Import(Color.class)
public class MainConfig2 {
}
    @Test
    public void testImport(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
        Color bean = context.getBean(Color.class);
        System.out.println(bean);
    }

使用ImportSelector

public interface ImportSelector {

	/**
	 * Select and return the names of which class(es) should be imported based on
	 * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
	 */
	String[] selectImports(AnnotationMetadata importingClassMetadata);

}

测试:

//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {

        return new String[]{"com.wj.bean.Red","com.wj.bean.Person"};
    }
}

@Configuration
@Import({Color.class, MyImportSelector.class})//向IOC容器中导入Color组件
public class MainConfig2 {
}

测试方法:

    @Test
    public void testImport(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
        printBean(context);
    }

    public void printBean(ApplicationContext applicationContext){
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }

image-20201216095730216

使用ImportBeanDefinitionRegistrar

手动注册bean到容器中

public interface ImportBeanDefinitionRegistrar {

	/**
	 * Register bean definitions as necessary based on the given annotation metadata of
	 * the importing {@code @Configuration} class.
	 * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
	 * registered here, due to lifecycle constraints related to {@code @Configuration}
	 * class processing.
	 * @param importingClassMetadata annotation metadata of the importing class
	 * @param registry current bean definition registry
	 */
    //AnnotationMetadata 当前类的注解信息
    //BeanDefinitionRegistry BeanDefinitionRegistry注册类
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);

}
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    //如果容器中含有Red和Person,就往容器中导入blue
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean red = registry.containsBeanDefinition("com.wj.bean.Red");
        boolean person = registry.containsBeanDefinition("com.wj.bean.Person");
        if(red && person){
            //指定bean的定义信息
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Blue.class);
            registry.registerBeanDefinition("blue",rootBeanDefinition);
        }
    }
}

@Configuration
@Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})//向IOC容器中导入Color组件
public class MainConfig2 {
}

    @Test
    public void testImport(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
        printBean(context);
    }

执行结果:

image-20201216100730266

FactoryBean注册组件

//创建一个spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
    @Override
    public Color getObject() throws Exception {
        System.out.println("ColorFactoryBean初始化。。。");
        return new Color();
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }
}

@Configuration
@Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})//向IOC容器中导入Color组件
public class MainConfig2 {

    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }
}

    @Test
    public void testImport() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
        Object bean = context.getBean("colorFactoryBean");
        System.out.println(bean);

        Object bean2 = context.getBean("&colorFactoryBean");
        System.out.println(bean2);
    }

image-20201216102833960

在id前面加一个&符号,可以直接获取FactoryBean本身。这里在BeanFactory的源码中提到:

public interface BeanFactory {

	/**
	 * Used to dereference a {@link FactoryBean} instance and distinguish it from
	 * beans <i>created</i> by the FactoryBean. For example, if the bean named
	 * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
	 * will return the factory, not the instance returned by the factory.
	 */
	String FACTORY_BEAN_PREFIX = "&";
原文地址:https://www.cnblogs.com/wwjj4811/p/14142725.html