我们继续上次的,上次讲了存在单例的情况,可能是普通对象,也可能是FactoryBean
,是FactoryBean
可能是要获取创建的对象。这次我们继续第二段。这段主要是判断是不是正在创建的原型类型,原型类型无法解决循环应用问题,会报异常。为什么原型不能循环引用呢,因为原型的定义就是每次都是需要新的对象,如果A
是原型,引用B
,这个时候B
也是要被创建的,如果B
是原型,也引用A
,那A
也要被重新创建,然后A
里面又要引用B
,又重新创建,这样下去就变成创建的死循环了,所以原型循环引用不行。如果发现父工厂存在,bean定义不存在,就会从父工厂去找,让父工厂去创建,这个情况比较少,所以暂时不深入了。
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {//原型的循环引用报错
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.如果bean定义不存在,就检查父工厂是否有
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 if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
继续下面一段,首先判断是否仅仅是检查类型,不是的话才会标记成已经创建了,或者正要创建,并且会设置需要bean
定义合并标记,以便后面获得最新的bean
定义。然后会处理dependsOn
依赖,有依赖的会优先处理依赖,这个后面讲。
//标记已经创建
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);//获取合并后的bean定义
checkMergedBeanDefinition(mbd, beanName, args);
//保证dependsOn的先实例化
// 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);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
其实就是放进一个alreadyCreated
集合里做标记,但是这里会设置需要合并bean
定义,这个在前面讲过,因为在创建之后可能会有很多处理器处理过bean
定义,所以这里要把bean
定义做一个合并,也就是刷新。
protected void markBeanAsCreated(String beanName) {
if (!this.alreadyCreated.contains(beanName)) {
synchronized (this.mergedBeanDefinitions) {
if (!this.alreadyCreated.contains(beanName)) {//需要重新获取合并一下bean定义,以免元数据被同时修改
clearMergedBeanDefinition(beanName);
this.alreadyCreated.add(beanName);
}
}
}
}
protected void clearMergedBeanDefinition(String beanName) {
RootBeanDefinition bd = this.mergedBeanDefinitions.get(beanName);
if (bd != null) {
bd.stale = true;//需要合并
}
}
我们还是来一般正常的创建吧,如果判断你是到了类型,就开始创建单例,这里传了一个lambda
表达式来创建bean
。
if (mbd.isSingleton()) {//如果是单例,准备创建单例
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
这个获取单例跟以前的不一样,需要创一个ObjectFactory
方法,也就是说,可能需要调用这个方法来获取。首先还是先获取下如果存在就返回了,否则就开始创建单例,先做开始创建的标记,然后创建对象,然后清除标记,最后加入到单例集合中。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);//获取
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {//单例是否在销毁中,报异常
throw new BeanCreationNotAllowedException...
}
beforeSingletonCreation(beanName);//创建前做个正在创建的标记
boolean newSingleton = false;//是否创建单例成功,感觉这个用处不大
...
try {//调用ObjectFactory的getObject创建bean对象
singletonObject = singletonFactory.getObject();
newSingleton = true;//只要获取了就是新单例
}
catch (IllegalStateException ex) {
...
}
catch (BeanCreationException ex) {
...
}
finally {
...
afterSingletonCreation(beanName);
}
if (newSingleton) {//如果是新的单例,就加入到单例集合
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
调用ObjectFactory
的getObject
创建bean
对象,其实里面就是这个方法,首先要进行创建类型的解析,解析过程比较复杂,后面讲,因为我们只有名字,不知道要创建什么类型,然后进行方法覆盖,主要是处理look-up
方法,CGLIB动态代理实现一些look-up
方法,需要检查能不能覆盖,再创建之后进行处理器处理,这个也是扩展点,然后创建。
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
...
RootBeanDefinition mbdToUse = mbd;
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);//解析出bean的类型
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {//能解析出来,没有BeanClass只有BeanClassName
mbdToUse = new RootBeanDefinition(mbd);//重新创建RootBeanDefinition
mbdToUse.setBeanClass(resolvedClass);//设置解析的类型
}
try {//准备方法覆盖,处理look-up方法
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
...
}
try {//后置处理器在实例化之前处理,如果返回不为null,直接就返回了
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
...
}
try {//真正创建
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
...
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
...
}
catch (Throwable ex) {
...
}
}
在实例化之前被处理器处理。如果有处理器返回不为null
的话,就直接进行初始化了,最后会设置是否被解析了。如果被处理器处理了,比如动态代理后返回,就直接返回对象了。
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {//非合成的,且有InstantiationAwareBeanPostProcessors
Class<?> targetType = determineTargetType(beanName, mbd);//获取类型
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);//是否解析了
}
return bean;
}
InstantiationAwareBeanPostProcessor
类型的处理器处理,返回的是一个Object
对象, 也就是说这里可以做一些代理的事,如果发现有一个处理器返回的不是null
,就直接返回了。
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
如果发现applyBeanPostProcessorsBeforeInstantiation
返回的对象不是null
,就说明已经有对象了,所以就会进行初始化后处理,如果返回null的话就说明不处理了,直接返回了,否则就进行处理。这里有点像装饰器,把existingBean
一层层的装饰,最后返回,如果不想装饰了就直接返回。
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
如果处理器没有返回对象的话,就会进行最后的对象创建doCreateBean
,我们后面说吧。
这个可以在创建对象之前进行干预,比如我想干坏事,我偷偷的找个地方加入一个TestInstantiationAwareBeanPostProcessor
处理器,然后返回一个TestBean
的对象,这样别人就无法获取到userDao
类型了。
public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if(beanName.equals("userDao")){
TestBean testBean = new TestBean();
return testBean;
}
return null;
}
}
public class TestBean {
}
配置类里是可以获取UserDao
实例的:
@Configuration
public class MyConfig {
@Bean
public UserDao userDao(){
return new UserDaoImple();
}
}
@Test
public void InstantiationAwareBeanPostProcessorTest() throws Exception {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(MyConfig.class);
//添加处理器,搞破坏
applicationContext.getBeanFactory().addBeanPostProcessor(new TestInstantiationAwareBeanPostProcessor());
applicationContext.refresh();
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
System.out.println(userDao);
}
在初始化的时候应该是UserDao
的,我给他返回了TestBean
实例,他还没用,所以不会报错。
然后我们进行获取就报异常啦:
java.lang.ClassCastException: class com.ww.pojo.TestBean cannot be cast to class com.ww.pojo.UserDao (com.ww.pojo.TestBean and com.ww.pojo.UserDao are in unnamed module of loader 'app')
当然项目里没人这么干,正确的做法比如做动态代理,我再来一个JDK
的动态代理试试,其实你看了这个就可以理解AOP
怎么实现的。
正常应该这样:
处理器返回JDK
动态代理后:
这个就是可以扩展返回一个JDK
动态代理对象的。
public class TestJDKProxyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if(beanName.equals("userDao")){
UserDao userDaoimpl=new UserDaoImple();
UserDao userDao= (UserDao) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{UserDao.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是JDK动态代理的");
method.invoke(userDaoimpl);
return null;
}
});
return userDao;
}
return null;
}
}
这个记得要判断beanName
,不然你可能把内部的处理器给改了,类型不对就报错了,比如:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' is expected to be of type 'org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor' but was actually of type 'com.ww.pojo.TestBean'
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' is expected to be of type 'org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor' but was actually of type 'com.ww.pojo.TestBean'
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:395)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:89)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532)
at com.ww.AppTest.InstantiationAwareBeanPostProcessorTest(AppTest.java:38)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
有点长了,后面我们继续doCreateBean
讲解。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。