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. 转载:ADTS header

    转自:http://blog.csdn.net/tx3344/article/details/7414543 1.ADTS是个啥 ADTS全称是(Audio Data Transport Stream ...

  2. 报bug mui分享微信 ,qq 分享失败

    1. iOS分享链接到微信,分享成功,但是分享的只有title,其他参数都没有 原因是mui分享进行了更新,msg新增了 msg.type 这个配置参数 qq : msg.type='text' 微信 ...

  3. CSS 绝对定位时,水平居中而不影响原文档中其它元素

    div.absolutemiddle { position: absolute; left: 50%; transform: translate(-50%); /* 平移50%为自身尺寸的一半,实现水 ...

  4. 【Python协程的实现】

    " 补充:数据安全问题 进程: 多个进程操作同一个文件,会出现数据不安全 线程: 多个线程操作同一个全局变量,会出现数据不安全 对于共享的数据操作: 如果是 += *= /= -= 操作,都 ...

  5. SQLite3约束介绍

    SQLite 约束 约束是在表的数据列上强制执行的规则.这些是用来限制可以插入到表中的数据类型.这确保了数据库中数据的准确性和可靠性. 约束可以是列级或表级.列级约束仅适用于列,表级约束被应用到整个表 ...

  6. 2.2.FastDFS-单机拆分版-存储器安装配置

    Centos610系列配置 我们在Centos610FastDFS单机模式-FastDFS安装 中已经完成了FastDFS的安装,接下来我们进行FastDFS存储器的安装. 1.找到FastDFS配置 ...

  7. mybatis Plus 多表联合查询

    //实体类package com.sk.skkill.entity; import com.baomidou.mybatisplus.annotation.TableField;import com. ...

  8. socket实现简单的FTP

    一.开发环境 server端:centos 7  python-3.6.2 客户端:Windows 7 python-3.6.2 pycharm-2018 程序目的:1.学习使用socketserve ...

  9. 安装go和goland

    1.建议去go语言中文网下载,网址:https://studygolang.com/dl ,下图是下载页面及包介绍 2.Windows版安装 3.在cmd命令行窗口输入“go version”可以查看 ...

  10. MySQL复制方法

    MySQL的二进制日志,MySQL复制原理,MySQL主从模式搭建,MySQL双主模式搭建,MySQL级联模式搭建,MySQL半同步模式复制 一.二进制日志 1.概念 MySQL的二进制日志(bina ...