美文网首页
spring4 IOC的init-method源码

spring4 IOC的init-method源码

作者: sunpy | 来源:发表于2020-09-03 23:36 被阅读0次

    init-method的例子

    public class User {
        
        public User() {
            System.out.println("User实例已经创建!");
        }
    
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        
        public void initUser() {
            System.out.println("Bean初始化执行的方法");
        }
    }
    
    <beans:bean id="user" class="cn.spy.spring.source.code.User" init-method="initUser">
            <beans:property name="name" value="zhangsan"></beans:property>
    </beans:bean>
    
    public static void main(String[] args) {
         ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
    }
    

    结果:



    为什么没有获取bean,就已经加载bean了?
    由于在spring ioc初始化阶段,实例化非懒加载方式的一些单例。而这些bean被实例化之后,其init-method字段配置的方法名称作为bean的属性(注意:记住的是方法名称),被检查到如果存在,则回调该方法,回调方式只是通过方法名称进行反射而已。

    读取bean配置的init-method标签

    读取init-method标签是伴随着读取bean标签是一样的,只是作为bean标签的子节点而已。使用Dom技术读取XML文档(ResouceLoader读取),得到Resouce对象,将Resouce对象转化为Document对象。获取Document中的Element元素对象都封装为BeanDefinition,将BeanDefinition添加到BeanDefinitionMap集合映射中,最终添加到Spring IOC的管理容器BeanFactory(具体是DefaultListBeanFactory)。


    处理给定的Bean标签的方法processBeanDefinition

    执行init-method配置的方法

    执行init-method配置的方法已经在beanFactory的BeanDefinitionMap中。



    执行init-method配置的方法的流程:


    4.png

    从refresh方法开始,finishBeanFactoryInitialization方法; 预先加载bean,从BeanDefinitionMap中加载bean名称集合,遍历集合,调用getBean方法先生成bean,最后委派到doCreateBean方法:createBeanInstance创建bean实例,populateBean方法为实例属性填充,之后初始化方法initializeBean:检查bean是否注册了init-method,如果注册了,那么执行回调,调用init-method注册的方法,只是采用反射的方式来执行该方法。

    protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
                throws Throwable {
        // 判断传入的bean是否为InitializingBean类型的实例
        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (logger.isDebugEnabled()) {
                logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
            // 传入的bean如果实现了InitializingBean接口
            // 那么可以执行afterPropertiesSet方法
            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        @Override
                        public Object run() throws Exception {
                            ((InitializingBean) bean).afterPropertiesSet();
                            return null;
                        }
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }
    
        if (mbd != null) {
            // 获取init-method指定方法的名称
            String initMethodName = mbd.getInitMethodName();
            if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                // 反射方式执行该方法
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }
    
    // 使用jdk反射方式调用bean指定的init-method方法
    protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
        String initMethodName = mbd.getInitMethodName();
        final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
                BeanUtils.findMethod(bean.getClass(), initMethodName) :
                ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
        if (initMethod == null) {
            if (mbd.isEnforceInitMethod()) {
                throw new BeanDefinitionValidationException("Couldn't find an init method named '" +
                        initMethodName + "' on bean with name '" + beanName + "'");
            }
            else {
                if (logger.isDebugEnabled()) {
                    logger.debug("No default init method named '" + initMethodName +
                            "' found on bean with name '" + beanName + "'");
                }
                // Ignore non-existent default lifecycle methods.
                return;
            }
        }
    
        if (logger.isDebugEnabled()) {
            logger.debug("Invoking init method  '" + initMethodName + "' on bean with name '" + beanName + "'");
        }
    
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                @Override
                public Object run() throws Exception {
                    ReflectionUtils.makeAccessible(initMethod);
                    return null;
                }
            });
            try {
                AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    @Override
                    public Object run() throws Exception {
                        initMethod.invoke(bean);
                        return null;
                    }
                }, getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {
                InvocationTargetException ex = (InvocationTargetException) pae.getException();
                throw ex.getTargetException();
            }
        }
        else {
            try {
                ReflectionUtils.makeAccessible(initMethod);
                initMethod.invoke(bean);
            }
            catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:spring4 IOC的init-method源码

          本文链接:https://www.haomeiwen.com/subject/rwlasktx.html