Как мне внедрить мои зависимости с помощью @Configurable в сочетании с readResolve ()

Фреймворк, который я разрабатываю для своего приложения, очень сильно зависит от динамически генерируемых объектов домена. Недавно я начал использовать Spring WebFlow, и теперь мне нужно иметь возможность сериализовать объекты моего домена, которые будут храниться в области потока.

Я провел небольшое исследование и выяснил, что могу использовать writeReplace() и readResolve(). Единственная загвоздка в том, что мне нужно найти фабрику в контексте Spring. Я пробовал использовать @Configurable(preConstruction = true) вместе с интерфейсом маркеров BeanFactoryAware.

Но beanFactory всегда является null, когда я пытаюсь использовать его в моем методе createEntity(). Ни конструктор по умолчанию, ни инжектор setBeanFactory() не вызываются.

Кто-нибудь пробовал это или что-то подобное? Я включил соответствующий класс ниже.

Заранее спасибо, Брайан

/*
 *  Copyright 2008 Brian Thomas Matthews Limited.
 *  All rights reserved, worldwide.
 *
 *  This software and all information contained herein is the property of
 *  Brian Thomas Matthews Limited. Any dissemination, disclosure, use, or
 *  reproduction of this material for any reason inconsistent with the
 *  express purpose for which it has been disclosed is strictly forbidden.
 */

package com.btmatthews.dmf.domain.impl.cglib;

import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.util.StringUtils;

import com.btmatthews.dmf.domain.IEntity;
import com.btmatthews.dmf.domain.IEntityFactory;
import com.btmatthews.dmf.domain.IEntityID;
import com.btmatthews.dmf.spring.IEntityDefinitionBean;

/**
 * This class represents the serialized form of a domain object implemented
 * using CGLib. The readResolve() method recreates the actual domain object
 * after it has been deserialized into Serializable. You must define
 * <spring-configured/> in the application context.
 * 
 * @param <S>
 *            The interface that defines the properties of the base domain
 *            object.
 * @param <T>
 *            The interface that defines the properties of the derived domain
 *            object.
 * @author <a href = "mailto:[email protected]">Brian Matthews</a>
 * @version 1.0
 */
@Configurable(preConstruction = true)
public final class SerializedCGLibEntity<S extends IEntity<S>, T extends S>
    implements Serializable, BeanFactoryAware
{
    /**
     * Used for logging.
     */
    private static final Logger LOG = LoggerFactory
        .getLogger(SerializedCGLibEntity.class);

    /**
     * The serialization version number.
     */
    private static final long serialVersionUID = 3830830321957878319L;

    /**
     * The application context. Note this is not serialized.
     */
    private transient BeanFactory beanFactory;

    /**
     * The domain object name.
     */
    private String entityName;

    /**
     * The domain object identifier.
     */
    private IEntityID<S> entityId;

    /**
     * The domain object version number.
     */
    private long entityVersion;

    /**
     * The attributes of the domain object.
     */
    private HashMap<?, ?> entityAttributes;

    /**
     * The default constructor.
     */
    public SerializedCGLibEntity()
    {
        SerializedCGLibEntity.LOG
            .debug("Initializing with default constructor");
    }

    /**
     * Initialise with the attributes to be serialised.
     * 
     * @param name
     *            The entity name.
     * @param id
     *            The domain object identifier.
     * @param version
     *            The entity version.
     * @param attributes
     *            The entity attributes.
     */
    public SerializedCGLibEntity(final String name, final IEntityID<S> id,
        final long version, final HashMap<?, ?> attributes)
    {
        SerializedCGLibEntity.LOG
            .debug("Initializing with parameterized constructor");

        this.entityName = name;
        this.entityId = id;
        this.entityVersion = version;
        this.entityAttributes = attributes;
    }

    /**
     * Inject the bean factory.
     * 
     * @param factory
     *            The bean factory.
     */
    public void setBeanFactory(final BeanFactory factory)
    {
        SerializedCGLibEntity.LOG.debug("Injected bean factory");

        this.beanFactory = factory;
    }

    /**
     * Called after deserialisation. The corresponding entity factory is
     * retrieved from the bean application context and BeanUtils methods are
     * used to initialise the object.
     * 
     * @return The initialised domain object.
     * @throws ObjectStreamException
     *             If there was a problem creating or initialising the domain
     *             object.
     */
    public Object readResolve()
        throws ObjectStreamException
    {
        SerializedCGLibEntity.LOG.debug("Transforming deserialized object");

        final T entity = this.createEntity();
        entity.setId(this.entityId);
        try
        {
            PropertyUtils.setSimpleProperty(entity, "version",
            this.entityVersion);
            for (Map.Entry<?, ?> entry : this.entityAttributes.entrySet())
            {
                PropertyUtils.setSimpleProperty(entity, entry.getKey()
                    .toString(), entry.getValue());
            }
        }
        catch (IllegalAccessException e)
        {
            throw new InvalidObjectException(e.getMessage());
        }
        catch (InvocationTargetException e)
        {
            throw new InvalidObjectException(e.getMessage());
        }
        catch (NoSuchMethodException e)
        {
            throw new InvalidObjectException(e.getMessage());
        }
        return entity;
    }

    /**
     * Lookup the entity factory in the application context and create an
     * instance of the entity. The entity factory is located by getting the
     * entity definition bean and using the factory registered with it or
     * getting the entity factory. The name used for the definition bean lookup
     * is ${entityName}Definition while ${entityName} is used for the factory
     * lookup.
     * 
     * @return The domain object instance.
     * @throws ObjectStreamException
     *             If the entity definition bean or entity factory were not
     *             available.
     */
    @SuppressWarnings("unchecked")
    private T createEntity()
        throws ObjectStreamException
    {
        SerializedCGLibEntity.LOG.debug("Getting domain object factory");

        // Try to use the entity definition bean

        final IEntityDefinitionBean<S, T> entityDefinition = (IEntityDefinitionBean<S, T>)this.beanFactory
            .getBean(StringUtils.uncapitalize(this.entityName) + "Definition",
                IEntityDefinitionBean.class);

        if (entityDefinition != null)
        {
            final IEntityFactory<S, T> entityFactory = entityDefinition
                .getFactory();
            if (entityFactory != null)
            {
                 SerializedCGLibEntity.LOG
                    .debug("Domain object factory obtained via enity definition bean");

                 return entityFactory.create();
            }
        }

        // Try to use the entity factory

        final IEntityFactory<S, T> entityFactory = (IEntityFactory<S, T>)this.beanFactory
            .getBean(StringUtils.uncapitalize(this.entityName) + "Factory",
                IEntityFactory.class);

        if (entityFactory != null)
        {
            SerializedCGLibEntity.LOG
                .debug("Domain object factory obtained via direct look-up");

            return entityFactory.create();
        }

        // Neither worked!

        SerializedCGLibEntity.LOG.warn("Cannot find domain object factory");

        throw new InvalidObjectException(
            "No entity definition or factory found for " + this.entityName);
    }
}
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
1 800
2

Ответы 2

Вы используете Spring ApplicationContext или BeanFactory? Если вы используете ApplicationContext, вы можете реализовать ApplicationContextAware вместо этого, и spring предоставит вам контекст приложения. Я никогда раньше не использовал Spring BeanFactory, но я использовал ApplicationContext, и он работает.

Неважно, использую ли я ApplicationContextAware или BeanFactoryAware. У меня ни то, ни другое не работает. Похоже, проблема в том, что опция preConstruction = true не работает вместе с объектами, созданными с помощью readResolve ().

Brian Matthews 27.10.2008 04:28

Вы уверены, что ваш конфигурируемый класс был правильно сплетен, скомпилировав его с помощью компилятора ApsectJ или с помощью переплетения во время выполнения.

Вам также необходимо указать атрибуты в файле конфигурации, помечая bean-компонент как прототип. Что-то вроде:

<aop:spring-configured />
<bean class = "package.name.SerializedCGLibEntity" scope = "prototype">
<property name = "beanFactory" value = "whateverValue"/>
</bean>

да. Это определенно соткано. Я поместил операторы трассировки в конструктор по умолчанию, и они никогда не вызываются.

Brian Matthews 01.02.2009 19:09

Другие вопросы по теме