本文是作者原创,版权归作者所有.若要转载,请注明出处.

最近在看spring源码,但是spring的体系太庞大了,在这里记录一下阅读源码中遇到知识点

@PostConstruct

被注解的方法,在对象加载完依赖注入后执行

看个demo

package com.day01.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; @Configuration
@ComponentScan("com.day01")
public class SpringConfig { }

IndexDao

package com.day01.service;

import org.springframework.stereotype.Component;

@Component
public class IndexDao { public IndexDao(){
System.out.println("IndexDao 构造方法");
}
}

IndexService

@Service
public class IndexService {
@Autowired
private IndexDao indexDao; public IndexService(){
System.out.println("IndexService 构造方法");
} @PostConstruct
public void init(){
System.out.println("IndexService init方法");
} public void hello(){
System.out.println("IndexService");
} }

Testday01

public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
IndexService indexService = (IndexService) applicationContext.getBean("indexService");
indexService.hello();
}

看结果

可以看出在spring项目中,在一个bean的初始化过程中,方法执行先后顺序为Constructor > @Autowired > @PostConstruct

BeanPostProcessor

BeanPostProcessor是Spring框架的提供的一个扩展点,通过实现BeanPostProcessor接口,程序员就可插手bean实例化的过程

看demo

@Component
public class TestBeanPostProcessor implements BeanPostProcessor { /**
* 在bean初始化之前执行
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("indexService")){
System.out.println("indexService postProcessBeforeInitialization");
}
//这里也可以产生代理对象 Proxy.newProxyInstance(),也是aop实现的原理
return bean;
} /**
* 初始化之后
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("indexService")){
System.out.println("indexService postProcessAfterInitialization");
}
return bean;
} }

运行上文的Testday01,看下结果

可以看出

===Spring IOC容器实例化Bean===
===调用BeanPostProcessor的postProcessBeforeInitialization方法===
===调用bean实例的初始化方法===
===调用BeanPostProcessor的postProcessAfterInitialization方法===

值得说明的是这个接口可以设置多个,会形成一个列表,那么如何确定他们的执行顺序呢?

Ordered和PriorityOrdered

Spring提供了Ordered和PriorityOrdered接口,来处理相同接口实现类的优先级问题

看个demo

TestBeanPostProcessor

@Component
public class TestBeanPostProcessor implements BeanPostProcessor , PriorityOrdered { /**
* 在bean初始化之前执行
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("indexService")){
System.out.println("indexService postProcessBeforeInitialization");
}
//这里也可以产生代理对象 Proxy.newProxyInstance(),也是aop实现的原理
return bean;
} /**
* 在bean初始化之前执行
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("indexService")){
System.out.println("indexService postProcessAfterInitialization");
}
return bean;
} @Override
public int getOrder() {
return 100;//注意这里
}
}

TestBeanPostProcessor2

@Component
public class TestBeanPostProcessor2 implements BeanPostProcessor , PriorityOrdered { /**
* 在bean初始化之前执行
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("indexService")){
System.out.println("indexService postProcessBeforeInitialization2");
}
//这里也可以产生代理对象 Proxy.newProxyInstance(),也是aop实现的原理
return bean;
} /**
* 在bean初始化之前执行
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("indexService")){
System.out.println("indexService postProcessAfterInitialization2");
}
return bean;
} @Override
public int getOrder() {
return 99;
}
}

运行test类,看结果

这段代码的逻辑:

  1. 若对象o1是Ordered接口类型,o2是PriorityOrdered接口类型,那么o2的优先级高于o1

  2. 若对象o1是PriorityOrdered接口类型,o2是Ordered接口类型,那么o1的优先级高于o2

  3. 其他情况,若两者都是Ordered接口类型或两者都是PriorityOrdered接口类型,调用Ordered接口的getOrder方法得到order值,order值越大,优先级越小

若2个对象中有一个对象实现了PriorityOrdered接口,那么这个对象的优先级更高。

若2个对象都是PriorityOrdered或Ordered接口的实现类,那么比较Ordered接口的getOrder方法得到order值,值越低,优先级越高

BeanFactoryPostProcessor

spring的扩展点之一:实现该接口,可以在spring的bean创建之前修改beandefinitions属性。

例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉。
可以同时配置多个BeanFactoryPostProcessor,并通过设置'order'属性来控制各个BeanFactoryPostProcessor的执行次序

看个demo

@Component
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("===============TestBeanFactoryPostProcessor============"); }
}

测试类

public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
//AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(IndexService.class);
IndexService indexService = (IndexService) applicationContext.getBean("indexService");
indexService.hello();
IndexService indexService2 = (IndexService) applicationContext.getBean("indexService");
System.out.println(indexService);
System.out.println(indexService2);
}

运行一下,看结果

可以看到,spring管理的bean默认是单例的,我们把indexService改成prototype试一下

@Component
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("===============TestBeanFactoryPostProcessor============");
BeanDefinition indexService = beanFactory.getBeanDefinition("indexService");
String scope = indexService.getScope();
System.out.println(scope);//singleton
//indexService.setScope("singleton");
indexService.setScope("prototype");//设置为原型
System.out.println(scope);//singleton
}
}

看下结果

BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口,并可以注册bean到spring容器中,一共要实现以下两个方法:

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException:
该方法的实现中,主要用来对bean定义做一些改变。 void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException:
该方法用来注册更多的bean到spring容器中,详细观察入参BeanDefinitionRegistry接口,看看这个参数能带给我们什么能力。

看个demo

public class IndexService2  {

    private ApplicationContext applicationContext;
public IndexService2(){
System.out.println("IndexService2 构造方法");
} @PostConstruct
public void init(){
System.out.println("IndexService2 init方法");
} public void hello(){
System.out.println("IndexService2 hello");
} }

注意:IndexService2并没有@Component注解,说明这个类并没有交给spring管理,继续

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setScope("singleton");
genericBeanDefinition.setBeanClass(IndexService2.class);//将IndexService2交给spring管理
registry.registerBeanDefinition("indexService2",genericBeanDefinition);
} @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("===============MyBeanDefinitionRegistryPostProcessor============");
}
}

注意上述代码中通过BeanDefinitionRegistryPostProcessor 将IndexService2手动注册交给spring管理

运行test类

public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
//AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(IndexService.class);
IndexService indexService = (IndexService) applicationContext.getBean("indexService");
indexService.hello();
IndexService2 indexService2 = (IndexService2) applicationContext.getBean("indexService2");
System.out.println(indexService);
System.out.println(indexService2);
}

看结果

ApplicationContextAware

我们可以通过注解@Autowired 很简单方便获取bean,虽然这种方法很简单方便,但是有些特殊场景用不了,比如静态方法中不能使用

此时可以借助ApplicationContextAware获取bean

看个demo

@Service
public class TestServiceImpl { public String hello(){
return "hello world";
} }

这里无法注入TestServiceImpl 无法使用,看demo

@Component
public class ApplicationContextUtil implements ApplicationContextAware { private static ApplicationContext applicationContext = null;
@Autowired
private TestServiceImpl testService; /**
* 实现ApplicationContextAware接口, 注入Context到静态变量中.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextUtil.applicationContext = applicationContext;
} /**
* 获取静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
} /**
* 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
} /**
* 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
} /*public static String test(){
String hello = testService.hello();
}*/
}

看测试类

public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
//AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(IndexService.class);
IndexService indexService = (IndexService) applicationContext.getBean("indexService");
indexService.hello();
System.out.println(indexService);
/*IndexService2 indexService2 = (IndexService2) applicationContext.getBean("indexService2");
System.out.println(indexService2);*/
String testServiceImpl = ((TestServiceImpl) ApplicationContextUtil.getBean("testServiceImpl")).hello();
System.out.println(testServiceImpl);
}

看结果

ok,今天就先到这里,以后有新的内容随时补充吧

spring源码解析之前置知识点的更多相关文章

  1. spring 源码解析

    1. [文件] spring源码.txt ~ 15B     下载(167) ? 1 springн┤┬вио╬Ш: 2. [文件] spring源码分析之AOP.txt ~ 15KB     下载( ...

  2. Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean

    Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Sprin ...

  3. Spring源码解析 - AbstractBeanFactory 实现接口与父类分析

    我们先来看类图吧: 除了BeanFactory这一支的接口,AbstractBeanFactory主要实现了AliasRegistry和SingletonBeanRegistry接口. 这边主要提供了 ...

  4. Spring源码解析——循环依赖的解决方案

    一.前言 承接<Spring源码解析--创建bean>.<Spring源码解析--创建bean的实例>,我们今天接着聊聊,循环依赖的解决方案,即创建bean的ObjectFac ...

  5. Spring源码解析-ioc容器的设计

    Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...

  6. Spring源码解析系列汇总

    相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的Spring源码解析系列文章的汇总,总共包含以下专题.喜欢的同学可以收藏起来以备不时之需 SpringIOC源码解析(上) 本篇文章搭建了IOC源 ...

  7. Spring源码解析之PropertyPlaceholderHelper(占位符解析器)

    Spring源码解析之PropertyPlaceholderHelper(占位符解析器) https://blog.csdn.net/weixin_39471249/article/details/7 ...

  8. Spring源码解析之BeanFactoryPostProcessor(三)

    在上一章中笔者介绍了refresh()的<1>处是如何获取beanFactory对象,下面我们要来学习refresh()方法的<2>处是如何调用invokeBeanFactor ...

  9. Spring源码解析之ConfigurationClassPostProcessor(二)

    上一个章节,笔者向大家介绍了spring是如何来过滤配置类的,下面我们来看看在过滤出配置类后,spring是如何来解析配置类的.首先过滤出来的配置类会存放在configCandidates列表, 在代 ...

随机推荐

  1. 用pytorch做手写数字识别,识别l率达97.8%

    pytorch做手写数字识别 效果如下: 工程目录如下 第一步  数据获取 下载MNIST库,这个库在网上,执行下面代码自动下载到当前data文件夹下 from torchvision.dataset ...

  2. 曹工杂谈--只用一个命令,centos系统里装了啥软件,啥时候装的,全都清清楚楚

    前言 一直以来,对linux的掌握就是半桶水的状态,经常yum装个东西,结果依赖一堆东西:然后再用源码装个东西,只知道make.make install,背后干了啥也不清楚了,卸载也不方便. 这几天工 ...

  3. apt 安装 版本

    1. 通过apt-get安装指定版本软件 apt-get install package=version 2. 查询指定软件有多少个版本 2.1 通过网站搜索https://packages.ubun ...

  4. Linux下解压rar压缩包

    wget http://www.rarlab.com/rar/rarlinux-x64-4.2.0.tar.gz rar软件不需要安装,直接解压到/usr/local下,以下操作需要有root权限. ...

  5. zabbix自动监控钉钉报警

    钉钉报警 一:设置钉钉机器人  二:zabbix服务器server端配置 1.修改zabbix_server.conf文件 [root@server ~]# vim /usr/local/zabbix ...

  6. TCP链接的三次握手与四次断开

    一直总觉得三次握手和四次断开,之前老师讲的有问题,经过自己再次琢磨,发现是的,老师讲的没毛病,这次也把自己的理解总结一下,让对这个知识模糊的小伙伴再换种思路去理解 首先看一下TCP三次握手发生了哪些: ...

  7. JavaScript面向对象那些东西-继承

    继承 父类里有些属性方法 子类想把父类中的这些属性方法 继承过来给子类自己的实例也用用 ( ps: →_→ 能不能专业点 没文化真可怕 ) 一.原型链继承 // 原型链继承:把子类的原型作为父类的实例 ...

  8. vlookup匹配不出,明明文本内容是一样的,求解答。

    看起来很简单,肉眼看都知道就是匹配他,但是就是匹配不出.用trim去掉了空格,用分列去掉空格.tab这些看不见的.也改了单元格是数字型,而且粘贴是用数值型粘贴,全都匹配不出用if函数验证两个匹配对象是 ...

  9. 爱创课堂每日一题第五十四天- 列举IE 与其他浏览器不一样的特性?

    IE支持currentStyle,FIrefox使用getComputStyle IE 使用innerText,Firefox使用textContent 滤镜方面:IE:filter:alpha(op ...

  10. ubuntu16 安装redis

    ubuntu16 安装redis并开机自启 1.redis-3.2.5.tar.gz解压到/usr/local下 tar -xvf redis-3.2.5.tar.gz 2.进入源码包/usr/loc ...