Spring注解详解之组件注册(@Configuration,@Bean,@ComponentScan)

Spring注解详解之组件注册(@Configuration,@Bean,@ComponentScan)

在spring源码中,会有很多注解的运用,而且,在spring boot和spring could运用和学习中,很多时候也需要查看源码,对spring的注解的了解也是不可或缺的,就准备做个spring注解的系列,记录一些重要注解的使用,以便日后查看和学习

1.@Configuration:

@Target({ElementType.TYPE})//使用在类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component//是一个组件,
public @interface Configuration {
}

从上面的源码,可以看出该注解用于类上,并且是IOC容器的一个组件,注明该注解标注的类是一个配置类,类似于下面的xml配置文件的作用,该注解类的内部包含一个或多个@Bean注解的方法,这些方法会被 AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器

注意

1. @Configuration不可以是final类型; 
2.  @Configuration不可以是匿名类; 
<?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">
    <bean id="person" class="com.ming.bean.Person">
        <property name="id" value="123"></property>
        <property name="name" value="zhangsan"></property>
    </bean>
</beans>

2.@Bean

从下面源码,该注解使用在注解方法和注解的定义,标记在方法上,方法的返回值相当于向IOC容器中注入一个bean,返回值相当于上面xml文件中bean标签的class属性,方法的名称相当于bean标签的id属性,@bean注解中有一个name属性来指定bean的id;

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documentedpublic 
@interface Bean {
}

3.举例

首先定义一个配置类

@Configuration//告知spring是一个配置类
public class MyConfig { 
    //向IOC容器中注册一个bean,类型为返回值的类型,id默认使用方法名子    
    @Bean("Person")//通过name属性来指定bean的id    
    public Person person(){        
    	return new Person(12,"lisi");    
    }
}

测试方法

@Test
public void testAnno(){
    //AnnotationConfigApplicationContext扫描配置类,指定配置类
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);    
    Person bean = applicationContext.getBean(Person.class);    
    System.out.println(bean);    
    //从IOC容器中通过类型获取bean的名字    
    String[] names = applicationContext.getBeanNamesForType(Person.class);    
    for (String name : names) {        
        System.out.println(name);    
    }
}
//输出结果
Person{id=12, name='lisi'}
Person

4.@ComponentScan:自动扫描和指定扫描规则

该注解的作用就是,根据定义的扫描路径, 把符合扫描规则的类装配到spring容器中 , 相当于之前xml配置文件中的 context:component-scan标签,

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    @AliasFor("basePackages")
    String[] value() default {};
    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

    String resourcePattern() default "**/*.class";

    boolean useDefaultFilters() default true;

    ComponentScan.Filter[] includeFilters() default {};

    ComponentScan.Filter[] excludeFilters() default {};

    boolean lazyInit() default false;

    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
        FilterType type() default FilterType.ANNOTATION;

        @AliasFor("classes")
        Class<?>[] value() default {};

        @AliasFor("value")
        Class<?>[] classes() default {};

        String[] pattern() default {};
    }
}

basePackages与value: 用于指定包的路径,进行扫描

basePackageClasses: 用于指定某个类的包的路径进行扫描

nameGenerator: bean的名称的生成器

useDefaultFilters: 是否开启对@Component,@Repository,@Service,@Controller的类进行检测

includeFilters: 包含的过滤条件 (注意:在使用这个时,需要将useDefaultFilters属性设置为false,才能生效默认是true)

excludeFilters: 排除的过滤条件,用法和includeFilters一样

	FilterType.ANNOTATION:按照注解过滤
    FilterType.ASSIGNABLE_TYPE:按照给定的类型
    FilterType.ASPECTJ:使用ASPECTJ表达式
    FilterType.REGEX:正则
    FilterType.CUSTOM:自定义规则        

创建下面的测试工程,controller,service,dao都分别加注解@Repository,@Service,@Controller,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-76LUa35Y-1583330609745)(D:\soft\typora\笔记\spring注解详解\images\1583307278841.png)]

修改配置类,通过value属性指定扫描的包, includeFilters属性指定过滤条件(包括@Controller和@Service)

//告知spring是一个配置类
@Configuration
/*
value:指定扫描的包,
excludeFilters:Filter[]扫描时按指定的规则进行排除
includeFilters:Filter[]扫描时按指定的规则进行包含(注意:在使用这个时,需要将useDefaultFilters属性设置为false,默认是true才能生效)
 */
@ComponentScan(value ="com.ming",
        useDefaultFilters=false,
        //按照注解类型指定controller,按照给定类型指service
        includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class},ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {UserServiceImpl.class})))
public class MyConfig {

    //向IOC容器中注册一个bean,类型为返回值的类型,id默认使用方法名子
    @Bean("Person")//通过name属性来指定bean的id
    public Person person(){
        return new Person(12,"lisi");
    }
}

测试方法

@Test
public void testAnno(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
    //获取容器中bean的名字
    String[] names = applicationContext.getBeanDefinitionNames();
    for (String name : names) {
        System.out.println(name);
    }
}

//输出结果,上面的4个是spring自己注入的组件
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
myConfig //@Configuration注解包含@Component,也是容器中的一个组件
userController
userServiceImpl 
Person //controller,service,是配置类中指定包含的,person是@Bean("Person")注入的

增加自定义的过滤类MyTypeFilter,来验证 FilterType.CUSTOM:自定义规则

//自定义类型过滤器,需要继承TypeFilter接口
public class MyTypeFilter implements TypeFilter {
    /*
    MetadataReader:读取到正在扫描的类的信息
    MetadataReaderFactory:可以获取到其他类的信息
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //获取当前类的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前类的资源(类路径)
        Resource resource = metadataReader.getResource();
        //获取当前正在扫描类的类的信息(实现接口等)
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        String className = classMetadata.getClassName();
        //输出扫描类的名字
        System.out.println("---->"+className);
        if(className.contains("service")){
            return true;//不过滤类名中包含service的组件
        }
        return false;
    }
}

验证测试类:

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

//输出结果,指定的扫描路径是com.ming,该包路径下的每一个类都会被MyTypeFilter过滤,可以看出扫描的这些类中只有service类没有被过滤掉,其他的都被过滤掉了,从IOC容器中获取不到
---->com.ming.SpringTest
---->com.ming.bean.Person
---->com.ming.config.MyTypeFilter
---->com.ming.controller.UserController
---->com.ming.dao.UserRepositoryImpl
---->com.ming.service.UserServiceImpl
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
myConfig
userServiceImpl
person
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值