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


    Spring组件注册就是让Spring的IOC容器去管理组件的这个bean,

    SPring组件基于注解的注册方法主要有以下几种:

    首先需要一个@Configuration注解的配置类,告诉Spring容器配置的入口,和xml配置文件的功能一样

    一:@Bean

    首先新建一个Person类,属性为String:name,Integer:age;

    新建配置类,代码如下:

    @Configuration//表示当前类为一个配置类
    public class MainConfig01 {
    	@Bean
    	public Person person() {
    		return new Person("Alen", 18);
    	}
    }

    测试类如下:

    @Test
    public void test01() {
    	AnnotationConfigApplicationContext applicationContext = new 
             AnnotationConfigApplicationContext(MainConfig01.class);
    		String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
    		for (String name : beanDefinitionNames) {
    			System.out.println(name);
    		}
    	}

    打印出来容器中的组件除了Spring本身自带的还有这两个: mainConfig01  person

    1. @Bean默认beanDefinitionName为方法名,也可以指定@Bean("Alen")
    2. @Bean 和xml文件配置中的<Bean>标签一致,也可以指定以下属性

               2.1.默认为单例模式,scope可以指定单例还是多例,单例默认在容器创建是创建组件并放入容器,多例则在获取时创建

               2.2指定init-method和destory-method,单例下Bean的生命周期交给容器管理,init-method和destory-method都会执行,多例下只     会执行destory-method

               2.3.@Lazy注解,组件会在容器获取时初始化创建。

    二:@ComponentScan+@Component(@Service,@Repository,@Controller)

                包扫描+组件注解,@ComponentScan中可以指定要扫描的包中加注了组件注解的类

    在@ComponentScan注解中,

    1.默认会自动扫描以下四个注解注解的组件

    /**
     * Indicates whether automatic detection of classes annotated with {@code @Component}
     * {@code @Repository}, {@code @Service}, or {@code @Controller} should be enabled.
     */
    boolean useDefaultFilters() default true;

    2.标签值为@Filter的两个过滤器

    Filter[] excludeFilters() default {};//排除
    Filter[] includeFilters() default {};//包含

    值为@Filter,默认的过滤类型为注解格式,

    /**
     * The type of filter to use.
     * <p>Default is {@link FilterType#ANNOTATION}.
     * @see #classes
     * @see #pattern
     */
    FilterType type() default FilterType.ANNOTATION;

    在Filter Type枚举类型中还有其他几个格式

    public enum FilterType {	
        // Filter candidates marked with a given annotation.
    	ANNOTATION,//按照注解过滤
    	// Filter candidates assignable to a given type.
    	ASSIGNABLE_TYPE,//按照类型过滤
    	// Filter candidates matching a given AspectJ type pattern expression.
    	ASPECTJ,//使用ASPECTJ表达式
    	// Filter candidates matching a given regex pattern.
    	REGEX,//按照正则过滤
    	//Filter candidates using a given custom
    	CUSTOM//按照用户自定义
    }

    按照自定义的规则

    {@link org.springframework.core.type.filter.TypeFilter} implementation.

    我们需要去实现TypeFilter接口,举个例子,代码如下:

    public class MyFliterType implements TypeFilter {
    	@Override
    	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
    			throws IOException {
    		ClassMetadata classMetadata = metadataReader.getClassMetadata();
    		String className = classMetadata.getClassName();
    		//此处只测试是否匹配扫描的类名包含Demo
    		if (className.contains("Demo")) {
    			return true;
    		}
    		return false;
    	}
    }

    配置类如下:

    @Configuration
    @ComponentScan(value = "com.practice.bean")
    public class MainConfig01 {
    	@Bean
    	public Person person() {
    		return new Person("Alen", 18);
    	}
    }

    测试类:

    @Test
    public void test02() {
    	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig01.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
    mainConfig01
    controllerDemo
    daoDemo
    serviceDemo
    person
    • 1。@ComponentScan(value = "com.practice.bean",  excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = { Controller.class}) }),将Controller注解的组件排除在外,controllerDemo将不会注册
    • 2。@ComponentScan(value = "com.practice.bean", useDefaultFilters = false)将使用默认的过滤器开关置为false,则@Component(@Service,@Repository,@Controller)四个注解的组件将不会自动扫描注册
    • 3.@ComponentScan(value = "com.practice.bean",  excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = { MyFliterType.class}) }),根据自定义规则包含Demo的组件将不会被注册

    includeFilters此处不再讲解,需要将useDefaultFilters = false置为false,因为默认开启会扫描Componernt四个注解。

    三。@Conditional按照条件加载,满足条件则会加载

    自定义一个条件,需要实现Condition类,代码如下

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

    此类的意思是在操作系统在Windows环境下则加载

     在扫描的com.practice.bean包中加了@Component注解的某个类上加上@Conditional(value = MyCondition.class)注解

    我们将启动参数改为-Dos.name=Linux,则此组件将不会再被注册。

    四。@Import(value = {  })导入组件

          1. 直接导入

           在bean的包下先建一个 MyImport类,我们将此注解@Import(value = { MyImport.class })加在我们的主配置类上,执行测试类,

    可以看到,输出的组件中包含了该类的全类名(默认ID为全类名)。

          2.ImportSelector:导入组件选择器,

       2.1实现接口ImportSelector:

    public class MyImportSelector implements ImportSelector {
    	@Override
    	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    		//importingClassMetadata.getClassName()为配置类
    		return new String[] { "com.practice.bean.MyImport" };
    	}
    }

    配置类注解@Import(value = {MyImportSelector.class }),执行测试类,可以看到MyImport组件已注册

      2.2ImportBeanDefinitionRegistrar:导入组件定义注册器

    作用:实现ImportBeanDefinitionRegistrar接口,我们可以为容器注册组件。

       新建ImportBeanDefinitionRegistrarTest类以做测试:

    public class ImportBeanDefinitionRegistrarTest{
    }

      新建MyImportBeanDefinitionRegistrar类,为容器注册ImportBeanDefinitionRegistrarTest类的Bean定义信息,导入该组件。

     代码如下:

    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    	@Override
    	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    		RootBeanDefinition beanDefinition = new RootBeanDefinition(ImportBeanDefinitionRegistrarTest.class);
    		registry.registerBeanDefinition("importBeanDefinitionRegistrarTest", beanDefinition);
    	}
    }
    

         配置类注解改为@Import(value = {MyImportSelector.class,MyImportBeanDefinitionRegistrar.class }),执行测试类,可以看到importBeanDefinitionRegistrarTest组件已注册。

    五。使用FactoryBean注册组件

    FactoryBean实现类如下:

    public class MyFactoryBean implements FactoryBean<Person> {
    	@Override
    	public Person getObject() throws Exception {
    		return new Person();
    	}
    	@Override
    	public Class<?> getObjectType() {
    		return Person.class;
    	}
    }

    配置类修改为

    @Configuration
    @ComponentScan(value = "com.practice.bean")
    public class MainConfig01 {
    	@Bean
    	public MyFactoryBean MyFactoryBean() {
    		return new MyFactoryBean();
    	}
    }
    

    运行测试类,可以看到MyFactoryBean已被注册。那么这个MyFactoryBean就是MyFactoryBean类吗?

    我们在测试类中加上:

    Object bean = applicationContext.getBean("MyFactoryBean");
    System.out.println(bean);

    打印出的bean为com.practice.bean.Person类,说明Person已被注册到容器中。

    那么怎么获取这个MyFactoryBean类组件呢,使用&符号,源码中已给出说明。

    /**
     * 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 = "&";

     Object bean = applicationContext.getBean("&MyFactoryBean");

    打印bean.getClass.Console显示class com.practice.bean.MyFactoryBean。

  • 相关阅读:
    【Flink系列十二】使用OpenResty 在InfluxDB协议层拦截Flink指标
    【Azkaban优化】防止IP变化导致频繁登录
    困扰多年的Quartz重复调度的问题,终于找到原因
    【Flink系列十一】FlinkSQL Gateway以及支持Kerberos多租户的实现思路
    【Flink系列十三】FlinkKafkaConnector KafkaSource FlinkKafkaConsumer没有上报指标
    IDEA项目结构出现 0% methods,0% lines covered up
    java去重 up
    svndown下来项目但是导入不了maven包,解决办法 up
    新型病毒加强勒索病毒预防 up
    java list 时间排序, up
  • 原文地址:https://www.cnblogs.com/demo-alen/p/13547234.html
Copyright © 2020-2023  润新知