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. 【深入HTTP协议】

    目录 HTTP 请求 HTTP 响应 "HTTP是(Hyper Text Transfer Protocol)超文本传输协议的缩写. HTTP的发展是万维网协会(World Wide Web ...

  2. python函数编程闯关总结

    文件处理相关 1,编码问题 (1)请问python2与python3中的默认编码是什么? python .x默认的字符编码是ASCII,默认的文件编码也是ASCII python .x默认的字符编码是 ...

  3. CCF 试题编号: 201909-4 试题名称: 推荐系统

    这题是stl的综合应用,map要想快,直接上unordered_map,这样查询接近O(1),是不是很嗨皮. 思路其实还是很简单的,type+id做个Hash,由于set.insert的第一个返回值是 ...

  4. Laravel Vuejs 实战:开发知乎 (8)美化编辑器

    1.使用UEditor增量包: simple-ueditors 执行下载: git clone https://github.com/JellyBool/simple-ueditor.git 2.用此 ...

  5. 关于anaconda-navigator打不开的问题

    19-10版本的anaconda-navigator打不开,没有图形化界面就是很糟糕 在命令行执行各种命令都没有问题,说明anaconda并没有出现大的问题,可能只是图形化界面出了问题. 执行 ana ...

  6. 计算机二级-C语言-程序修改题-190114记录-对整型变量进行取余操作可以取得各个位上的值。

    //给定程序中fun函数的功能是:从低位开始取出长整形变量s中奇数位上的数,依次构成一个新的数放在t中.高位仍在高位,低位仍在低位.例如:当s中的数为7654321时,t中的数为7531. //重难点 ...

  7. Java AQS 的胡言乱语修正版

    前言 适合读者:3 年以上经验的同学 谈到并发编程,基本上都会想到JDK 的 JUC 工具包,它包含 锁,并发工具类,原子类,线程池,还有阻塞队列,这是从网上找的一个大致的知识体系. 相信这些工具读者 ...

  8. 1143. Longest Common Subsequence

    link to problem Description: Given two strings text1 and text2, return the length of their longest c ...

  9. Pychram 运行程序在 run 窗口和 python console 窗口之间切换

    有图有真相 第一步: 第二步:

  10. linux文本处理工具-1

    文件内容: cat ,more,less 文件截取:head,tail 按列抽取:cut 排序和统计:sort,wc ----------------------------------------- ...