spring源码分析:Aware接口让你的bean对容器直接操作

Posted Small leaf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring源码分析:Aware接口让你的bean对容器直接操作相关的知识,希望对你有一定的参考价值。

相信大家都知道很多其他框架,比如mybatis,shiro等等,spring框架本身有些类会实现ApplicationContextAware,BeanFactoryAware或者等等其他XXXAware,这是用来干嘛呢?

spring容器来管理bean。如果说bean需要知道容器的状态获取容器的信息直接使用容器那么就需要实现XXXAware来实现了。

以下具体讲解spring是如何让bean直接操作spring容器的。

package com.share1024.aware;

import org.springframework.stereotype.Component;

/**
 * @author : yesheng
 * @Description :
 * @Date : 2017/11/7
 */
@Component
public class User 

    public void say()
        System.out.println("i am a student");
    
package com.share1024.aware;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.servlet.ServletConfig;

/**
 * @author : yesheng
 * @Description :
 * @Date : 2017/11/7
 */
@Component
public class CustomApplicationAware implements ApplicationContextAware ,BeanFactoryAware

    private ApplicationContext applicationContext;

    private BeanFactory beanFactory;

    private ServletConfig servletConfig;

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 
        this.applicationContext = applicationContext;
    

    public void say()
        User user = (User) applicationContext.getBean("user");
        user.say();
    
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException 
        this.beanFactory = beanFactory;
    

    public void say2()
        User user = (User) beanFactory.getBean("user");
        System.out.println("from beanFactory");
        user.say();
    


package com.share1024.aware;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author : yesheng
 * @Description :
 * @Date : 2017/11/7
 */
@Configuration
@ComponentScan("com.share1024.aware")
public class JavaConfig 


    public static void main(String[] args) 
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(JavaConfig.class);
        CustomApplicationAware customApplicationAware = (CustomApplicationAware) applicationContext.getBean("customApplicationAware");
        customApplicationAware.say();
        customApplicationAware.say2();
    

运行结果

i am a student
from beanFactory
i am a student

CustomApplicationAware实现了ApplicationContextAware和BeanFactoryAware接口。通过set方法就让容器获得ApplicationContext和BeanFactory对象,那么我们可以用这两个对象对spring容器进行操作了。
使用起来确实很简单,我们去看看是如何实现这两个set方法的,首先提下spring容器对bean初始化分为三个步骤,第一资源文件的定位(xml,javaconfig),二、BeanDefinition的载入,三向IOC容器注册这些BeanDefinition。

而我们这里是发现在Ioc容器的依赖注入环节。也就是getBean环节。

先看看ApplicationContextAware和BeanFactoryAware

public interface ApplicationContextAware extends Aware 
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;


public interface BeanFactoryAware extends Aware 
void setBeanFactory(BeanFactory beanFactory) throws BeansException;

public interface Aware 

两个接口都实现了Aware,通过多态实现不同的Aware。

debug到

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(JavaConfig.class);

这行代码,go

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) 
        this();
        register(annotatedClasses);
        refresh();
    

我这里使用的java配置文件的方式refresh是spring对bean初始化初始化,依赖注入核心环节。

public void refresh() throws BeansException, IllegalStateException 
        synchronized (this.startupShutdownMonitor) 
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try 
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            

            catch (BeansException ex) 
                if (logger.isWarnEnabled()) 
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            

            finally 
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            
        
    

我们直接定位到finishBeanFactoryInitialization(beanFactory)。只要bean不是抽象,是单例,不是懒加载就会在这里进行依赖注入。

@Override
    public void preInstantiateSingletons() throws BeansException 
        if (this.logger.isDebugEnabled()) 
            this.logger.debug("Pre-instantiating singletons in " + this);
        

        // Iterate over a copy to allow for init methods which in turn register new bean definitions.
        // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
        List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

        // Trigger initialization of all non-lazy singleton beans...
        for (String beanName : beanNames) 
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) 
                if (isFactoryBean(beanName)) 
                    final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) 
                        isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() 
                            @Override
                            public Boolean run() 
                                return ((SmartFactoryBean<?>) factory).isEagerInit();
                            
                        , getAccessControlContext());
                    
                    else 
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean<?>) factory).isEagerInit());
                    
                    if (isEagerInit) 
                        getBean(beanName);
                    
                
                else 
                    getBean(beanName);
                
            
        

        // Trigger post-initialization callback for all applicable beans...
        for (String beanName : beanNames) 
            Object singletonInstance = getSingleton(beanName);
            if (singletonInstance instanceof SmartInitializingSingleton) 
                final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
                if (System.getSecurityManager() != null) 
                    AccessController.doPrivileged(new PrivilegedAction<Object>() 
                        @Override
                        public Object run() 
                            smartSingleton.afterSingletonsInstantiated();
                            return null;
                        
                    , getAccessControlContext());
                
                else 
                    smartSingleton.afterSingletonsInstantiated();
                
            
        
    

直接进入getBean(beanName);

AbstractBeanFactory.doGetBean

if (mbd.isSingleton()) 
                    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() 
                        @Override
                        public Object getObject() throws BeansException 
                            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);
                

getSingleton第二个参数是一个接口,传入一个自己的实现。JdbcTemplate,RedisTemplate等等很多地方都有这样的实现。

进入createBean(beanName, mbd, args);

AbstractAutowireCapableBeanFactory.createBean

protected Object createBean(String beanName, RootBeanDefinition mbd, 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);
        

        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) 
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        
        return beanInstance;
    

进入 Object beanInstance = doCreateBean(beanName, mbdToUse, args);
大致上看这几个方法这几个

...
//初始化类的构造函数
if (instanceWrapper == null) 
            instanceWrapper = createBeanInstance(beanName, mbd, args);

...
Object exposedObject = bean;
        try 
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) 
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            
        
...
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) 
        if (System.getSecurityManager() != null) 
            AccessController.doPrivileged(new PrivilegedAction<Object>() 
                @Override
                public Object run() 
                    invokeAwareMethods(beanName, bean);
                    return null;
                
            , getAccessControlContext());
        
        else 
            invokeAwareMethods(beanName, bean);
        

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) 
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        

        try 
            invokeInitMethods(beanName, wrappedBean, mbd);
        
        catch (Throwable ex) 
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        

        if (mbd == null || !mbd.isSynthetic()) 
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        
        return wrappedBean;
    
private void invokeAwareMethods(final String beanName, final Object bean) 
        if (bean instanceof Aware) 
            if (bean instanceof BeanNameAware) 
                ((BeanNameAware) bean).setBeanName(beanName);
            
            if (bean instanceof BeanClassLoaderAware) 
                ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
            
            if (bean instanceof BeanFactoryAware) 
                ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            
        
    

BeanNameAware、BeanClassLoaderAware、BeanFactoryAware这三个接口就在这里来具体给类来进行set。

Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) 
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        
    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException 

        Object result = existingBean;
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) 
            result = beanProcessor.postProcessBeforeInitialization(result, beanName);
            if (result == null) 
                return result;
            
        
        return result;
    

ApplicationContextAwareProcessor对应的是ApplicationContextAware相应的处理类。

ApplicationContextAwareProcessor implements BeanPostProcessor

此时会调用ApplicationContextAwareProcessor.postProcessBeforeInitialization


    @Override
    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException 
        AccessControlContext acc = null;

        if (System.getSecurityManager() != null &&
                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) 
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        

        if (acc != null) 
            AccessController.doPrivileged(new PrivilegedAction<Object>() 
                @Override
                public Object run() 
                    invokeAwareInterfaces(bean);
                    return null;
                
            , acc);
        
        else 
            invokeAwareInterfaces(bean);
        

        return bean;
    

    private void invokeAwareInterfaces(Object bean) 
        if (bean instanceof Aware) 
            if (bean instanceof EnvironmentAware) 
                ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
            
            if (bean instanceof EmbeddedValueResolverAware) 
                ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
                        new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
            
            if (bean instanceof ResourceLoaderAware) 
                ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
            
            if (bean instanceof ApplicationEventPublisherAware) 
                ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
            
            if (bean instanceof MessageSourceAware) 
                ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
            
            if (bean instanceof ApplicationContextAware) 
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            
        
    

EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware进行处理。

从上面来看,以后我们需要bean中直接对IOC容器进行操作,可以实现相应的接口。


菜鸟不易,望有问题指出,共同进步

以上是关于spring源码分析:Aware接口让你的bean对容器直接操作的主要内容,如果未能解决你的问题,请参考以下文章

Spring原理分析-Aware接口&InitializingBean

死磕 Spring----- IOC 之 深入分析 Aware 接口

Spring - BeanFactoryAware扩展接口

Spring - BeanFactoryAware扩展接口

Aware接口

[死磕 Spring 27/43] --- IOC 之 深入分析 Aware 接口