1、通过注解指定容器和注册Bean
@Configuration public class MainConfig { @Bean public Person person(){ return new Person("lisi",12); } }
@Configuration注解的类可被Spring认定为容器类(说明Spring会自动扫描所有的类,然后将带有@Configuration注解的类视为容器类),@Bean注解的方法的返回值即为注册的Bean,Bean的id默认为方法名,id可通过@Bean注解的属性指定
public class MainTest { public static void main(String args[]){ // ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); // Person p = (Person) context.getBean("person"); // System.out.print(p); ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class); Person person = context.getBean(Person.class); System.out.print(person); } }
使用ApplicationContext的实现类加载bean的xml配置文件和加载配置类时都会在加载时就创建对象,但会有些不同:使用xml配置的方式会默认调用指定Class的无参构造器,属性的值是通过Setter方法注入的;而使用配置类时则会调用配置类中所有@Bean注解的方法,调用的构造器是在该方法中指明的。
2、通过注解指定容器类的扫描范围和扫描规则
@Configuration @ComponentScan(value = "com.bdm", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})}) public class MainConfig { @Bean public Person person() { return new Person("lisi", 12); } }
@Configuration @ComponentScan(value = "com.bdm", useDefaultFilters = false, includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})}) public class MainConfig { @Bean public Person person() { return new Person("lisi", 12); } }
@ComponentScan注解的value属性指定了扫描的包,表示此包中使用了@Controller、@Service、@Repository、@Component等注解的类会被纳入Spring容器的管理;excludeFilters属性表示该包中哪些类别的类不会被纳入Spring容器管理,它的属性值是一个数组;includeFilters属性表示指定的包中哪些类别的类会被纳入到Spring容器管理,注意要同时设置useDefaultFilters的属性为false;
JDK1.8之后一个容器类可以使用多次@ComponentScan注解,JDK1.8之前则可以使用@ComponentScans实现这个需求
@Configuration @ComponentScans(value = {@ComponentScan(value = "com.bdm", useDefaultFilters = false, includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})}), @ComponentScan(value = "com.bdm", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})})}) public class MainConfig { @Bean public Person person() { return new Person("lisi", 12); } }
该注解的value值是一个@ComponentScan数组
TypeFilter的值:
FilterType.ANNOTATION:指定注解注解的类
FilterType.ASSIGNABLE_TYPE:指定类型的类
FilterType.ASPECTJ:使用AspectJ表达式过滤
FilterType.REGEX:使用正则表达式过滤
FilterType.CUSTOM:自定义过滤规则
3、自定义过滤规则
自定义规则类需实现TypeFilter接口:
public class BdmTypeFilter implements TypeFilter{ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { //注解 AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); //路径 Resource resource = metadataReader.getResource(); //类名 ClassMetadata classMetadata = metadataReader.getClassMetadata(); String className = classMetadata.getClassName(); if(className.contains("action")) return true; MetadataReader metadataReader1 = metadataReaderFactory.getMetadataReader(""); return false; } }
MetadataReader:获取正被扫描的类的信息,包括该类的注解信息、路径信息、类名信息等
MetadataReaderFactory:获取MetadataReader
使用自定义过滤规则:type=FilterType.CUSTOM
@Configuration @ComponentScan(value="com.bdm",useDefaultFilters = false,includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {BdmTypeFilter.class})}) public class MainConfig { @Bean public Person person() { return new Person("lisi", 12); } }
则在指定包com.bdm及其子包下所有符合自定义规则(此处为类名中含有action字符串)的类将被纳入Spring容器管理
由此可以看出Spring容器在通过扫描的方式决定将哪些类纳入容器管理前会先扫描指定包下所有的类,再看这些类是否符合被纳入管理的条件(有没有指定注解、类名是否符合条件、路径是否符合条件等),所以如果在一个包下需要被Spring容器管理的类所占的比例比较小时最好不要使用扫描包的方式,而使用@Bean注解的方式性能会更好些,因为减少了遍历