Spring源码笔记1
1、Spring框架功能整体介绍
1.1 Spring Core Container
- Core和Beans模块是框架的基础部分,提供了IOC和DI的特性。这里的基础概念是BeanFactory,他提供对Factory模式的经典实现来实现程序“单例模式”的需要,并真正允许你从程序逻辑中分离出依赖关系和配置。
- Context:处理BeanFactory,一般是用ApplicationContext。他构建与Core和Beans模块的基础之上。Context模块集成了Beans的特性,并未Spring核心提供了大量的扩展,添加了对国际化、事件传播、资源加载和对Context的透明创建的支持。也就是说,Context也是一个beanFactory,但是进行了功能的扩展。
- BeanFactory和Application的本质区别是,BeanFactory是延迟加载的,ApplicationContext是非延迟加载的。BeanFactory在启动的时候不会去实例化Bean,中有从容器中拿Bean的时候才会去实例化,ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化;
- Expression Language:表达式语言,可以设置属性的值,一般用的比较少。
1.2 Spring Data Access/Integration(spring数据访问)
- JDBC:JdbcTemplate,提供了一个JDBC的抽象层,可以消除冗长的JDBC编码。
- ORM:流行的对象-关系映射:如JPA、JDO、Hibernate、iBatis等,提供一个交互层,利用ORM封装包。
- OXM 模块提供了一个对 ObjecνXML 映射实现的抽象层,Object/XML 映射实现包括 JAXB、 Castor、 XMLBeans、 JiBX 和 XStrearn 。
- Transaction支持编程和声明性的事务管理,这些事务类必须实现特定的接口,并且对所有的 POJO 都适用 。
1.3 SpringWeb
- Web 模块:提供了基础的面向 Web 的集成特性c 例如,多文件上传、使用 servlet listeners 初始化 IoC 容器以及一个面向 Web 的应用上下文。 它还包含 Spring 远程支持中 Web 的相关部分。
1.4 Spring Aop
- Aspects 模块提供了对 AspectJ 的集成支持。
2、Spring IOC容器底层的注解使用
2.1 把bean加入IOC容器,并获取
@Configuration
public class MainConfig {
@Bean//默认是当实例的
public TestHandler testHandler(){
return new TestHandler();
}
}
@Bean的形式注入,bean的默认名称是方法名,若是@Bean(value = “bean的名称”),那么bean的名称叫就是指定的。
去容器龚获得bean的信息:传入配置类
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
Object handler = context.getBean("testHandler");
2.2@CompentScan包扫描
@Configuration
@ComponentScan(basePackages = {"com.panzh.compentScan"});
public class MainConfig {
}
这里的basePackages是一个数组,也就是可以设置多个值,用大括号进行包裹
excludeFilters,过滤器用法:
@Configuration
@ComponentScan(basePackages = {"com.panzh.compentScan"},excludeFilters = {
//过滤掉service注解的类,即该类不背扫描;
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Service.class),
//过滤掉特定了类,即可分配类型的
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = TestHandler.class)
})
public class MainConfig {
}
即可过滤掉我们需要过滤的类。
includeFilters的用法,若是使用这种方法,需要把useDefaultFilters设置为false,默认为true,表示扫描全部。
@Configuration
@ComponentScan(basePackages = {"com.panzh.compentScan"},includeFilters = {
//过滤掉service注解的类,即该类不背扫描;
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Service.class),
//过滤掉特定了类,即可分配类型的
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = TestHandler.class)
},useDefaultFilters = false)
public class MainConfig {
}
@ComponentScan.Filter Type的类型
- 注解形式:FilterType.ANNOTATION; @Controller、@Service。。
- 指定类型:FilterType.ASSIGNABLE_TYPE; 我们特定的类
- aspectj类型,不常用 FilterType.ASPECTJ
- 正则表达式的类型 FilterType.REGEX(不常用)
- 自定义类型 FilterType.CUSTOM;
public enum FilterType {
//注解形式 比如@Controller @Service @Repository @Compent
ANNOTATION,
//指定的类型
ASSIGNABLE_TYPE,
//aspectJ形式的
ASPECTJ,
//正则表达式的
REGEX,
//自定义的
CUSTOM
}
自定义Filter。我们需要写一个类集成TypeFilter,注意名称,不要写错了。
//自定义一个过滤器,也就是FilterType.CUSTOM
public class TulingFilterType implements TypeFilter {
//方法返回true即加载到ioc容器,返回false则不包含到ioc容器;
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获得类的元数据
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//也就定义了只有包含了“Handler”字符串的类可以被ico容器进行扫描;
if (classMetadata.getClassName().contains("Handler")){
return true;
}
return false;
}
}
对每一个加入容器的主键进行过滤判断。启动的方式,跟上面几种类型是相同的。
3、Bean的作用域对象
在不指定@Scope的情况下,所有的bean都是单实例的bean,而且是饿汉加载(容器启动实例就创建 好了)
@Bean
public Person person() {
return new Person();
}
使用@Scope属性可以设置作用域方法。如果Scope的属性为prototype,表示为多实例的,并且为懒汉加载模式((IOC容器启动的时候,并不会创建对象,而是 在第一次使用的时候才会创建)
@Bean
@Scope(value = "prototype")
public Person person() {
return new Person();
}
- singleton:单实例(默认)
- prototype:多实例,懒加载
- request:同义词请求
- session:同一个会话级别
@bean的懒加载注解@Lazy(主要针对单实例的bean容器启动的时候,不创建对象,在第一次使用的时候创建对象)
@Bean
@Lazy
public Person person() {
return new Person();
}
@Conditional条件判断。如果返回true,表示条件成立,放入ioc容器,不成立就不放进ioc 容器。
我们自己写一个类实现Condition接口
public class TulingCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
if (conditionContext.getBeanFactory().containsBean("123")){
return true;
}
return false;
}
}
@Configuration
public class MainConfig {
@Bean//默认是当实例的
@Conditional(TulingCondition.class)//必须符合条件,才会被加载进ioc容器
public Cat cat(){
return new Cat();
}
}
往IOC容器中添加组件的方法:
- @CompentScan + @Controller @Service @Respository @compent
- 通过@Bean的方式来导入组件(适用于第三方主键的类)
- 通过@Import来导入组件(导入的主键的id为全类名路径)
@Configuration
@Import(value = {Person.class, Car.class})
public class MainConfig { }
- 通过Import的ImportSelector类实现主键的导入。
public class TulingImportSelector implements ImportSelector {
//可以获取导入类的注解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.tuling.testimport.compent.Dog"};
} }
@Configuration
@Import(value = {Person.class, Car.class, TulingImportSelector.class})
public class MainConfig { }
通过@Import的 ImportBeanDefinitionRegister导入组件 (可以指定bean的名称),导入到bean定义的注册器。
public class TulingBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//创建一个bean定义对象
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Cat.class);
//把bean定义对象导入到容器中
registry.registerBeanDefinition("cat",rootBeanDefinition);
} }
@Configuration
@Import(value = {Person.class, Car.class, TulingImportSelector.class, TulingBeanDefinitionRegister.class})
public class MainConfig {}
通过实现Factory接口来实现注册主键。
4、bean的生命周期
bean的创建->初始化->销毁方法
1. 由容器管理bean的生命周期,我们可以指定bean 的初始化方法和销毁方法
@Configuration public class MainConfig {
//指定了bean的生命周期的初始化方法和销毁方法.
@Bean(initMethod = "init",destroyMethod = "destroy")
public Car car() {
return new Car();
}
}
针对单实例bean的话,容器启动的时候,bean的对象就创建了,而且容器销毁的时候,也会调用Bean的销毁方法
针对多实例bean的话,容器启动的时候,bean是不会被创建的而是在获取bean的时候被创建,而且bean的销毁不受 IOC容器的管理.
2. InitializingBean和DisposableBean 的二个接口实现bean的初始化以及销毁方法
@Component public class Person implements InitializingBean,DisposableBean {
public Person() {
System.out.println("Person的构造方法");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean的destroy()方法 ");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean的 afterPropertiesSet方法");
}
}
③:通过JSR250规范 提供的注解@PostConstruct 和@ProDestory标注的方法
@Component public class Book {
public Book() {
System.out.println("book 的构造方法");
}
//构造之后调用
@PostConstruct
public void init() {
System.out.println("book 的PostConstruct标志的方法");
}
//销毁之前调用
@PreDestroy
public void destory() {
System.out.println("book 的PreDestory标注的方法");
}
}
4:通过Spring的BeanPostProcessor的 bean的后置处理器会拦截所有bean创建过程
postProcessBeforeInitialization 在init方法之前调用
postProcessAfterInitialization 在init方法之后调用
5.通过@Value + @PropertySource来给组件赋值
自动装配:先根据类型进行查找,如果有多个,就按照属性名称来查找。
可以添加注解,按照指定的名字进行查找
@Qualifier("tulingDao") //指定按照tulingDao的名称来进行查找
如果没有的话,我们的ioc容器会报错,我们为了不报错,可以加上这个注解:
@Autowired(required = false)
另外@Autowired可以加在set方法上,表示到ioc容器中寻找合适的参数进行注入。亦可以标注在构造方法上,告诉ioc容器按照这个构造方法注入,如果只有一个构造方法,可以不标注。
当我们的组件需要使用到ioc底层的组件的时候,我们可以实现xxxAware接口来实现:
@Component public class TulingCompent implements ApplicationContextAware,BeanNameAware {
private ApplicationContext applicationContext;
@Override
public void setBeanName(String name) {
System.out.println("current bean name is :【"+name+"】");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}