本文内容记录一下@Configuration注解的使用以及它与xml文件是如何对应的。
自从spring3.0开始,@Configuration可以用于定义配置了,也就是替代了过去xml配置,被注解的类内部含有一个或多个Bean,这些方法会被AnnotationConfigApplicationContext或者AnnotationConfigWebApplicationContext加载扫描,并构建Bean从初始化spring容器,类似于加载xml文件ClassPathXmlApplicationContext类加载xml文件。
一、@Bean的使用:使用此注解,表示在容器中注册一个Bean,类型为方法返回值的类型,id默认为是方法名,也可以自行指定id,在xml中类似于一组标签,举个简单例子:
xml的使用
首先创建一个类并在xml中注册一个Bean,id为person,class写出全路径,并定义两个属性name和age,
在过去我们通过ClassPathXmlApplicationContext来加载xml文件,根据指定bean的id通过getBean(id)来获取到Bean,例如:
public class MainTes {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Person bean = (Person) applicationContext.getBean("person");
System.out.println("person:"+bean);
//打印信息:person:Person{name='张三', age='18'}
}
}
@Bean注解的使用:
我们需要自定义一个类@Configuration来指定为配置类等同于xml文件中的,我们在类中注册Bean
//配置类==配置文件
@Configuration //告诉spring这是一个配置类
public class MainConfig {
@Bean(name = "person") //在容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id,也可以自己指定name属性为id类型
public Person person(){
return new Person("李四","16");
}
}
通过AnnotationConfigApplicationContext类扫描加载
public class MainTes {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
//根据返回值类型来得到Bean
Person bean = applicationContext.getBean(Person.class);
//根据id来得到Bean
Person bean1 = (Person) applicationContext.getBean("person");
//获取bean的id,也就是@Bean(name="person")中name的值,没有的话就默认为方法名作为id。
String[] str = applicationContext.getBeanNamesForType(Person.class);
for (String st : str) {
System.out.println("str:" + st);
}
System.out.println("bean:" + bean);
System.out.println("bean1:" + bean1);
// 打印信息:
// str:person
// bean:Person{name='李四', age='16'}
// bean1:Person{name='李四', age='16'}
}
}
我们都能加载并得到容器中的Bean
也就是说
@Configuration等同于xml中的
@Bean等同于xml中的
二、包扫描组件:只要标注了@Controller、@Service、@Respository、@Component 都会被扫描到在xml的配置中是这样,一般我们在指定base-package的时候都是写包的根目录,因为它会自动扫描根目录 下所有的包,只要标注了以上四个注解的都会被扫描到。
在这我主要记录一下@ComponentScan的使用:
@ComponentScan等同于上面xml配置文件的扫描组件:会自动扫描包路径下面的所有@Controller、@Service、@Repository、@Component 的类
@ComponentScan里的属性:value指定扫描的包,includeFilters包含那些过滤,excludeFilters不包含那些过滤,useDefaultFilters默认的过滤规则是开启的,如果我们要自定义的话是要关闭的。其中@Filters是一个过滤器的接口。
value属性:点开spring定义的注解类ComponentScan我们可以发现value属性默认为一个String[]类型
value的值可以一般是扫描包名:
首先我分别创建一个dao,service,controller分别在三个不同包中,注意看下包名,我这为了方便观看,将三个类整合到了一起。
package dao;
import org.springframework.stereotype.Repository;
@Repository
public class TestDao {}
/*----------------------------------------------*/
package Controller;
import org.springframework.stereotype.Controller;
@Controller
public class TestController {}
/*----------------------------------------------*/
package service;
import org.springframework.stereotype.Service;
@Service
public class TestService {}
我这扫描Controller、dao,service注解
//配置类==配置文件
@Configuration //告诉spring这是一个配置类
//扫描策略
@ComponentScan(value = {"Controller","dao","service"}) //也可以根目录扫描的方式,会自动扫描目录下带有4个注解的包
public class MainConfig {}
public class AnnoTest {
@SuppressWarnings("resource")
@Test
public void test01(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] definition = applicationContext.getBeanDefinitionNames();
for(String name : definition){
System.out.println("name:"+name);
//在打印的信息中我们可以看到上方标注了@Controller @Service @Repository的类名
}
}
}
excludeFilters:过滤器,定义了过滤规则,相当于内的子标签主要的过滤规则为:
FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照给定的类型
FilterType.ASPECTJ:使用ASPECTJ表达式
FilterType.REGEX:使用正则
FilterType.CUSTOM:使用自定义规则
例如:type为按照注解类型,value中指定了不被扫描的注解名称,我们这样可以在扫描的时候跳过带有这两个注解的类。
//配置类==配置文件
@Configuration //告诉spring这是一个配置类
//扫描策略
@ComponentScan(value = {"Controller","dao","service"},excludeFilters ={
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class,Service.class}), //按照注解来过滤
}) //也可以根目录扫描的方式,会自动扫描目录下带有4个注解的包
public class MainConfig {
}
我们查看spring定义注解ComponentScan我们可以找到Filter,我们可以发现spring中默认是注解方式的过滤规则,点开FilterType我们能发现spring定义几种过滤规则。
includeFilters:与excludeFilters作用相反,扫描时只扫描的包,但是需要注意的是,使用这个的时候需要指定userDefaultFilters = false把默认扫描规则为false,因为默认的时true不会生效。
@ComponentScan(value = {"Controller","dao","service"},includeFilters ={
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class,Service.class}), //按照注解来过滤
},useDefaultFilters = false) //也可以根目录扫描的方式,会自动扫描目录下带有4个注解的包
public class MainConfig {
}
FilterType.CUSTOM:自定义扫描规则,这个稍微重要点。
我们需要自定义一个Filter实现TypeFilter并重写match方法,并根据方法返回的布尔类型为true或false来判断是否过滤。
例如:指定Filter类型为自定义类型,值为自己定义的一个类
//配置类==配置文件
@Configuration //告诉spring这是一个配置类
//扫描策略
@ComponentScan(value = {"Controller","dao","service"},excludeFilters ={
@ComponentScan.Filter(type = FilterType.CUSTOM,value = {MyFilter.class}) //由自定义的Filter返回的布尔值来过滤
})
public class MainConfig {
}
public class MyFilter implements TypeFilter {
/**
* @param metadataReader 读取到的当前正在扫描的类的信息
* @param metadataReaderFactory 获取其他任何类的信息
* @return
* @throws IOException
*/
@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);
if(className.contains("er")){
return true;
}
return false;
}
}
public class AnnoTest {
@SuppressWarnings("resource")
@Test
public void test01(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] definition = applicationContext.getBeanDefinitionNames();
for(String name : definition){
System.out.println("name:"+name);
}
}
}
打印信息:
---->Controller.TestController
---->dao.d.TesDao1
---->dao.d1.TesDao2
---->dao.TestDao
---->service.TestService
name:tesDao1
name:tesDao2
name:testDao
我们可以看到扫描的类有5个,但是只要标注了@Repository的没有被过滤,@Controller和@Service都被过滤掉了,因为他们包了"er"。
记录学习笔记算是强制让自己学习和鞭策自己,同时也希望能够帮助有需要的伙伴,对于笔记有什么错误的或者不足的希望大家能帮忙纠正一下。万分感谢!