spring bean的重新加载

架构体系  

  在谈spring bean的重新加载前,首先我们来看看spring ioc容器。

  spring ioc容器主要功能是完成对bean的创建、依赖注入和管理等功能,而这些功能的实现是有下面几个组件完成的:

  Resource:对资源的抽象,不同的资源有不同的实现,例如:ClasspathResource、FileSystemResource。。。

  BeanDefinition:描述一个具体的bean,里面包含了bean的一些基本信息,不同类型的bean也有不同的实现类:ScannedGenericBeanDefinition、RootBeanDefinition

  BeanDefinitionReader:将资源转化BeanDefinition的一个接口,针对不同类型的资源有不同的实现:XmlBeanDefinitionReader、PropertiesBeanDefinitionReader

  BeanFactory:bean工厂,实现了对bean的创建、注入于与管理

  ApplicationContext:应用上下文,持有BeanFactory对象

  

  BeanFactory

     SpringBean的创建是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者管理对象间的依赖关系提供了很多便利和基础服务,在Spring中有许多的IOC容器的实现供用户选择和使用

    spring bean的重新加载

    BeanFactory定义了工厂类基本的操作,BeanFactory有三个直属子类:AutowireCapableBeanFactory,HierarchicalBeanFactory,ListableBeanFactory;这个三个子类定义了spring对不同bean的处理。

spring对不同的场景提供了不同实现,下面的类

    AutowireCapableBeanFactory:定义了对bean的创建与注入

    HierarchicalBeanFactory:定义了对结构化的bean进行处理

    ListableBeanFactory:定义了对bean的匹配查找

    DefaultListableBeanFactory:以上三个接口的默认实现。提供了bean定义的注册与缓存和对単例bean的初始化

  BeanDefinition

    BeanDefinition是对一个具体的bean的描述,包括了initMethodName、destroyMethodName、资源文件等 。  

  spring bean的重新加载

bean 创建注入

  ioc容器的初始化过程包括对资源的定位、资源的解析、beanDefinition的注册、bean的创建与注入。

    refresh是整个ioc容器创建的入口

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

            // 实现了对资源的定位,解析,beanDefinition的注册
            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();

                // 初始scope为singleton和不是延迟加载的bean
                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();
            }
        }
    }

  resource的解析和beanDefinition的注册

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

    //beanDefintion的注册
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // 将beanDefintion注册到beanFactory
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

  单例bean的创建入口。

public void preInstantiateSingletons() throws BeansException {

        List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

        // 创建bean
        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);
                }
            }
        }
    }

  spring在内部维护了一个缓存用来保存已创建的单例bean,所以spring在创建bean的时候会首先在缓存里看有没有,如果没有则创建,这同时也为循环依赖提供了支持,spring不对是原型的bean提供循环依赖支持

    protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {

        final String beanName = transformedBeanName(name);
        Object bean;

        // 首先从缓存里取
        Object sharedInstance = getSingleton(beanName);

        //省略其它代码
        。。。
        。。。
        。。。
    }

  创建bean

     BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }

  bean注入过程,根据注入类型注入

if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

            // Add property values based on autowire by name if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }

            // Add property values based on autowire by type if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }

            pvs = newPvs;
        }

  一般我们在项目中使用@Autowired注解是由AutowiredAnnotationBeanPostProcessor这个类实现注入的

    public PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

        //获取注入元数据
        //AutowiredAnnotationBeanPostProcessor里面维护了一个变量用户缓存注入元数据
        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
        try {
            metadata.inject(bean, beanName, pvs);//依赖注入
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
        }
        return pvs;
    }

    public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
        Collection<InjectedElement> elementsToIterate =
                (this.checkedElements != null ? this.checkedElements : this.injectedElements);
        if (!elementsToIterate.isEmpty()) {
            boolean debug = logger.isDebugEnabled();
            for (InjectedElement element : elementsToIterate) {
                if (debug) {
                    logger.debug("Processing injected element of bean '" + beanName + "': " + element);
                }
                element.inject(target, beanName, pvs);
            }
        }
    }

    protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
            Field field = (Field) this.member;
            try {
                Object value;
                if (this.cached) {
                    value = resolvedCachedArgument(beanName, this.cachedFieldValue);
                }
                else {
                    DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
                    desc.setContainingClass(bean.getClass());
                    Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
                    TypeConverter typeConverter = beanFactory.getTypeConverter();
                    //获取依赖的bean,会递归调用getBean()方法,直到获取到的bean没有任何依赖
                    value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
                    synchronized (this) {
                        if (!this.cached) {
                            if (value != null || this.required) {
                                this.cachedFieldValue = desc;
                                registerDependentBeans(beanName, autowiredBeanNames);
                                if (autowiredBeanNames.size() == 1) {
                                    String autowiredBeanName = autowiredBeanNames.iterator().next();
                                    if (beanFactory.containsBean(autowiredBeanName)) {
                                        if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                                            this.cachedFieldValue = new RuntimeBeanReference(autowiredBeanName);
                                        }
                                    }
                                }
                            }
                            else {
                                this.cachedFieldValue = null;
                            }
                            this.cached = true;
                        }
                    }
                }
                if (value != null) {
                    ReflectionUtils.makeAccessible(field);
                    field.set(bean, value);//通过反射设置值
                }
            }
            catch (Throwable ex) {
                throw new BeanCreationException("Could not autowire field: " + field, ex);
            }
        }
    }

 spring bean的重新加载

  大家都知道我们在eclipse debug模式运行应用程序时,当我们修改了方法体内的代码时,是不需要马上重启就能生效的(其中的原理暂时没找到)。现在我们要实现的spring bean的重新加载,不仅可实现对方法体外做了代码修改能生效,也不需要在dubug模式运行。要实现这样的功能,首先我们要收集到spring为我们创建了哪些bean,然后监听bean对应的字节码文件有没有发生改变,当发生改变时,重新加载。

  spring bean的收集

  spring在创建bean时,使用了beanDefinition来描述一个bean,并把beanDefinition维护在DefaultListableBeanFactory.beanDefinitionMap。收集bean 可以在spring容器启动完成时获取beanFactory并持有,创建一个ApplicationListener的实现类

  

public class Startup implements ApplicationListener<ContextRefreshedEvent> {

    public void onApplicationEvent(ContextRefreshedEvent event) {
        BeanWatch beanWatch = new BeanWatch(event.getApplicationContext());
        beanWatch.start();
    }
}

  获取需要监听的bean

private Map<String, ClassBeanDefinition> findWatchBean() {
        Map<String, ClassBeanDefinition> watchBeans = new HashMap<String, ClassBeanDefinition>();
        for (String name : applicationContext.getBeanDefinitionNames()) {// 获取spring管理的所有bean名称
            Object bean = applicationContext.getBean(name);// 获取bean
            BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(name);
            Class<?> clazz = bean.getClass();
            URL resource = clazz.getResource("");
            File file = new File(resource.getPath() + clazz.getSimpleName() + ".class");
            ClassBeanDefinition classBeanDefinition = new ClassBeanDefinition();
            classBeanDefinition.setBeanDefinition(beanDefinition);
            classBeanDefinition.setFile(file);
            classBeanDefinition.setBeanName(name);
            watchBeans.put(name, classBeanDefinition);
        }
        return watchBeans;
    }

  字节码重新加载

  收集完字节码文件之后要做的就是,对文件的监听,当一个文件发生改变时,我们需要做的是重新将改变的class文件加载进来,但spring为我们创建bean时已经将class文件加载进来了,由于java的类加载机制,一个类只会加载一次,所以我们需要自定义一个classLoader去动态的加载我们需要的类

public class DynamicClassLoader extends ClassLoader {

    public DynamicClassLoader(ClassLoader parent) {
        super(parent);
    }

    public Class<?> loadClass(File file,String className) throws ClassNotFoundException {
        try {
            InputStream input = new FileInputStream(file);
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            int data = input.read();
            while (data != -1) {
                buffer.write(data);
                data = input.read();
            }
            input.close();
            byte[] classData = buffer.toByteArray();
            return defineClass(className, classData, 0, classData.length);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}

重新加载bean

  当我们拥有了最新的字节码时,我们需要把bean工厂维护的beanDefinition修改为最新的字节码并把spring工厂对应的bean缓存删除,然后再调用beanFactory的getBean()方法

public void reloadBean(ClassBeanDefinition classBeanDefinition, Class<?> clazz, DynamicClassLoader classLoader) {
        try {
            //只针对ScannedGenericBeanDefinition做实现
            ScannedGenericBeanDefinition beanDefinition = (ScannedGenericBeanDefinition) beanDefinitionMap.get(classBeanDefinition.getBeanName());
            beanDefinition.setBeanClass(clazz);
            // 删除beanFactory缓存的bean
            factoryBeanObjectCache.remove(classBeanDefinition.getBeanName());
            // 删除合并的BeanDefinitions
            mergedBeanDefinitions.remove(classBeanDefinition.getBeanName());
            Object bean = beanFactory.getBean(classBeanDefinition.getBeanName());
            reloadReferenceClass(classBeanDefinition, bean, classLoader);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

  到此我们已经把改变的bean重新加载进来,但是,如果该bean是别的bean的一个依赖,那么我们需要为有依赖了改变的bean重新进行注入。由于我们前面将bean加载进来时,bean的字节码是被不同的ClassLoader重新加载进来的,如果此时直接将有依赖的bean从缓存删掉,然后再调用getBean()会导致spring在为bean注入时抛ClassCastException,所以我们需要维护一个ClassLoader对象用来作为每次加载新字节码的ClassLoader的父ClassLoader。

public void reloadReferenceClass(ClassBeanDefinition classBeanDefinition, Object bean, DynamicClassLoader parent) {
        Class<?> typeClass = bean.getClass();
        Set<String> injectCacheKeys = findReferenceClass(typeClass.getName());
        DynamicClassLoader classLoader = new DynamicClassLoader(parent);
        Thread.currentThread().setContextClassLoader(classLoader);
        for (String cacheKey : injectCacheKeys) {// 将引用了该bean的类重新创建
            Map<String, InjectionMetadata> map = (Map<String, InjectionMetadata>) Reflections.getFieldValue(autowiredAnnotationBeanPostProcessor, "injectionMetadataCache");
            InjectionMetadata metadata = map.get(cacheKey);
            ClassBeanDefinition definition = beanDefinitions.get(cacheKey);
            try {
                Class<?> clazz = classLoader.loadClass(definition.getFile(), definition.getBeanDefinition().getBeanClassName());
                Field[] fields = clazz.getDeclaredFields();
                Collection<InjectedElement> injectedElements = (Collection<InjectedElement>) Reflections.getFieldValue(metadata, "injectedElements");
                Set<InjectedElement> checkedElements = (Set<InjectedElement>) Reflections.getFieldValue(metadata, "checkedElements");
                Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : injectedElements);
                for (Field f : fields) {
                    Class<?> type = f.getType();

                    if (type.isInstance(bean)) {
                        for (InjectedElement element : elementsToIterate) {
                            Field field = (Field) element.getMember();
                            if (field.getType().getName().equals(f.getType().getName())) {
                                Reflections.setFieldValue(element, "member", f);//修改spring维护的InjectedElement属性
                                break;
                            }
                        }
                    }
                }
                parentClassLoader = parent;
                reloadBean(definition, clazz, classLoader);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

  

上一篇:DOS攻击之详解--转载


下一篇:hive explode 行拆列