1、概述:
此篇博文,和后续几篇博文,码字之前,有点惶恐,恐言语不当,误彼误己,思后还是决定写,一是为了整理记忆,二是把自己所想所悟写出,让大家指正,共同进步。此篇博文,主要写Spring,后续会写SpringMvc、SpringBoot、SpringCloud。
Spring核心可分为以下几点:
- 依赖注入,控制反转;
- 生命周期;
- aop;
- 循环依赖;
注:此篇文章中的代码是基于Sprng5.0注解开发,非xml装配bean,另外工程是基于eclipse 简单maven工程。
2、依赖注入,控制反转:
在述之前,我们先简单认识一下Spring,Spring本质就是对java对象管理,它会将java对象放在一个线程安全的hashmap里,key就是对象的名字,如:
@Bean
public User user() {
User user = new User();
user .setName("sd");
user .setUserId(100);
return user ;
}
Map hashMap = new ConcurrentHashMap<String,Object>();
hashMap.put("user", user() );
hashMap可理解为Spring的容器,看以下内容脑里一定要有这个存储模型。
我经常面试时,谈及Spring,都会问面试者对这8个字(依赖注入,控制反转)理解,几乎全是这样回答,bean方式注入Spring容器,无需java new去创建对象,暂不论回答对错。
现在来拆分这个8个字,依赖,即我写的代码,要去依赖Spring提供的bean对象。注入,即将依赖的bean对象注入到Spring容器中。控制,即我写的代码,要去控制Spring中依赖bean对象的实现逻辑,到了这里发现没有,我写的代码没有去实现具体逻辑,而是反过来去控制Spring中依赖bean的实现逻辑,这就是反转。
上面所书有点绕,来一个简单又明朗的!就是我写的代码要去依赖Spring容器,从中获取对象,而这个对象实现的逻辑,要按我的逻辑去实现编码,说白了就是我不想去实现,你帮我实现就行,我要你就给我。
从Spring容器中获得bean对象很简单,无非这样 User user = hashMap.get("user")。难的是如何去控制bean对象实现逻辑,java是面向对象语言,有封装、继承、多态三大特性,继承可以继承接口实现逻辑,接口本质实现编码约定,这里的约定,可理解为我让你实现我需要的逻辑,多态用于运行时动态链编,父类可见于子类的实现。整过程说白了,就是我定义接口约定,让你实现,实现好了以后,再注入到Spring容器,并为其取一个我们之间约定好的名字,然后我使用时通过名字找到bean对象,赋值于接口变量,实现调用。
例如:用mybatis访问数据库,配置数据源时,无需关心连结的数据库是mysql,还是oracle,只需要配置指定驱动包就行,如:spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver或spring.datasource.driver-class-name=com.mysql.jdbc.Driver 。也不关心使用的连结池,是阿里的也吧,是c3p0也好,mybatis只需要定义一个数据源接口(datasource),制定好规范,让别人实现,mybatis使用时从Spring容器中取出对象,赋值给接口变量,实现调用就行。下面是SprinBoot直观的配制:
Mysql:
spring.datasource.min-idle=5
spring.datasource.max-idle=10
spring.datasource.max-active=15
spring.datasource.username=test
spring.datasource.password=test
spring.datasource.initial-size=5
spring.datasource.max-wait=10000
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://192.168.106.142:3306/?characterEncoding=utf-8&serverTimezone=GMT%2B8
Oracle:
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.password=test
spring.datasource.url=jdbc:oracle:thin:@192.168.106.142:1521:test
spring.datasource.username=dev
spring.datasource.initial-size=8
spring.datasource.max-idle=10
spring.datasource.max-wait=30000
spring.datasource.min-idle=8
spring.datasource.max-active=20
再来一个Xml bean注入,更直观:
<bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<!-- 数据库基本信息配置 -->
<property name="url" value="${url1}" />
<property name="username" value="${username1}" />
<property name="password" value="${password1}" />
<property name="driverClassName" value="${driverClassName}" />
<property name="filters" value="${filters}" />
<!-- 最大并发连接数 -->
<property name="maxActive" value="${maxActive}" />
<!-- 初始化连接数量 -->
<property name="initialSize" value="${initialSize}" />
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${maxWait}" />
<!-- 最小空闲连接数 -->
<property name="minIdle" value="${minIdle}" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" />
<property name="validationQuery" value="${validationQuery}" />
<property name="testWhileIdle" value="${testWhileIdle}" />
<property name="testOnBorrow" value="${testOnBorrow}" />
<property name="testOnReturn" value="${testOnReturn}" />
<property name="maxOpenPreparedStatements" value="${maxOpenPreparedStatements}" />
<!-- 打开 removeAbandoned 功能 -->
<property name="removeAbandoned" value="${removeAbandoned}" />
<!-- 1800 秒,也就是 30 分钟 -->
<property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" />
<!-- 关闭 abanded 连接时输出错误日志 -->
<property name="logAbandoned" value="${logAbandoned}" />
</bean>
那依赖注入,控制反转,到底有什么好处,我认为核心是解藕,就是我不关心具体的实现,我只知道要实现什么,告诉别人给我实现就好,然后通过Spring在藕在一起,并且具体实现是可插拔的(接口和多态),因为实现者可以有多个,我觉得那个好,我就用那个。
另外就是要有容器的思想,就是我们开发时,所需对象全部注入到Spring容器,即放入线程安全的hash里,统一管理。
2、生命周期:
我这里写的生命周期,可能与其它笔者不一样,仅是我的理解总结。
一是指bean驻留内存的生命周期,即bean在Spring容器进程生命周期内,会不会被gc回收。二是指bean从无到有、到初使化(其实主要谈这里)、再到注入Spring容器的生命周期。
先谈一,我们都知道, Spring容器中bean有5种作用域,分别是:
1、singleton 单例模式,全局有且仅有一个实例;
2、prototype 原型模式,每次获取bean都会产生一个新的对象;
3、request 每次请求都会产生一个新的对象,并且bean对象只对当前http请求有效;
4、session,会session会话周期一样;
5、global session 每个全局的HttpSession对应一个实例;
后三种主要是http请求相关,这里不细说,也很少用。singleton创建后会长驻内存,且Spring容器中只能有一个唯一(bean id一样)对象,prototype 创建后也会长驻内存,但每次从Spring容器获取都会产生一个新的对象,可以看出singleton是非线程安全,prototype是线程安全。Spring容器即是一个ConcurrentHashMap集合对象,如果其生命周期不能与进程寿终正寝,就不能谈进程,这里要强调一下。可以用@Scope注解控制作用域,如:@Scope("singleton")。
singleton还有一个知识点,即Spring bean对象的创建时机,分为懒汉式和饿汉式,赖汉式用到的时候再创建,饿汉式Spring容器一运行加载时就创建,默认是饿汉式。可以用Lazy控制加载方式,如:@Lazy(true)就是懒汉式。
现在来谈二,即是bean创建注入到Spring容器的过程,其实这里没什么好写的,总结下来就是:
1、反射创建bean对象;
2、调用set方法设置属性值(如果设置了);
3、调用对象继承的接口方法(如果实现了,如:ApplicationContextAware接口,主要是用来获取ApplicationContext),说白 了就是bean对象注入Spring容器过程中,Spring检查是否实现了约定接口,如果实现了就调用,目的实现一些自定义逻辑和回送一些你所需信息。代码如:
public class GetApplicationContext implements ApplicationContextAware{
private static ApplicationContext applicationContext = null;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("setApplicationContext");
GetApplicationContext.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return GetApplicationContext.applicationContext;
}
}
@Bean
public GetApplicationContext getApplicationContext() {
return new GetApplicationContext();
}
4、调用前置处理器方法、再调用initMethod方法、再调用后置处理器方法,代码如:
public class TestBeanPostProcessor implements BeanPostProcessor{
//前置处理器
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization" + " " + beanName);
return bean;
}
//后置处理器
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization" + " " + beanName);
return bean;
}
private void initMethod() {
System.out.println("call initMethod");
}
}
@Bean(initMethod = "initMethod")
public TestBeanPostProcessor testBeanPostProcessor() {
return new TestBeanPostProcessor();
}
这里我们可以看到前置和后置处理器方法,对initMethod方法进行前后拦截,这也是aop的思想(后续会说),我们先记住后置处理器方法(aop代理对象和被代理对象是在这里实现绑定)。我们是实现BeanPostProcessor接口实现前置和后置处理器方法。
5、注入容器,使用与销毁(如果注解了@Bean(destroyMethod = "destroyMethod"),将会被调用);
以上代码不完整,如果要可加我的联系方式。
4、aop:
aop其实是一种编程思想,编码发展过程可简述为,过程化开发(早期汇编和C语言时代),再到面向对象开发(c++、java、c#),最后到面向切面(aop),aop本质是无感知(动态链编)对实现的代码进行拦截,如:mybatis访问数据库时的事务注解,用于事务开启,提交或回滚。
aop有前置、后置、环绕、运行、异常5类切面通知,如果我们同时开启,运行和异常将是互斥的,也就是说如果发生异常,运行通知不会执行,致于其它切面通知执行顺序(切面通知调用执行顺序,用到了责任链设计模式。),请运行代码自行总结,代码如下:
1、基于eclipse创建一个简单的maven工程,并在pom.xml引入所需依赖,如:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
<!-- aop -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
</dependencies>
2、定义切面类,指定切入口(即扫包指定),开启切面通知(前置、后置、环绕、运行、异常),代码如下:
package com.springaop.testaop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAop {
@Pointcut("execution (* com.springaop.serviceaop..*.*(..))")
public void logAop() {
}
@Before("logAop()")
public void doBefore(JoinPoint joinPoint) {
System.out.println("before + 前置通知");
}
@After("logAop()")
public void doAfter(JoinPoint joinPoint) {
System.out.println("after + 后置通知");
}
@AfterReturning("logAop()")
public void afterReturning(JoinPoint joinPoint) {
System.out.println("afterReturning + 运行通知");
}
@AfterThrowing("logAop()")
public void afterThrowing(JoinPoint joinPoint) {
System.out.println("afterThrowing + 异常通知");
}
@Around("logAop()")
public void doAround(ProceedingJoinPoint joinPoint)throws Throwable{
System.out.println("doAround + 环绕通知(s)");
joinPoint.proceed();
System.out.println("doAround + 环绕通知(e)");
}
}
3、定义实现层,用于被aop切面测试,代码如:
package com.springaop.serviceaop;
import org.springframework.stereotype.Component;
@Component
public class LogAopService {
public void testAop() throws Exception {
System.out.println("test testAop");
int i = 10;
//i = 1 / 0; //用于测试异常切面通知
System.out.println(i);
}
}
4、定义Spring注解类( @Configuration ),注解类相当于早期的xml注解,本质就是将对象注入到Spring容器,代码如下:
package com.springaop.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;
import com.springaop.testaop.LogAop;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan({"com.springaop.serviceaop","com.springaop.testaop"})
public class MySpringAop {
}
相关注解说明:
@Component:将定义类注入Spring容器;
@EnableAspectJAutoProxy:开启aop;
@Aspect:定义切面类;
@Pointcut:定义切入口;
@ComponentScan:扫包将类注入Spring容器;
5、定义Spring容器启动类,测试aop,代码如下:
package com.springaop;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.springaop.config.MySpringAop;
import com.springaop.serviceaop.LogAopService;
public class Test1 {
private static AnnotationConfigApplicationContext applicationContext;
public static void main(String[] args) {
//通过java类注解方式,启动spring容器。
applicationContext = new AnnotationConfigApplicationContext(MySpringAop.class);
if (null == applicationContext){
System.out.println("start spring fail");
return;
}
LogAopService logAopService = applicationContext.getBean("logAopService", LogAopService.class);
try {
logAopService.testAop();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("over");
}
}
以上代码自行运行测试,现在我们来思考Spring aop怎么实现动态切入?
其实Spring是在bean对象生成时,后置处理器方法里创建代理对象实现切入,而这个切入的逻辑,是@EnableAspectJAutoProxy这个注解完成的,该注解内容如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
@Import(AspectJAutoProxyRegistrar.class),@Import将会把AspectJAutoProxyRegistrar注入到Spring容器,完成动态代理对象的创建,当bean容器注入Spring容器时,如果被@Pointcut切入(扫包),就会在后置处理器方法里完成切入,实现无感知拦截。
Spring创建代理对象(即实现aop)有两种方式,如果被代理类有实现接口就用jdk动态代理,如果没有实现就用cglib动态代理。
最后总结一下,SpringAop 综合运用cglib和jdk动态代理,实现代理对象创建,如果被代理类有实现接口就用jdk动态代理,如果没有实现就用cglib动态代理,并在后置处理器调用AspectJAutoProxyRegistrar方法完成代理对象与被代理对象绑定,实现切面。
5、循环依赖:
循环依赖其实也没什么好写的,很多博文或者其它,我感觉都写得太繁杂了,无非事注入Spring的Bean对象,出现相互依赖创建,即我中有你,你中有我,并且不是单例模式。
如:
public class A{
@Autowired
private B b;
.....
}
public class B{
@Autowired
private A a;
.....
}
@Configuration
public class MySpringConfig {
@Bean
@Scope("prototype")
public A a() {
return new A();
}
@Bean
@Scope("prototype")
public B b() {
return new B();
}
}
那如何解决,使用单例,从逻辑层绕开,最后可能有人会问单例是如何解决循环依赖,什么是Spring三级缓存?
先来引入一个概念,完整对象和非完整对象,完整对象是指对象创建了,所有属性已经赋值,非完整对象是指对象创建了,属性没有赋值。如代码:
HashMap<Object,Object> objectHashMap = new HashMap<Object,Object>();
objectHashMap.put("A", new A());
objectHashMap.put("B", new B());
A a = (A)objectHashMap.get("A");
B b = (B)objectHashMap.get("B");
a.SetB(b); //a未赋值前是非完整对象
b.SetA(a); //b未赋值前是非完整对象
其实上面代码就是Spring解决单例循环依赖的方式,Spring用的是递归调用函数的方式。
有了上面的概念,我们来看Spring使用三级缓存解决单例循环依赖。
Spring使用的三级缓存集合。
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
singletonObjects:是一级缓存,缓存完整对象,即创建成功的对象,并且所有属性已经赋值;
earlySingletonObjects:是二级缓存;
singletonFactories:是三级缓存;
singletonsCurrentlyInCreation:用来标记开始创建的对象;
核心代码请看中文注解就行。
//看代码入口函数,该函数完成bean的创建,代码在该类下:org.springframework.beans.factory.support.AbstractBeanFactory
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 从缓存中获取对象,
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 从缓存中没有获取到对象
//判断是否是多例循环依赖,如果是抛出异常,所以Spring没有解决多例的循环依赖。
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
getBean(dep);
}
}
// Create bean instance.
if (mbd.isSingleton()) {
/*
我们创建对象是单例,因此将会走这里。
getSingleton(beanName, () -> {可理解为标记对象创建
*/
sharedInstance = getSingleton(beanName, () -> {
try {
//标记完了就去创建对象
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
//从缓存中取象
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//首先从一级缓存,取到直接返回。
Object singletonObject = this.singletonObjects.get(beanName);
/*isSingletonCurrentlyInCreation标识对象没有创建,如果对象开始创建了将会在singletonsCurrentlyInCreation中标记*/
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//一级缓存没有查询二级缓存,二级有就直接返回。
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//二级缓存再没有,再查询三级缓存,三级缓存没有就返回空。
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//三级有把其放入二级并返回。
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
//标识该对象已经开始创建了
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
//属性赋值成功以后(完整对象),最后把对象放放到一级缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
//标识该对象已经开始创建了
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
//开始创建bean对象
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
//这里去创建bean对象
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException ex) {
// A previously detected exception with proper bean creation context already...
throw ex;
}
catch (ImplicitlyAppearedSingletonException ex) {
// An IllegalStateException to be communicated up to DefaultSingletonBeanRegistry...
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
//这里去创建bean对象
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//反射创建bean对象,调用无参数构告函数,记住这里它是非完整对象。
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
/*
这里判断是单例,且是循环依赖,且是标记中已有,标中已有指开始创建了。
*/
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
//为true就走这里
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//把非完整对象放入三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//在这里给非完整对象属性进行赋值,如果属性也是Spring容器对象,它也会走doGetBean()获取对象给属性赋值。
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
//把非完整对象放入三级缓存
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
//如果一级缓存没有该对象,就把该对象放入三级缓存
if (!this.singletonObjects.containsKey(beanName)) {
//放入三级缓存(非完整对象)
this.singletonFactories.put(beanName, singletonFactory);
//从二级缓存移出
this.earlySingletonObjects.remove(beanName);
//记录beanname,可以理解为Spring的创建对象的日志记录
this.registeredSingletons.add(beanName);
}
}
}
看上面代码时,要有这个逻辑,首先创建自己时是在三级缓存(非完整对象),创建好了自己再去给属性赋值,属性被同样的方法递归创建,创建时发现依赖的对象(属性)在三级缓存就把其移到二级缓存,如果没有继续递归创建,直到属性赋值完(完整对象),再把自己移到一级缓存,二级和三级存储的是非完整对象,一级存储的是完整对象,其实这里我认为设计最巧妙的是二级缓存,我无法用文字表述,自己悟吧!二级缓存是防第三者利器,如果只有两级缓存,将防不到第三者。