1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/wkgcass-Pure.IoC

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
Readme.md

click here(git@osc) чтобы получить английскую версию руководства.

Pure.IoC

Pure.IoC – это легковесный автоматический фреймворк внедрения зависимостей на основе классов и аннотаций.

Использует JDK 1.8
Рекомендовано использовать вместе с Spring

<dependency>
  <groupId>net.cassite</groupId>
  <artifactId>pure.ioc</artifactId>
  <version>0.3.2</version>
</dependency>

Концепция фреймворка

Использует уже существующие логические связи вместо сложной конфигурации.

Основные возможности

  • IOC
  • AOP

Проектирование

Обычно при написании Java используется фреймворк Spring для управления IoC. Spring основан на beanах, поэтому требуется отображение классов в beanы и описание зависимости между ними.

На самом деле, часто зависимости могут быть определены только по типу. Например,

class A{
	...
	public void setB(B b){ this.b = b; }
}

class B{
}

Очевидно, что A зависит от B, и A должен будет передать экземпляр B через метод setB. Это естественная логическая связь.

Типовая зависимость уже установлена во время написания кода, так что было бы полезно иметь инструмент, который помог бы автоматически выполнять такие "очевидные" зависимости. Поэтому был создан Pure.IoC

Архитектура фреймворка

Расширяемость

При проектировании Pure.IoC были учтены различные ситуации. Рассмотрим следующий пример:

@Singleton
@Wire
class Complex{
	private ...
	
	public Complex(){ ... }
	@Default public Complex(AnotherClass obj){ ... }
	
	public void setA(A a){ ... }
	public void setB(B b){ ... }	
	public void setInterface(Interf1 interf){ ... }
	public void setInterface(@Use(clazz=Impl2.class)Interf2 interf){ ... }
}

@Default(clazz=Impl1.class) interface Interf1{ ... }

Эти аннотации означают:

  • @Singleton Complex является единственным объектом
  • @Wire указывает на необходимость автовнедрения при создании
  • @Default указывает на использование определенного конструктора или реализации интерфейса
  • @Use указывает на использование конкретного класса

Аннотации могут быть бесконечными, но они не должны усложнять систему. В результате использована следующая архитектура:

AnnotationHandler + HandlerChain

AnnotationHandler делится на три типа,

  • ParamAnnotationHandler отвечает за получение экземпляров по типу
  • ConstructorFilter отвечает за выбор конструктора, учитывая аннотации на нем
  • TypeAnnotationHandler отвечает за выбор типа для создания, учитывая аннотации на типе

Хэндлеры регистрируются в IOCController, где они обрабатываются в порядке регистрации. Реализация хэндлеров немного напоминает AOP, обычно вызывается chain.next().handle(...), затем принимаются решения на основе возвращаемого значения или выбрасываемых исключений. Подробнее см. документацию по интерфейсу handle каждого хэндлера.

Таким образом, можно легко расширять аннотации.

Циклические зависимости

Циклические зависимости хотя и не очень распространены, но могут возникнуть. A -> B -> C -> A
Логически, один из A, B, C должен быть singleton, иначе создание объектов будет бесконечным циклом.

Кроме того, Spring требует, чтобы конструкторы не имели циклических зависимостей, иначе сборка невозможна.

Но Pure.IoC изящно решает проблему циклических зависимостей.

  • Все внедрения происходят при конструировании. Только после завершения всех внедрений происходит конструирование.
  • Для singleton перед фактическим конструированием его ссылка передается IOCController, указывая на то, что singleton существует.
  • Поскольку конструирование завершается только после завершения всех внедрений, нет опасений получить объект, который еще находится в процессе конструирования.

Поэтому даже если конструкторы содержат циклические зависимости, все равно можно успешно выполнить внедрение (все зависимости являются конструкторными).

Применимость

Pure.IoC, будучи спроектированным для внедрения при конструировании, может быть использован без каких-либо дополнительных компонентов. Также он может работать вместе со Spring. Даже часть setter может быть внедрена через этот фреймворк, а другая часть — через Spring.

Прямое использование с Struts2 также возможно. Поскольку весь процесс внедрения полностью внутри класса, нет необходимости в специальной конфигурации объектного фабрикатора Struts2, как это требуется в случае Spring.

Рекомендуется использовать следующий подход:

extends AutoWire

Но иногда необходимо наследовать другой класс, тогда есть два способа решения проблемы:

@Wire class A { ... }

Класс, помеченный аннотацией @Wire, будет внедрен в любом случае, когда он проходит через Pure.IoC.
Для получения экземпляра можно использовать

AutoWire.get(A.class)
class A {
	public A(){
		AutoWire.wire(this);
	}
}

В конструкторе передается ссылка на себя для внедрения.

На самом деле все входные точки в конечном итоге вызывают AutoWire.wire(Object)

Как использовать?

  • Сначала используйте любой из трех вышеописанных методов для подключения к фреймворку.

  • Затем в точке входа программы вызовите

    IOCController.autoRegister();

или зарегистрируйте каждый хэндлер вручную, например,

register(new DefaultConstructorFilter());

Если вы работаете в Java EE, вы можете использовать Listener для выполнения этой операции

  • Наконец, вызовите

    IOCController.closeRegistering();

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

Если хэндлеры не зарегистрированы, но сборка началась, будут вызваны autoRegister() и closeRegistering().

По умолчанию поведение

При отсутствии участия аннотаций поведение по умолчанию такое:

при внедрении setter, получается параметр типа и запрашивается экземпляр у IOCController, затем вызывается invoke setter.

При получении экземпляра, берется уникальный конструктор или конструктор без параметров.
Если конструктор имеет параметры, берутся экземпляры соответствующего типа.
Затем производится конструирование.

Расширенные аннотации

Тип

  • Wire Указывает, что данный класс нуждается в внедрении
  • Singleton
    Указывает, что данный класс является singleton
  • Default(clazz)
    Обычно используется для интерфейсов или абстрактных классов
    При проверке типа, если встретится данная аннотация, будет создан указанный тип

Конструктор

  • Default()
    Указывает на использование данного конструктора при возможном конфликте

Параметр

  • Use(clazz, constant, variable)
    clazz представляет собой тип, который следует использовать для внедрения. Затем проводится проверка типа указанного типа.
    value представляет собой значение, которое должно быть зарегистрировано в scope
  • Force(value)
    Преобразует String значение value в соответствующий тип. Force поддерживает только примитивные типы и String
  • Extend(handler, args)
    Указывает на получение объекта из других объектных фабрик
    handler ExtendingHandler, который описывает, как получать объекты из других объектных фабрик
    args параметры для передачи в handler
  • Session(value)
    Указывает, что параметр setter будет общим для одного session
    value имя сессии
  • Ignore
    Игнорирует данный параметр, используется только для setter, то есть игнорирует данный setter> Кроме того, при обработке параметров предоставляется автоматическое внедрение примитивных типов.

Если доступного внедрения нет, будет проведена проверка примитивных типов и массивов, и они будут инициализированы значением по умолчанию (0, false, array[length=0]).

Другое

Сессия

Сессия существует в течение всего времени от начала сборки до её завершения. Почти каждый метод передаёт параметр сессии.
Например:
A зависит от B, B зависит от C и D. Где A и C наследуют AutoWire (явно вызывают AutoWire.wire(o)), а B и D используют аннотацию Wire.
Тогда ABD будут использовать одну сессию, а C — свою собственную.

Утилиты

Предоставлен класс Utils, содержащий некоторые общие операции и защищённые методы из IOCController. Если вам удобнее не наследовать IOCController, вы можете использовать методы из Utils для вызова этих защищённых методов.

ExtendingHandler

Основная цель — упрощение работы с получением объектов из других объектных фабрик. Но не ограничивается этим.
Можно рассматривать его как упрощение расширения.
Он используется для одновременной обработки Type, Setter и Param, но принимает только массив строковых параметров.

ScopeAware

Реализация интерфейса ScopeAware и аннотация @Wire приведут к тому, что метод будет вызван с текущим Scope в качестве параметра. На самом деле, можно просто записать setScope(Scope s) для выполнения внедрения.

AOP

С версии Yöntem 0.1.1 добавлена возможность использования AOP.

Чтобы активировать AOP, установите

@AOP({Weaver.class,...})

на классах с интерфейсами.

Когда такой класс будет внедрён Pure.IoC, или когда будет вызван

AOPController.weave(() -> экземпляр этого класса, Class.class)

будет получен прокси-объект.

Использование

Создайте ваш Weaving

class YourWeaver implements Weaver{
	@Override
	protected void doBefore(AOPPoint point) {
		...
	}

	@Override
	protected void doAfter(AOPPoint point) {
		...
	}

	@Override
	protected void doException(AOPPoint point) throws Throwable {
		...
	}
}

doBefore, doAfter, doException соответственно соответствуют Before, AfterReturn, AfterThrowing типам. Здесь это также является Around типом.

Также предоставлены BeforeWeaver, AfterWeaver, ExceptionWeaver.
Если вам нужны только определённые cut points, вы можете наследовать эти классы.

Если вам нужно использовать Introduction тип, это тоже довольно просто, достаточно реализовать нужные интерфейсы в вашем Weaving.

Вплетание

Используйте

@AOP({Weaver1.class, Weaver2.class, ...})

для вплетания
Если вы хотите использовать cglib, вы можете принудительно установить useCglib=true

@AOP(value={Weaver1.class, Weaver2.class, ...}, useCglib=true)	

Процесс AOP следует следующим шагам

  • Получите экземпляры каждого Weaver через AutoWire.get(Class)
  • Установите переменную для хранения текущего индекса массива Weaver
  • Выполните 'before' для каждого Weaver от первого до последнего
  • --Если установлено returnValue, сразу переходите к шагу 'after'
  • Выполните метод
  • --Если произошло исключение, выполните 'exception' для каждого Weaver от последнего до первого
  • Выполните 'after' для каждого Weaver от текущего индекса до первого

AOPPoint

Этот класс содержит следующие публичные поля/методы

  • target целевой объект
  • method текущий метод
  • args входные параметры (можно менять прямо здесь)
  • returnValue() получить возвращаемое значение
  • returnValue(Object) установить возвращаемое значение
  • exception() получить текущее исключение
  • exceptionHandled() обработано ли исключение

TargetAware

Реализация интерфейса TargetAware в Weaving приведёт к вызову метода с прокси объектом в качестве параметра после получения экземпляра Weaving.

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Лёгкий фреймворк для внедрения зависимостей, основанный на типах и аннотациях. Развернуть Свернуть
MIT
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/wkgcass-Pure.IoC.git
git@api.gitlife.ru:oschina-mirror/wkgcass-Pure.IoC.git
oschina-mirror
wkgcass-Pure.IoC
wkgcass-Pure.IoC
master