《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()方法,还记得分析了什么吗?不记得了才 ...
随机推荐
- 每天进步一点点------Error: Can't place pins assigned to pin location Pin_K22 (IOPAD_X41_Y19_N14)
在QII中的Assignments----Device----Device and pin option-----(选项卡)Dual purpose pin将nCE0 的设置改为: use as re ...
- 2020 i春秋新春战疫公益赛 misc
0x01 code_in_morse morse decode后得到: RFIE4RYNBINAUAAAAAGUSSCEKIAAAAEUAAAAA7AIAYAAAAEPFOMTWAAABANUSRCB ...
- CSS 动画过程及间接实现样式延时
/* 过度动画自动归位 */ @keyframes animation_button_scene { 0% { background: #9cacb4; } 10% { /* 样式过度2 */ } 6 ...
- RTT学习之软件包
网络工具集 (NetUtils) Ping 工具: 是一种网络诊断工具,用来测试数据包能否通过 IP 协议到达特定主机,依赖于LWIP,支持域名和IP访问: NTP 工具:NTP 是网络时间协议 (N ...
- 【PAT甲级】1098 Insertion or Heap Sort (25 分)
题意: 输入一个正整数N(<=100),接着输入两行N个数,表示原数组和经过一定次数排序后的数组.判断是经过插入排序还是堆排序并输出再次经过该排序后的数组(数据保证答案唯一). AAAAAcce ...
- 【PAT甲级】1083 List Grades (25 分)
题意: 输入一个正整数N(<=101),接着输入N个学生的姓名,id和成绩.接着输入两个正整数X,Y(0<=X,Y<=100),逆序输出成绩在x,y之间的学生的姓名和id. tric ...
- JAVA8-用lamda表达式和增强版Comparator进行排序
1.单条件升序: list.sort(Comparator.comparing(User::getId); 2.降序: list.sort(Comparator.comparing(User::get ...
- 【TCP/IP网络编程】:06基于UDP的服务器端/客户端
本篇文章简单描述了UDP传输协议的工作原理及特点. 理解UDP UDP和TCP一样同属于TCP/IP协议栈的第二层,即传输层. UDP套接字的特点 UDP的工作方式类似于传统的信件邮寄过程.寄信前应先 ...
- ZOJ007 Numerical Summation of a Series(纯数学)
#include<bits/stdc++.h> using namespace std; int main() { double i; double k; for(i=0.000;i-2. ...
- ETCD成员维护
# For each machine TOKEN=my-etcd-token-1 CLUSTER_STATE=new NAME_1=etcd-node-1 NAME_2=etcd-node-2 NAM ...