Spring
控制反转是思想 依赖注入是实现* 正转 new Object* 反转 容器帮我们查找及注入依赖对象 对象只是被动的接受依赖对象依赖注入(xml 和 java config)* 通过构造方法或者set方法* 基于设值函数的依赖注入(创建bean后调用bean的设值函数)* 注入集合* 自动装配* autowire byName byType constructor* 注解* @Required(属性
·
控制反转是思想 依赖注入是实现
* 正转 new Object
* 反转 容器帮我们查找及注入依赖对象 对象只是被动的接受依赖对象
依赖注入(xml 和 java config)
* 通过构造方法或者set方法
* 基于设值函数的依赖注入(创建bean后调用bean的设值函数)
* 注入集合
* 自动装配
* autowire byName byType constructor
* 注解
* @Required(属性setter方法 xml配置)
* @Autowired(setter方法 非setter方法 构造函数和属性)
* @Qualifier(两个实习类的时候做区分)
* JSR-250
* @PostConstruct(初始化回调函数)
* @PreDestroy(注释作为销毁回调函数的一个替代)
* @Resource(by-name 字段 setter方法)
* 基于Java的配置
* @Configuration(表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源)
* @Bean(支持初始化和销毁的回调方法)
* @import(允许从另一个配置类中加载@Bean定义)
BeanFactory
那为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有它使用的场合,它主要是为了区分在Spring 内部在操作过程中对象的传递和转化过程时,对对象的数据访问所做的限制
- ListableBeanFactory(可列表化的Bean)
- HierarchicalBeanFactory(有继承关系的Bean)
- AutowireCapableBeanFactory(定义Bean 的自动装配规则)
ApplicationContext
- 1、支持信息源,可以实现国际化。(实现MessageSource 接口)
- 2、访问资源。(实现ResourcePatternResolver 接口,后面章节会讲到)
- 3、支持应用事件。(实现ApplicationEventPublisher 接口)
BeanDefinition
Bean 对象在Spring 实现中是以BeanDefinition 来描述的
BeanDefinitionReader
Bean 的解析主要就是对Spring 配置文件的解析。这个解析过程主要通过BeanDefintionReader 来完成
基于Xml 的IOC 容器的初始化
- 寻找入口
通过main()方法启动
还有像AnnotationConfigApplicationContext 、FileSystemXmlApplicationContext 、XmlWebApplicationContext
等都继承自父容器AbstractApplicationContext 主要用到了装饰器模式和策略模式,
最终都是调用refresh()方法 - 获得配置路径
- 开始启动
- refresh()是一个模板方法,规定了IOC 容器的启动流程
在创建IOC 容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh 之后使用的是新建立起来的IOC 容器。
它类似于对IOC 容器的重启,在新建立好的容器中对容器进行初始化,对Bean 配置资源进行载入。
- refresh()是一个模板方法,规定了IOC 容器的启动流程
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//1、调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//2、告诉子类启动refreshBeanFactory()方法,Bean 定义资源文件的载入从
//子类的refreshBeanFactory()方法启动
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//3、为BeanFactory 配置容器特性,例如类加载器、事件处理器等
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//4、为容器的某些子类指定特殊的BeanPost 事件处理器
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//5、调用所有注册的BeanFactoryPostProcessor 的Bean
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//6、为BeanFactory 注册BeanPost 事件处理器.
//BeanPostProcessor 是Bean 后置处理器,用于监听容器触发的事件
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//7、初始化信息源,和国际化相关.
initMessageSource();
// Initialize event multicaster for this context.
//8、初始化容器事件传播器.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//9、调用子类的某些特殊Bean 初始化方法
onRefresh();
// Check for listener beans and register them.
//10、为事件传播器注册事件监听器.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//11、初始化所有剩余的单例Bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//12、初始化容器的生命周期事件处理器,并发布容器的生命周期事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
//13、销毁已创建的Bean
destroyBeans();
// Reset 'active' flag.
//14、取消refresh 操作,重置容器的同步标识.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
//15、重设公共缓存
resetCommonCaches();
}
}
}
- 创建容器
- 委派设计模式(父类定义抽象方法,调用子类容器实现的该方法) obtainFreshBeanFactory()方法调用子类容器的refreshBeanFactory()方法
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//这里使用了委派设计模式
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
//子类方法
@Override
protected final void refreshBeanFactory() throws BeansException { //如果已经有容器,销毁容器中的bean,关闭容器
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {//创建IOC 容器,其实这里就是创建了一个
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId()); //对IOC 容器进行定制化,如设置启动参数,开启注解的自动装配等
customizeBeanFactory(beanFactory);//调用载入Bean 定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions 方法,具体的实现调用子类容器 loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
- 载入配置路径
- 分配路径处理策略
- 解析配置文件路径
- 开始读取配置内容
- 准备文档对象
- 分配解析策略
- 将配置载入内存
- 载入元素
- 总结(BeanDefinition 的Resource 定位、加载和注册这三个基本的过程)
1、初始化的入口在容器实现中的refresh()调用来完成
2、对Bean 定义载入IOC 容器使用的方法是loadBeanDefinition()
通过ResourceLoader 来完成资源文件位置的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给出了ResourceLoader 的实现
,可以从类路径,文件系统,URL 等方式来定为资源位置。如果是XmlBeanFactory 作为IOC 容器,那么需要为它指定Bean 定义的资源,
也就是说Bean 定义文件时通过抽象成Resource 来被IOC 容器处理的, 容器通过BeanDefinitionReader 来完成定义信息的解析和Bean 信息的注册,
往往使用的是XmlBeanDefinitionReader 来解析Bean 的XML 定义文件- 实际的处理过程是委托给BeanDefinitionParserDelegate 来完成的,
从而得到bean 的定义信息,这些信息在Spring 中使用BeanDefinition 对象来表示-这个名字可以让我们想到loadBeanDefinition(),
registerBeanDefinition()这些相关方法。它们都是为处理BeanDefinitin 服务的,容器解析得到BeanDefinition 以后,
需要把它在IOC 容器中注册,这由IOC 实现BeanDefinitionRegistry 接口来实现。
注册过程就是在IOC 容器内部维护的一个HashMap 来保存得到的BeanDefinition 的过程。这个HashMap 是IOC 容器持有Bean 信息的场所,
以后对Bean 的操作都是围绕这个ConcurrentHashMap来实现的。然后我们就可以通过BeanFactory 和ApplicationContext 来享受到Spring IOC 的服务了,
在使用IOC容器的时候,我们注意到除了少量粘合代码,绝大多数以正确IOC 风格编写的应用程序代码完全不用关心如何到达工厂,
因为容器将把这些对象与容器管理的其他对象钩在一起。基本的策略是把工厂放到已知的地方,最好是放在对预期使用的上下文有意义的地方,
以及代码将实际需要访问工厂的地方。Spring本身提供了对声明式载入web 应用程序用法的应用程序上下文,并将其存储在ServletContext 中的框架实现
时序图:
基于Annotation的IOC 初始化(https://www.cnblogs.com/wuzhenzhao/p/10863712.html)
- 注解处理策略方式
- 类注解 Spring 容器根据注解的过滤规则扫描读取注解Bean 定义类,并将其注册到Spring IOC 容器中 如@Component、@Repository、@Controller、@Service
- 类内注解 通过Bean 后置注解处理器解析Bean 内部的注解 如 @Autowire、@Value、@Resource
- 向容器注册方式(最终都是 向Bean添加到容器中一个管理BeanDefinition的HashMap中)
- 容器创建后手动调用向容器注册,然后通过手动刷新容器,使得容器对注册的注解Bean 进行处理
- 扫描指定包向容器注解
依赖注入(DI)(https://www.cnblogs.com/wuzhenzhao/p/10882050.html)
- 用户第一次调用getBean()方法时,IOC 容器触发依赖注入
- 当用户在配置文件中将元素配置了lazy-init=false 属性,即让容器在解析注册Bean 定义时进行预实例化,触发依赖注入
- 过程
- 缓存重置
- 实例化
- 使用简单工厂/工厂方法/容器的自动装配方法/参数匹配的构造方法/无参构造方法(反射(没有方法覆盖)/CGLib(有方法覆盖)) 生成Java 实例对象
- 填充属性(依赖注入的过程就是Bean对象实例设置到它所依赖的Bean对象属性上去)
-
属性值类型不需要强制转换时,不需要解析属性值,直接准备进行依赖注入
-
属性值需要进行类型强制转换时,如对其他对象的引用(接口和实现类)等,首先需要解析属性值,然后对解析后的属性值进行依赖注入
-
对于集合类型的属性,将其属性值解析为目标类型的集合后直接赋值给属性
-
对于非集合类型的属性,大量使用了JDK 的反射机制,通过属性的getter()方法获取指定属性注入以前的值,同时调用属性的setter()方法为属性设置注入后的值
-
- 包装处理返回
Spring Bean
* bean作用域(prototype)
* singleton 单例(默认值)
* prototype 多例
* request 每次HTTP请求都会创建一个新的Bean
* session 同一个HTTP Session共享一个Bean
* global-session 一般用于Portlet应用环境
* 单例和多例选择
* 单例 节省cpu和内存
* 多例 防止有状态的实例并发线程安全问题
* 生命周期
* Bean的定义——Bean的初始化——Bean的使用——Bean的销毁
* Bean 后置处理器
(interface BeanPostProcessor)允许在调用初始化方法前后对 Bean 进行额外的处理
* Bean 定义继承
Spring 事件处理
* 单线程
* ApplicationContext加载 beans发布某些类型的事件(当上下文启动时,ContextStartedEvent 发布,当上下文停止时,ContextStoppedEvent 发布)
* ApplicationEvent ApplicationListener 提供在 ApplicationContext 中处理事件
* 如果一个 bean 实现 ApplicationListener,那么每次 ApplicationEvent 被发布到 ApplicationContext 上,那个 bean 会被通知
* 可以自定义事件
Spring AOP
* Aspect 一个模块具有一组提供横切需求的 APIs
* Join point 代表一个点
* Advice 这是实际行动之前或之后执行的
* Pointcut 一组一个或多个连接点
* 通知的类型
* 前置 方法执行之前
* 后置 方法执行之后(不考虑其结果)
* 返回后 只有方法成功完成时
* 抛出异常后 只有在方法退出抛出异常时
* 环绕通知 调用之前和之后(手动写调用方法)
更多推荐
已为社区贡献1条内容
所有评论(0)