一步步读spring
gradle编译spring5.0x源码
- 下载gradle4.4.1.bin.zip,解压再配置环境变量
-
https://services.gradle.org/distributions/
- 下载spring5.0x,再用gradle idea进行源码编译(如果是eclipse开发工具,可用gradle eclipse -x :eclipse)
-
https://github.com/spring-projects/spring-framework/tree/5.0.x
- 等待编译完毕,用idea打开即可
spring3.0中各个模块的作用
aop--------------------Spring的面向切面编程,提供AOP(面向切面编程)实现
aspects---------------Spring提供对AspectJ框架的整合\
beans------------------SpringIoC(依赖注入)的基础实现
context.support--------Spring-context的扩展支持,用于MVC方面
context---------------Spring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持,如邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及各种视图层框架的封装等
core-------------------Spring3.0的核心工具包
expression-------------Spring表达式语言
instrument.tomcat------Spring3.0对Tomcat的连接池的集成
instrument------------Spring3.0对服务器的代理接口
jdbc-------------------对JDBC的简单封装
jms--------------------为简化JMS API的使用而作的简单封装
orm--------------------整合第三方的ORM框架,如hibernate,ibatis,jdo,以及 spring的JPA实现
oxm--------------------Spring 对Object/XMl的映射支持,可以让Java与XML之间来回切换
test--------------------对Junit等测试框架的简单封装
transaction-------------为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理
web.portlet-------------SpringMVC的增强
web.servlet-------------对JEE6.0 Servlet3.0的支持
web.struts--------------整合Struts的时候的支持
web--------------------SpringWeb下的工具包
原文链接:https://blog.csdn.net/mixika99/article/details/72723374
beanFactory
选择此处作为入口
org.springframework.context.support;
ClassPathXmlApplicationContext
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
private Resource[] configResources;
protected Resource[] getConfigResources() {
return this.configResources;
}
public ClassPathXmlApplicationContext(.........各种构造方法)
其继承关系的uml图如下:
beanFactory的方法解释
// todo 从IOC中拿到单例
Object getBean(String name) throws BeansException;
// todo 判断ioc中有bean吗
boolean containsBean(String name);
// todo 是否单例 如果isSingleton,那么从容器中每次调用getBean方法,获取的都是同一个对象的实例,---单例模式
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// todo 是否单例 如果isSingleton,那么从容器中每次调用getBean方法,获取的都是同一个对象的实例,---单例模式
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// todo 如果isPrototype,那么每次(直接或间接)调用getBean方法,获取的都是一个新创建的对象。---原型模式
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
// todo 获得bean的class类型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// todo 获得bean的别名
String[] getAliases(String name);
ioc容器初始化的三个步骤
-
定位 (找到下xml文件在哪里)
-
加载
之后会使用dom4j解析,将xml解析结果保存成BeanDefination,进而存在内存中 -
注册
使用抽象工厂,根据BeanDefination的内容去生产了----只是说明了bean,调用bean才会初始化bean
//
工厂是标准化输出产品,ioc就是hash map
调用getBean/lazy-init为true是会触发bean的初始化
DI依赖注入
spting是使用map形式创建的单例
package org.springframework.beans.factory.support
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly){}
spring中如果不声明bean的scope,则默认都是单例的
spring AOP
切面是有n个具有共同点的bean组成的集合
com.service.impl.* 就是一个切面
某个bean的某个方法 ------------切入点
一个包是一个切面,一个对象的方法是一个切入点,目标对象,被代理对象,连接点是调用方法时的规则,切面是大规则,连接点是小规则(详细规则),满足连接点规则,就会触发通知(调用代理的代码)。
IOC入口
AnnotationConfigApplicationContext 通过注解初始化spring环境
ClassPathXmlApplicationContext 通过xml初始化spring环境
public class AnnotationConfigApplicationContext extends GenericApplicationContext {
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
//this.beanDefinitionMap.put(beanName,beanDefination) 将annotatedClasses转beanDefination再装入map
register(annotatedClasses);
//最重要的方法,没有之一
refresh();
}
}
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
public GenericApplicationContext() {
//spring工厂代码的核心实现类
this.beanFactory = new DefaultListableBeanFactory();
this.beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
}
}
refresh()方法:
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//完成类的扫描,并处理@ImportResource("com.xxx")
//@import(xxx.class) @MapperScan
//scan ----> put map ----> 执行 invokeBeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//真正new 对象,需要去new 的单例
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
}
}
这个finishBeanFactoryInitialization()方法里的
// Instantiate all remaining (non-lazy-init) singletons. 实例化对象,之前是先处理spring核心的对象
beanFactory.preInstantiateSingletons();
ctrl+alt+B 我们进到 它的具体实现上来,看它是整么实现的
断点调试设置成:只有当beanName.equals(“c”)才进入循环体
//拿到map里的所有key
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
//符合规则的,就是加了注解的,可能需要实例化的bean,已完成扫描。。。。。
//单例是缓存到map中的,而原型是不需要缓存的。因有lazy/scope ,所以这里是可能需要
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
//相当于beanDefinitionMap.get(beanName)从map里拿到所有的bean
//autowire是处理注解开发
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
一个xml中的或者类上的注解@Component,Scope,这些信息都会对应一个beanDefination,类名的小写是key,类所对应的beanDefination是value(相当能记录bean的更多信息的Class)
spring遵循开闭原则。提供了许多的方法,供外界访问(你可以和spring一起来共同完成这个过程--------只需要你的类实现BeanFactoryPostProcessor接口就可以参与beanFactory构建bean的过程中来,和spring一起工作,修改beanFactory,可以对map中选中的要new的东西进行偷梁换柱)
测试类
public class Test {
public static void main(String args[]){
AnnotationConfigApplicationContext
annotationConfigApplicationContext
=new AnnotationConfigApplicationContext(Appconfig.class);
/* for (City){
RootBeanDefinition beanDefinition=new RootBeanDefinition();
beanDefinition.setBeanClassName("city");
beanDefinition.setBeanClass(CityService.class);
beanDefinition.setScope("prototype"); //这里设置bean的类型是原型 模式
beanDefinition.setLazyInit(true);
........
map.put("city",beanDefinition);
//AnnotationConfigApplicationContext代码上这就是上下文
//初始spring的时候,这些组件(beanDefination,map)加在一起维持spring的正常工作,就叫上下文
}*/
// File("d:\\com\\xxx")
// List list=file.list();
// for(singleName:listName){
// class.forName("singleName")
// }
scan —>map.put()----->beanFactoryProcessor()处理
你得告知spring一个起点类,指定要扫描那些东西,才开始扫描,在起点类中加@component是然并卵的。起点类都没有,spring不知从何扫描起。
spring在未执行beanFactoryProcesser之前,就会放7个创世纪(spring用来开天劈地的 类)在beanMap里面
spring环境:defaultbeanFactory(bean工厂),beanFatoryPostProcessor(后置处理器),singlePool(单例池),beanDefination…为了配合aop或ioc这些功能,这些组件加在一起就构成了spring的环境
spring中的异常工具类
public abstract class Assert {
public static void state(boolean expression, String message) {
if (!expression) {
throw new IllegalStateException(message);
}
}
public static void isTrue(boolean expression, String message) {
if (!expression) {
throw new IllegalArgumentException(message);
}
}
...........
}
beanFactory是一个装载bean的工厂
factoryBean是一个生产bean的bean,他是一个特殊的bean
//beanName的命名是否规范,有无乱码,特殊符号#,$,%....
final String beanName = transformedBeanName(name);
去掉断点的方法
组件的集合—环境(spring容器是组件的集合,并不是单单指一个map—spring中用的是ConCunrrentMap,即源码中的命名是SingleObject,理解成单例池即可)
90%是单例 getBean==null 就
10%非单例
AnnotationConfigApplicationContext—父类----GenericApplicationContext–父类—AbstractApplicationContext–找到-----》refresh()方法----进入子方法-----》finishBeanFactoryInitialization(beanFactory);----进入子方法------》beanFactory.preInstantiateSingletons();------ctrl+alt+b查看该方法的具体实现—》
if (isEagerInit) {
getBean(beanName);
}
进到getBean(),再进到doGetBean()
来到了超级经典的Object sharedInstance = getSingleton(beanName);
bean是否
调试时查看临时变量
调试模式下:查看栈帧和线程