Headshrinker
@Headshrinker
Java-разработчик

Можете посоветовать Best-practice по реализации сквозной логики определения изменений в объекте?

В книге "Spring 3 для профессионалов" увидел пример сквозной логики "Обнаружение модификации объекта с помощью введений". Немного изменил указанный там код:
интерфейс
public interface IsModified {
    public boolean isModified();
}

реализация интерфейса
public class IsModifiedMixin extends DelegatingIntroductionInterceptor implements IsModified {

    private boolean isModified = false;
    private Map<Method, Method> methodCache = new HashMap<Method, Method>();

    public boolean isModified() {
        return isModified;
    }

    public Object invoke(MethodInvocation invocation) throws Throwable {
        if (!isModified) {
            if ((invocation.getMethod().getName().startsWith("set"))
                    && (invocation.getArguments().length == 1)) {
                // Вызвать соответствующий метод get, чтобы посмотреть,
                // изменилось ли значение.
                Method getter = getGetter(invocation.getMethod());
                if (getter != null) {
                    // Для методов, предназначенных только для записи,
                    // проверка модификации не важна.
                    Object newVal = invocation.getArguments()[0];
                    Object oldVal = getter.invoke(invocation.getThis(), null);
                    if ((newVal == null) && (oldVal == null)) {
                        isModified = false;
                    } else if ((newVal == null) && (oldVal != null)) {
                        isModified = true;
                    } else if ((newVal != null) && (oldVal == null)) {
                        isModified = true;
                    } else {
                        isModified = (!newVal.equals(oldVal));
                    }
                }
            }
        }
        return super.invoke(invocation);
    }

    private Method getGetter(Method setter) {
        Method getter = null;
        // Попытка извлечения из кеша.
        getter = (Method) methodCache.get(setter);
        if (getter != null) {
            return getter;
        }
        String getterName = setter.getName().replaceFirst("set", "get");
        try {
            getter = setter.getDeclaringClass().getMethod(getterName, null);
            // Метод извлечения из кеша.
            synchronized (methodCache) {
                methodCache.put(setter, getter);
            }
            return getter;
        } catch (NoSuchMethodException ex) {
            // Должен быть только для записи.
            return null;
        }
    }
}

советчик
public class IsModifiedAdvisor extends DefaultPointcutAdvisor {
    public IsModifiedAdvisor() {
        super(new IsModifiedMixin());
    }
}

Добавление примеси с использованием среза
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <bean id="modifiedAdvisor"
          class="ru.its360.system.modifiedmixin.advisor.IsModifiedAdvisor">
        <property name="pointcut">
            <bean class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
                <property name="expression" value="execution(* ru.its360.development360..domain.model..*(..))"/>
            </bean>
        </property>
    </bean>
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
</beans>

По идее должно выполняться следующее: к каждой модели примешивается логика IsModified и создается прокси.
Код к сожалению не работает. При запуске проекта на томкате выдается эксепшн:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'creditProgramManager': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ru.its360.document.ticket.service.api.ticket.category.ITicketCategoryManager ru.its360.development.development360.credits.creditprogram.service.application.CreditProgramManager.ticketCategoryManager; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ticketCategoryManager': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ru.its360.leasing360.workflow.IWorkFlowManager ru.its360.security.accesslayer.service.application.SecurityAbstractManager.flowManager; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'workFlowManager': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ru.its360.development.development360.tenders.tender.service.api.ITenderManager ru.its360.development360.workflow.workflow.service.application.WorkFlowManager.tenderManager; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tenderManager': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ru.its360.development.development360.tenders.developmentcontract.service.api.IDevelopmentContractManager ru.its360.development.development360.tenders.tender.service.application.TenderManager.developmentContractManager; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'developmentContractManager': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ru.its360.development.development360.tenders.paymentprofile.service.api.IPaymentProfileManager ru.its360.development.development360.tenders.developmentcontract.service.application.DevelopmentContractManager.paymentProfileManager; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'paymentProfileManager': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ru.its360.development.development360.tenders.paymentprofile.service.calc.api.IPaymentProfileCalculatorFactory ru.its360.development.development360.tenders.paymentprofile.service.application.PaymentProfileManager.paymentProfileCalculatorFactory; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'paymentProfileCalculatorFactory': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ru.its360.development.development360.tenders.paymentprofile.service.calc.api.IDDUFullOfShareWithoutCreditCalculator ru.its360.development.development360.tenders.paymentprofile.service.calc.application.PaymentProfileCalculatorFactory.dduFullOfShareWithoutCreditCalculator; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'DDUFullOfShareWithoutCreditCalculator': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: protected ru.its360.development.development360.buildings.section.service.api.IRealtyObjectManager ru.its360.development.development360.tenders.paymentprofile.service.calc.application.AbstractPaymentProfileCalculator.realtyObjectManager; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'realtyObjectManager': Bean with name 'realtyObjectManager' has been injected into other beans [statusRealtyObjectManager] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.


Я думаю это связано с тем что DefaultAdvisorAutoProxyCreator создает прокси для бинов какого то абстрактного типа (пока не разобрался) и остальные бины спринга не могут работать с ними.
  • Вопрос задан
  • 2482 просмотра
Решения вопроса 1
Headshrinker
@Headshrinker Автор вопроса
Java-разработчик
Решил задачу таким способом: делаю подмешивание к объекту непосредственно перед тем местом где вероятно объект может измениться и после проверяю. Работает для JSF при работе через форму.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы