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 源码分析的更多相关文章

  1. Spring IOC 源码分析

    Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢?阅读本文 ...

  2. spring IoC源码分析 (3)Resource解析

    引自 spring IoC源码分析 (3)Resource解析 定义好了Resource之后,看到XmlFactoryBean的构造函数 public XmlBeanFactory(Resource  ...

  3. Spring IoC 源码分析 (基于注解) 之 包扫描

    在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫 ...

  4. Spring Ioc源码分析系列--Ioc的基础知识准备

    Spring Ioc源码分析系列--Ioc的基础知识准备 本系列文章代码基于Spring Framework 5.2.x Ioc的概念 在Spring里,Ioc的定义为The IoC Containe ...

  5. Spring Ioc源码分析系列--前言

    Spring Ioc源码分析系列--前言 为什么要写这个系列文章 首先这是我个人很久之前的一个计划,拖了很久没有实施,现在算是填坑了.其次,作为一个Java开发者,Spring是绕不开的课题.在Spr ...

  6. Spring Ioc源码分析系列--Ioc源码入口分析

    Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...

  7. Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析

    Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析 前言 上一篇文章Spring Ioc源码分析系列--Ioc源码入口分析已经介绍到Ioc容器 ...

  8. Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理

    Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理 前言 上一篇分析了BeanFactoryPostProcessor的作用,那么这一篇继续 ...

  9. Spring Ioc源码分析系列--Bean实例化过程(一)

    Spring Ioc源码分析系列--Bean实例化过程(一) 前言 上一篇文章Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理已经完成了对 ...

  10. Spring Ioc源码分析系列--Bean实例化过程(二)

    Spring Ioc源码分析系列--Bean实例化过程(二) 前言 上篇文章Spring Ioc源码分析系列--Bean实例化过程(一)简单分析了getBean()方法,还记得分析了什么吗?不记得了才 ...

随机推荐

  1. yii2 gii开启

    gii模块可以通过配置yii\base\Application::modules属性开启它.在config/web.php文件中会有以下配置代码: $config = [ ... ]; if (YII ...

  2. mysql中的文件排序(filesort)

    在MySQL中的ORDER BY有两种排序实现方式: 1. 利用有序索引获取有序数据 2. 文件排序 在explain中分析查询的时候,利用有序索引获取有序数据显示Using index ,文件排序显 ...

  3. python 的头文件包含问题

    一个python项目中一个文件需要引用另一个文件中的类,遇到的几个问题,总结如下: 0x01 情况一:在同一目录下 project |--a.py |--b.py |--main.py 在main.p ...

  4. Hadoop3.1.1源码Client详解 : 写入准备-RPC调用与流的建立

    该系列总览: Hadoop3.1.1架构体系——设计原理阐述与Client源码图文详解 : 总览 关于RPC(Remote Procedure Call),如果没有概念,可以参考一下RMI(Remot ...

  5. springBoot日志快速上手简单配置

    默认配置 日志级别从低到高分为: TRACE < DEBUG < INFO < WARN < ERROR < FATAL. 如果设置为 INFO ,则低于 INFO 的信 ...

  6. thinkphp 连接webservice接口

    嗯,我现在真的好像骂人啊,但是我又是个文明的人,所以我就写出来让自己冷静一下 ok,正事,thinkphp连别人写的webservice接口 刚开始他叫什么nc接口,就把我给骗了,这就是人家的名字,和 ...

  7. Laravel Vuejs 实战:开发知乎 (4)实现找回密码

    资料 : Resetting Passwords   以及 Episode 35 - The Password Reset Flow 由于之前的实现里默认自带重置找回密码功能,不再复述. 默认的重置页 ...

  8. family_to_level函数

    #include <netinet/in.h> #include <sys/socket.h> int family_to_level(int family) { switch ...

  9. 「NOIP2018」赛道修建

    传送门 Luogu 解题思路 一眼先二分(上界树的直径,下界最小边权),然后再考虑 \(\text{DP}\). 对于当前节点 \(u\),在它的所有儿子中分别返回一条匹配不完的长度最大的路径 \(M ...

  10. 例题3_3 回文词(UVa401)

    输入一个字符串,判断它是否为回文串以及镜像串.输入字符串保证不含数字0.所谓回文串,就是反转以后和原串相同,如abba和madam.所有镜像串,就是左右镜像之后和原串相同,如2S和3AIAE.注意,并 ...