《Java Spring框架》Spring IOC 源码分析
1.下载源码
源码部署:https://www.cnblogs.com/jssj/p/11631881.html
并不强求,最好是有源码(方便理解和查问题)。
2. 创建子项目
Spring项目中创建子项目:https://www.cnblogs.com/jssj/p/12329839.html
3. 案例(两个干预Spring生成Bean)

AppConfig:
package accelerate.app; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; @Configuration
@ComponentScan("accelerate")
public class AppConfig {
}
Apple
package accelerate.bean; import org.springframework.stereotype.Component; @Component
public class Apple {
public Apple(){
System.out.println("Apple");
}
}
Test
package accelerate.bean;
public class Test {
public Test(){
System.out.println("构造方法-Test");
}
}
AccelerateBeanFactoryPostProcessor
package accelerate.mybatis; import accelerate.bean.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component; @Component
public class AccelerateBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition)beanFactory.getBeanDefinition("apple");
System.out.println("插手前:" + genericBeanDefinition.getBeanClassName());
genericBeanDefinition.setBeanClass(Test.class);
}
}
Demo
package accelerate.test; import accelerate.app.AppConfig;
import accelerate.bean.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Demo {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(AppConfig.class); System.out.println("最终生成的Bean:"+ annotationConfigApplicationContext.getBean("apple"));
}
}
build.gradle
group 'org.springframework'
version '3.2.19.BUILD-SNAPSHOT' apply plugin: 'java' sourceCompatibility = 1.8 repositories {
mavenCentral()
} dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile project(':spring-context')
compile project(':spring-beans') }
运行结果:

结论: Apple类加了注解@Compnent而Test类没有加注解,最后通过getBean(Test.class)却拿到了Apple这个Bean对象。
根据调试:看到Spring源码AbstractApplicationContext 类有如下代码循环调用。
/**
* author hubt
* 该代码执行循环执行实现BeanFactoryPostProcessor的类的方法。
* @param postProcessors
* @param beanFactory
*/
private void invokeBeanFactoryPostProcessors(
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) { for (BeanFactoryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanFactory(beanFactory);
}
}
如何修改干预Spring生成Bean的过程。
/**
* author
* Spring会将Bean的信息(类名,修饰符等等)写入BeanDefinition类中,并将这些BeanDefinition存放入beanDefinitionMap中。
* 该方法是根据你定义的名称获取对应存放bean信息的BeanDefinition。
* @param beanName name of the bean to find a definition for
* @return
* @throws NoSuchBeanDefinitionException
*/
@Override
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
if (bd == null) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("No bean named '" + beanName + "' found in " + this);
}
throw new NoSuchBeanDefinitionException(beanName);
}
return bd;
}
案例二:

AppConfig
package accelerate.app; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; @Configuration
@ComponentScan("accelerate")
public class AppConfig {
}
AopTest
package accelerate.mybatis; import accelerate.service.AccelerateInvocationHandler;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component; import java.lang.reflect.Proxy; @Component
public class AopTest implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
} public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("cityService")){
Class<?> aClass = bean.getClass().getInterfaces()[0];
Class[] classes = new Class[]{aClass};
Object o = Proxy.newProxyInstance(AopTest.class.getClassLoader(), classes, new AccelerateInvocationHandler(bean));
return o;
}
return bean;
}
}
AccelerateInvocationHandler
package accelerate.service; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class AccelerateInvocationHandler implements InvocationHandler { Object o; public AccelerateInvocationHandler(Object o){
this.o = o;
} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("aop----before");
Object result = method.invoke(o);
System.out.println("aop----after");
return result;
}
}
CityService
package accelerate.service;
import org.springframework.stereotype.Component;
@Component("cityService")
public class CityService implements L {
public CityService(){
System.out.println("构造方法----CityService");
}
public void query() {
System.out.println("logic---db");
}
}
package accelerate.service;
public interface L {
public void query();
}
Demo
package accelerate.test; import accelerate.app.AppConfig;
import accelerate.service.L;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Demo {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(AppConfig.class); L bean = annotationConfigApplicationContext.getBean(L.class);
bean.query();
}
}
build.gradle 配置不变。
运行结果:

结论:原本CityService只是一个普通Bean,被修改成一个代理类。
源码分析如下:
/**
* author hubt
* 循环执行Spring的后置处理,也就是说实现或者继承BeanPostProcessors的类都会在这里被运用到
* @param existingBean the new bean instance
* @param beanName the name of the bean
* @return
* @throws BeansException
*/
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException { Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
这边还运用了Java动态代理:https://www.cnblogs.com/jssj/p/11771408.html
案例三:
package accelerate1.app; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; @Configuration
@ComponentScan("accelerate1")
public class AppConfig {
}
package accelerate1.mybatis; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component; @Component
public class AccelerateBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition)beanFactory.getBeanDefinition("cityService");
/***将CityService,设置成自动装配的(Autowired的bytype方式)***/
genericBeanDefinition.setAutowireMode(2);
}
}
package accelerate1.service;
import org.springframework.stereotype.Component;
@Component("cityService")
public class CityService{
Province province;
public void setProvince(Province province) {
this.province = province;
}
public void query() {
System.out.println(province);
}
}
package accelerate1.service; import org.springframework.stereotype.Component; @Component
public class Province { public Province(){
System.out.println("init province");
}
}
package accelerate1.test; import accelerate1.app.AppConfig;
import accelerate1.service.CityService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Demo1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
annotationConfigApplicationContext.getBean(CityService.class).query();
}
}
运行结果:

可以看到:打印了Province这个对象的信息,我们没有使用@Autowired注解进行注入,而是通过后置处理器将AutowiredMode的值修改点而进行自动注入。
AutowiredMode的值有4种:
1. no: 不注入(默认)。
2. byname: 按属性名称自动连接。Spring寻找与需要自动装配的属性同名的bean。。
3. bytype: 如果容器中恰好存在一个属性类型的bean,则使该属性自动连接。如果存在多个错误,则会引发致命异常。
4. constructor:类似于byType但适用于构造函数参数。如果容器中不存在构造函数参数类型的一个bean,则将引发致命错误
注意:自动注入需要存在构造函数或者set方法才可以注入;而@Autowired不需要set方法,缺点:@Autowired只能注解在单个引用上。
Spring IOC 原理图:

感谢观看。
《Java Spring框架》Spring IOC 源码分析的更多相关文章
- Spring IOC 源码分析
Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢?阅读本文 ...
- spring IoC源码分析 (3)Resource解析
引自 spring IoC源码分析 (3)Resource解析 定义好了Resource之后,看到XmlFactoryBean的构造函数 public XmlBeanFactory(Resource ...
- Spring IoC 源码分析 (基于注解) 之 包扫描
在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫 ...
- Spring Ioc源码分析系列--Ioc的基础知识准备
Spring Ioc源码分析系列--Ioc的基础知识准备 本系列文章代码基于Spring Framework 5.2.x Ioc的概念 在Spring里,Ioc的定义为The IoC Containe ...
- Spring Ioc源码分析系列--前言
Spring Ioc源码分析系列--前言 为什么要写这个系列文章 首先这是我个人很久之前的一个计划,拖了很久没有实施,现在算是填坑了.其次,作为一个Java开发者,Spring是绕不开的课题.在Spr ...
- Spring Ioc源码分析系列--Ioc源码入口分析
Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...
- Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析
Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析 前言 上一篇文章Spring Ioc源码分析系列--Ioc源码入口分析已经介绍到Ioc容器 ...
- Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理
Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理 前言 上一篇分析了BeanFactoryPostProcessor的作用,那么这一篇继续 ...
- Spring Ioc源码分析系列--Bean实例化过程(一)
Spring Ioc源码分析系列--Bean实例化过程(一) 前言 上一篇文章Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理已经完成了对 ...
- Spring Ioc源码分析系列--Bean实例化过程(二)
Spring Ioc源码分析系列--Bean实例化过程(二) 前言 上篇文章Spring Ioc源码分析系列--Bean实例化过程(一)简单分析了getBean()方法,还记得分析了什么吗?不记得了才 ...
随机推荐
- ElementUI+Vue在使用el-dialog时,如何做到在弹出dialog时,外部呈锁定状态,而不是点击外部导致dialog直接关闭。
ElementUI+Vue在使用el-dialog时,如何做到在弹出dialog时,外部呈锁定状态,而不是点击外部导致dialog直接关闭. 问题描述 今天,在做Element+Vue项目时发现:Di ...
- P & R 8
Floorplan: 要做好floorplan需要掌握哪些知识跟技能? 通常,遇到floorplan问题,大致的debug步骤跟方法有哪些? 如何衡量floorplan的QA? T:Block lev ...
- Exception in thread "main" java.lang.UnsupportedClassVersionError: org/apache/tools/ant/launch/Launcher : Unsupported major.min
有事这么一大串错误 1.版本问题 首先看咱们的jdk安装的版本,我装的是1.7.0,但是ant下的是1.10.0版本,换成1.7.0就ok了 官网下载http://ant.apache.org 所有版 ...
- Git添加和克隆远程库
首先我们得有一个GitHub账号,然后把当前电脑的SSH Key添加到GitHub上面 第1步:创建SSH Key.在用户主目录下(可用 “cd ~”进入用户主目录),看看有没有.ssh目录,如果有, ...
- Java面向对象编程 -4.3
static应用实例 编写一个程序类,这个类可以实现实例化对象个数的统计,每次创建的实例化对象都可以实现一个统计操作. 此时可以单独创建一个static属性,因为所有对象都共享同一个static属性, ...
- Java IO流详解(六)——转换流
转换流也是一种处理流,它提供了字节流和字符流之间的转换.在Java IO流中提供了两个转换流:InputStreamReader 和 OutputStreamWriter,这两个类都属于字符流.其中I ...
- 5 asyncio 梨视频
# 如何提升requests模块爬取数据的效率?- 多进程或多线程(不建议) 太耗费资源- 线程池或进程池(适当使用) - 单线程 + 异步协程(推荐) # 线程池使用案例 # 梨视频 下载作业 im ...
- P1579
AC: #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for(int i = a; i < b ...
- Fluent_Python_Part2数据结构,04-text-byte,文本和字节序列
文本和字节序列 人使用文本,计算机使用字节序列 1. 大纲: 字符.码位和字节表述 bytes.bytearray和memoryview等二进制序列的独特特性 全部Unicode和陈旧字符集的编解码器 ...
- python应用-pycharm新建模板默认添加shebang编码作者时间等信息
1.pycharm4.5激活码 用户名: yueting3527 注册码: ===== LICENSE BEGIN ===== 93347-12042010 00001FMHemWIs"6w ...