Spring注解驱动开发学习总结1:组件注册之@Configuration、@Bean、@ComponentScan详解

1、使用@Configuration、@Bean给容器添加组件

可以使用@Configuration、@Bean给容器添加组件,具体步骤如下:

1.1 新建maven工程:spring-annotation

如下,新建maven工程spring-annotation:
在这里插入图片描述

1.2 pom文件添加依赖spring核心容器依赖

Pom文件添加spring核心容器的依赖spring-context,这里选择的是4.3.12版本
在这里插入图片描述

1.3 添加Person类

新建com.example.bean包,包下新建一个Person类:
在这里插入图片描述

1.4 添加配置类MainConfig

添加配置类MainConfig。
1)MainConfig类上添加@Configuration注解,spring会将标注该注解的类自动注入到容器中
2)给配置类中的方法添加@Bean注解。@Bean注解会给容器注册一个bean,类型为返回值的类型;id默认使用方法名作为id,也可以用name指定,比如@Bean(“person”)

package com.example.config;

import com.example.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

// 配置类就等同于以前的配置文件beans.xml
@Configuration
public class MainConfig {
    // @Bean注解会给容器注册一个bean。
    // 类型为返回值的类型;id默认使用方法名作为id,也可以用name指定,比如@Bean("person")
    @Bean
    public Person person() {
        return new Person("lisi", 20);
    }
}

1.5 运行main方法进行测试

添加main方法,送注解配置容器中获取Person类型的bean,以及获取它的名字:

package com.example;

import com.example.bean.Person;
import com.example.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        Person bean = applicationContext.getBean(Person.class);
        System.out.println("获取Person类型的bean为: " + bean);

        String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
        for (String name : beanNamesForType) {
            System.out.println("Person bean的名字: " + name);
        }
    }
}

运行MainTest,可以得到结果:
在这里插入图片描述

2、使用@ComponentScan自动扫描组件

@ComponentScan可以标注包扫描的位置,包扫描的路径下,所有标注了@Controller, @Service, @Repository, @Component 注解的类都会被自动注册到spring容器中

2.1 新建BookController, BookService, BookDao

新建
com/example/controller/BookController.java,
com/example/service/BookService.java,
com/example/dao/BookDao.java,
并添加对应的注解:
在这里插入图片描述

2.2 配置文件新增包扫描路径

配置文件新增包扫描路径:com.example,这样com.example路径下,所有标注了@Controller, @Service, @Repository, @Component 注解的类都会被自动注册到spring容器中。
在这里插入图片描述

2.3 测试@ComponentScan自动扫描组件功能

1)首先在pom文件中添加junit依赖,选择的版本是4.12
在这里插入图片描述
2)新建测试类src/test/java/com/example/test/IocTest.java,添加测试testComponentScan方法,看看刚刚添加的BookController,BookService, BookDao组件是否自动导入了容器中:

package com.example.test;

import com.example.config.MainConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IocTest {
    @SuppressWarnings("resource")
    @Test
    public void testComponentScan() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName:beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}

返回结果如下:
在这里插入图片描述

可以看到,刚刚标注了注解的BookController,BookService, BookDao, 这3个都已经自动导入了容器。
同时标注了@Configuration注解的配置类mainConfig,也自动导入了容器。
配置类mainConfig标注了@Bean方法的返回类型为Person,id为person的bean页自动导入了容器。

3、使用@ComponentScan指定扫描规则

1、使用@ComponentScan可以自动注入默认组件外,还可以自定义扫描规则
@ComponentScan中有以下3个参数

boolean useDefaultFilters() default true;
ComponentScan.Filter[] includeFilters() default {};
ComponentScan.Filter[] excludeFilters() default {};

1)配置excludeFilters参数,可以排除指定的组件,不导入容器;
2)配置includeFilters参数,可以只导入指定的组件到容器中,要求同时要将useDefaultFilters改为false

2、当配置includeFilters参数时,需要填写的是ComponentScan.Filter注解类型的数组。
ComponentScan.Filter中有一个参数type,表示要指定的组件的类型,它的参数类型是FIlterType

@interface Filter {
		FilterType type() default FilterType.ANNOTATION;
	}

FIlterType可填以下5种参数。其中ANNOTATION表示指定注解,ASSIGNABLE_TYPE表示指定类型。

public enum FilterType {
	ANNOTATION,
	ASSIGNABLE_TYPE,
	ASPECTJ,
	REGEX,
	CUSTOM
}

以下以只导入bookController, bookService组件进行举例,其中的type参数,选择了常用的:ANNOTATION和ASSIGNABLE_TYPE进行举例。

3.1 包扫描注解中指定扫描组件

在@ComponentScan包扫描注解中,新增includeFilters参数,该参数是ComponentScan.Filter的数组格式。

1)新增一个类型为ANNOTATION的Filter,表示指定扫描的类型是注解类型;参数value,填的是Controller.class,表示只扫描controller注解的组件。
2)新增一个类型为ASSIGNABLE_TYPE的Filter,表示类型是指定类名;参数value,填的是BookService.class,表示只扫描BookService类的组件。
同时,配置includeFilters参数时,需要将ComponentScan默认的参数useDefaultFilters改为false。

package com.example.config;

import com.example.bean.Person;
import com.example.service.BookService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

// 配置类就等同于以前的配置文件beans.xml
@Configuration
@ComponentScan(value = "com.example",
        useDefaultFilters = false,
        includeFilters = {
                @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class),
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = BookService.class)
        }
)
public class MainConfig {
    // @Bean注解会给容器注册一个bean。
    // 类型为返回值的类型;id默认使用方法名作为id,也可以用name指定,比如@Bean("person")
    @Bean
    public Person person() {
        return new Person("lisi", 20);
    }
}

3.2 测试@ComponentScan指定扫描规则功能

此时再运行testComponentScan,得到下图结果:
在这里插入图片描述

此时可以看到:
bookDao组件没有被注入容器,只有bookController,bookService注入了容器。
而mainConfig依然是通过@Configuration注解自动导入了容器;同理,person也还是通过@Bean注解自动导入了容器。

4、自定义TypeFilter指定过滤规则

1、上面提到了,FIlterType可填以下5种参数。
上一节中用到了,ANNOTATION和ASSIGNABLE_TYPE。本小节使用CUSTOM来进行自定义过滤规则。

public enum FilterType {
	ANNOTATION,
	ASSIGNABLE_TYPE,
	ASPECTJ,
	REGEX,
	// Filter candidates using a given custom org.springframework.core.type.filter.TypeFilter implementation.
	CUSTOM
}

通过注释可以看到,使用CUSTOM,需要提供一个自定义的org.springframework.core.type.filter.TypeFilter实现类。
因此我们首先需要构建一个自定义的TypeFIlter实现类。
2、可以先查看下TypeFIlter类,看下我们要实现什么方法?
可以看到该接口只有一个方法,这个方法就是用来判断该类是否满足过滤条件。
1)metadataReader:当前类的元信息(比如注解、类变量、类方法、类路径等)
2)metadataReaderFactory:当前类的元信息工厂,还包含父类及接口信息

public interface TypeFilter {
	/**
	 * Determine whether this filter matches for the class described by the given metadata.
	 * @param metadataReader the metadata reader for the target class
	 * @param metadataReaderFactory a factory for obtaining metadata readers for other classes (such as superclasses and interfaces)
	 * @return whether this filter matches
	 */
	boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException;
}

现在逻辑应该就很清楚了,我们构建一个自定义的TypeFilter实现类,然后加入到@ComponentScan.Filter参数中即可。

4.1 新建自定义的TypeFilter实现类

新建一个自定义的org.springframework.core.type.filter.TypeFilter实现类:com/example/filter/MyTypeFilter.java。

由于bookController, bookService, bookDao中,bookController和bookService的名字中都包含字符串"er",因此下面举例的过滤规则就是,如果该类的名字中包含字符串"er",那么该类就可以注入到容器中。

同时,还添加了日志,显示所有需要进入该方法进行过滤的bean的名称。

package com.example.filter;

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 MyTypeFilter implements TypeFilter {
    @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("er")) {
            System.out.println("	当前类满足自定义过滤规则!!!");
            return true;
        }
        return false;
    }
}

4.1 配置类改为自定义过滤规则

配置类改为自定义过滤规则:@ComponentScan.Filter(type = FilterType.CUSTOM, value = MyTypeFilter.class)

package com.example.config;

import com.example.bean.Person;
import com.example.filter.MyTypeFilter;
import com.example.service.BookService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

// 配置类就等同于以前的配置文件beans.xml
@Configuration
@ComponentScan(value = "com.example",
        useDefaultFilters = false,
        includeFilters = {
//                @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class),
//                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = BookService.class)
                @ComponentScan.Filter(type = FilterType.CUSTOM, value = MyTypeFilter.class)
        }
)
public class MainConfig {
    // @Bean注解会给容器注册一个bean。
    // 类型为返回值的类型;id默认使用方法名作为id,也可以用name指定,比如@Bean("person")
    @Bean
    public Person person() {
        return new Person("lisi", 20);
    }
}

4.3 测试自定义TypeFilter指定过滤规则的功能

测试结果如下图,可以看到bookController和bookService确实都注入了容器,而bookDao由于字符串中未包含“er”,因此不满足自定义过滤规则。
在这里插入图片描述

5、本篇小结

1、spring会将标注了 @Configuration 注解的类自动注入到容器中,该类就会成为一个配置类。
  1.1 给配置类中的方法添加@Bean注解。@Bean注解会给容器注册一个bean,类型为返回值的类型;id默认使用方法名作为id,也可以用name指定,比如@Bean(“id名称”)。
  1.2 配置类上可以添加@ComponentScan注解,该注解可以指出包扫描的位置。只要是在包扫描的路径下,所有标注了@Controller, @Service, @Repository, @Component 注解的类都会被自动注册到spring容器中。
    1.2.1 @ComponentScan注解可以配置excludeFilters参数,该参数可以排除指定的组件,这些组件不导入容器;
    1.2.2 @ComponentScan注解可以配置includeFilters参数,该参数只导入指定的组件到容器中,要求同时要将useDefaultFilters改为false;
    1.2.3 具体自定义规律规则可以参考上面详细的步骤介绍。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值