Spring: как убедиться, что класс создается только весной, а не ключевым словом new - PullRequest
3 голосов
/ 19 марта 2010

Можно ли гарантировать, что только spring может создавать экземпляр класса, а не по ключевому слову new во время компиляции? (Во избежание случайного создания экземпляра)

Спасибо!

Ответы [ 7 ]

6 голосов
/ 19 марта 2010

Если вы хотите обнаружить его во время компиляции, конструктор должен быть закрытым. Приватное, вероятно, слишком строгое (оно заставляет инструменты анализа кода предполагать, что его никогда не вызовут, и может даже вызывать предупреждения в некоторых IDE), я бы сказал, что по умолчанию (без модификатора, защищенного пакета) лучше. В тех случаях, когда вы хотите разрешить подклассы в других пакетах (но это невозможно без вызова конструктора непосредственно из этого подкласса), вы можете сделать его защищенным. Обязательно прокомментируйте конструктор соответствующим образом, чтобы всем, кто читает код, было понятно, почему конструктор такой.

Spring будет вызывать этот закрытый конструктор без каких-либо проблем (начиная с Spring 1.1, SPR-174 ).

Вопрос о том, разрешает ли это что-либо еще вызывать ваш конструктор, идея заставить каждого пользователя класса использовать инъекцию зависимостей Spring (так что вся цель этого вопроса) является хорошей идеей или нет, является целым другое дело.

Если это в библиотеке / фреймворке (то есть , обычно используется с Spring), ограничение использования может быть не очень хорошей идеей. Но если вы знаете, что классы будут использоваться только в вашем закрытом проекте, который уже заставляет использовать Spring, это может иметь смысл.

В качестве альтернативы, если ваша настоящая цель состоит просто в том, чтобы избежать возможности того, что кто-то создаст экземпляр и не инициализирует его своими зависимостями, вы можете просто использовать конструктор внедрения зависимостей.

И если ваша цель состоит только в том, чтобы предотвратить случайное использование конструктора (разработчики не знают, что класс должен быть инициализирован Spring), но не хотите полностью ограничивать возможности, вы может сделать его закрытым, но также добавить статический метод фабрики (с явным именем, например createManuallyInitializedInstance или что-то в этом роде).

Плохая идея. Другая возможная альтернатива - сделать конструктор общедоступным, но не рекомендуется. Таким образом, его все еще можно использовать (не прибегая к взломам, таким как использование отражения), но любое случайное использование выдаст предупреждение. Но это не совсем чисто: это не то, для чего предназначен амортизация.

5 голосов
/ 19 марта 2010

Единственный очевидный способ сделать это - во время выполнения через массивный хак; В конце концов, Spring работает с обычной Java (т. Е. Все, что может быть выполнено в Spring, должно быть выполнено через стандартную Java - поэтому невозможно достичь при проверке времени компиляции ). Итак, вот хак:

//CONSTRUCTOR
public MyClass() {
    try {
         throw new RuntimeException("Must be instantiated from with Spring container!");
    }
    catch (RuntimeException e) {
        StackTraceElement[] els  = e.getStackTrace();
        //NOW WALK UP STACK AND re-throw if you don't find a springframework package
        boolean foundSpring = false;
        for (StackTraceElements el : els) {
            if (el.getDeclaringClass().startsWith("org.springframework")) {
                foundSpring = true; break;
            }
        }
        if (!foundSpring) throw e;
    }
}

Я бы действительно не советовал делать это !

1 голос
/ 19 марта 2010

Я скажу вам, почему не , чтобы сделать это - вы не сможете высмеивать ваши классы. И поэтому вы не сможете проводить юнит-тесты.

1 голос
/ 19 марта 2010

Хотя я могу понять, почему вы хотите убедиться, что экземпляр класса создается только Spring, на самом деле это не очень хорошая идея. Одна из целей внедрения зависимости заключается в том, чтобы иметь возможность легко макетировать класс во время тестирования. Таким образом, во время модульных тестов должна быть возможность вручную создавать различные зависимости и фиктивные зависимости. Инъекция зависимостей призвана облегчить жизнь, и поэтому обычно полезно создавать экземпляры с помощью DI, но есть случаи, когда использование new является совершенно разумным, и следует соблюдать осторожность, чтобы не доводить какой-либо шаблон проектирования или идиомы до крайности. Если вы обеспокоены тем, что ваши разработчики будут использовать новые, где они должны использовать DI, лучшее решение для этого - установить проверки кода.

0 голосов
/ 19 марта 2010

Напишите аспект вокруг вызова в конструкторе и прервите, если не через Spring

0 голосов
/ 19 марта 2010

Не уверен, что Spring поддерживает это, поскольку я не пробовал и не использовал Spring довольно давно, однако с другим контейнером IOC хитрый маршрут, который я однажды выбрал, состоял в том, чтобы сделать один класс желаемым, чтобы его возвращали как введенный вами. интерфейс абстрактный класс, и чтобы контейнер IOC возвращал его как экземпляр производного класса. Таким образом, никто не может создать экземпляр класса (так как он абстрактный), и контейнер может вернуть производный класс этого.

Сам контейнер сгенерирует определение производного класса, поэтому не стоит беспокоиться о том, что кто-то попытается сконструировать один из них

0 голосов
/ 19 марта 2010

не знает о Spring, но если вы хотите иметь некоторый контроль над созданием новых экземпляров, вы должны сделать конструктор закрытым и создать внутри вашего класса метод public static YourClass getInstance(), который будет обрабатывать проверки и возвращать новый экземпляр этого объекта. Затем вы можете создать новый класс с помощью конструктора, который вызовет getInstance () .. и передать этот класс в Spring. Вскоре вы обнаружите места, где у вас были «незаконные» звонки за пределами весны ...

...