时隔一年多,在掌握了Spring、SpringBoot、SpringCloud之后
我再次回头,重新学习Spring框架
回顾以前的内容:
组件注册:
最早使用,是XML的方式:
导入依赖:
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.3.12.RELEASE</version></dependency>
一个实体类:


package org.dreamtech.bean;public class Person {private String name;private Integer age;@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}public Person() {}public Person(String name, Integer age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;} }
XML:
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="person" class="org.dreamtech.bean.Person"><property name="name" value="张三"/><property name="age" value="18"/></bean> </beans>
测试类:
package org.dreamtech;import org.dreamtech.bean.Person; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class MainTest {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");Person bean = (Person) applicationContext.getBean("person");System.out.println(bean);} }
打印:
Person{name='张三', age=18}
完成
后来,开始使用注解方式,不需要XML配置
写一个配置类:
package org.dreamtech.config;import org.dreamtech.bean.Person; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;/*** 配置类*/ @Configuration public class MainConfig {@Beanpublic Person person(){return new Person("李四",20);}}
测试类:
package org.dreamtech;import org.dreamtech.bean.Person; import org.dreamtech.config.MainConfig; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class MainTest {public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);Person bean = applicationContext.getBean(Person.class);System.out.println(bean);} }
打印:
Person{name='李四', age=20}
扫描Bean:扫描@Controller@Service等
在XML中的方式是:
<context:component-scan base-package="org.dreamtech.bean"/>
注解方式是:
@ComponentScan(value = "org.dreamtech")
根据我们开发常用的架构,新建类:
package org.dreamtech.controller;import org.springframework.stereotype.Controller;@Controller public class BookController { }
package org.dreamtech.service;import org.springframework.stereotype.Service;@Service public class BookService { }
package org.dreamtech.dao;import org.springframework.stereotype.Repository;@Repository public class BookDao { }
然后查看Spring容器中所有的Bean:
package org.dreamtech.test;import org.dreamtech.config.MainConfig; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class IOCTest {@Testpublic void test() {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);String[] definitionNames = applicationContext.getBeanDefinitionNames();for (String name : definitionNames) {System.out.println(name);}} }
打印如下:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
bookDao
bookService
person
在扫描的时候,可以进行过滤,指定哪些需要扫描,哪些不需要:
比如我想排除Controller注解类的扫描:
@ComponentScan(value = "org.dreamtech", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}) })
测试成功
比如我只想扫描Controller注解类:
@ComponentScan(value = "org.dreamtech", includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}) })
测试失败
原因:需要禁用掉默认扫描规则
@ComponentScan(value = "org.dreamtech", includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})},useDefaultFilters = false)
以上是按照注解进行过滤的,实际上还有很多其他的方式,但是不经常使用
比如:指定类、AspectJ表达式、正则表达式、自定义
排除指定类(包括子类等)
@ComponentScan(value = "org.dreamtech", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class})})
值得关注的是自定义规则:需要实现一个TypeFilter接口
我自定义只能扫描到包含字符串"er"的类
package org.dreamtech.config;import org.dreamtech.bean.Person; import org.dreamtech.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.core.type.filter.TypeFilter; import org.springframework.stereotype.Controller;/*** 配置类*/ @Configuration @ComponentScan(value = "org.dreamtech", includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})},useDefaultFilters = false ) public class MainConfig {@Beanpublic Person person() {return new Person("李四", 20);}}
package org.dreamtech.config;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 {/*** 实现** @param metadataReader 当前正在扫描的类* @param metadataReaderFactory 可以获取到其他任何类的信息* @return 是否匹配* @throws IOException 异常*/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;} }
测试后打印:
[-------------org.dreamtech.bean.Person-------------] [-------------org.dreamtech.config.MyTypeFilter-------------] [-------------org.dreamtech.controller.BookController-------------] [-------------org.dreamtech.dao.BookDao-------------] [-------------org.dreamtech.MainTest-------------] [-------------org.dreamtech.service.BookService-------------] [-------------org.dreamtech.test.IOCTest-------------] org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig person myTypeFilter bookController bookService