jBeanBox
Лицензия: Apache 2.0
jBeanBox — это инструмент IOC/AOP микромасштаба. За исключением сторонних библиотек, основной исходный код составляет около 3000 строк. Он использует модель программирования «Box», используя чистые классы Java в качестве конфигурации. jBeanBox работает на JDK 1.6 или выше.
Цель разработки jBeanBox состоит в том, чтобы преодолеть некоторые проблемы других инструментов IOC/AOP:
Добавьте следующую конфигурацию в pom.xml:
<dependency>
<groupId>com.github.drinkjava2</groupId>
<artifactId>jbeanbox</artifactId>
<version>4.0.0</version> <!-- Или новейшая версия -->
</dependency>
jBeanBox не зависит от каких-либо сторонних библиотек. Чтобы избежать конфликтов пакетов, сторонние библиотеки, такие как CGLIB, которые он использует, включены в jBeanBox исходным кодом.
Размер jar-файла jBeanBox большой, около 460 КБ, если вам не нужна функция AOP, вы можете использовать только его ядро DI, называемое «jBeanBoxDI», размером всего 49 КБ, поместите ниже в pom.xml:
<dependency>
<groupId>com.github.drinkjava2</groupId>
<artifactId>jbeanboxdi</artifactId>
<version>4.0.0</version> <!-- Или новейшая версия -->
</dependency>
Демонстрация показывает 10 различных методов внедрения:
public class HelloWorld {
public static class User {
String name;
public User() {}
@VALUE("User1")
public User(String name) { this.name = name;}
void setName(String name) { this.name = name;}
void init() {this.name = "User6";}
@PreDestroy
void end() {this.name= "User10";}
}
public static class UserBox extends BeanBox {
Object create() {return new User("User2");}
}
public static class UserBox7 extends BeanBox {
{ setBeanClass(User.class);
setProperty("name", "User7");
}
}
public static class H8 extends UserBox {{setAsValue("User8");}}
public static void main(String[] args) {
User u1 = JBEANBOX.getInstance(User.class);
User u2 = JBEANBOX.getBean(UserBox.class);
User u3 = JBEANBOX.getBean(new BeanBox().injectConstruct(User.class, String.class, value("User3")));
User u4 = JBEANBOX.getBean(new BeanBox(User.class).injectValue("name", "User4" ));
User u5 = JBEANBOX
.getBean(new BeanBox(User.class).injectMethod("setName", String.class, value("User5")));
User u6 = JBEANBOX.getBean(new BeanBox().setBeanClass(User.class).setPostConstruct("init"));
User u7 = new UserBox7().getBean();
BeanBoxContext ctx = new BeanBoxContext();
Interceptor aop=new MethodInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
invocation.getArguments()[0]="User9";
return invocation.proceed();
}
};
User u8 = ctx.rebind(String.class, "8").bind("8", H8.class)
.getBean(ctx.getBeanBox(User.class).addMethodAop(aop, "setName",String.class).injectField("name", autowired()));
System.out.println(u1.name); //Result: User1
System.out.println(u2.name); //Result: User2
System.out.println(u3.name); //Result: User3
System.out.println(u4.name); //Result: User4
System.out.println(u5.name); //Result:
*Примечание: в тексте запроса присутствуют фрагменты кода на языке Java, они были переведены на русский язык.* ```
System.out.println(u6.name); //Result: User6
System.out.println(u7.name); //Result: User7
System.out.println(u8.name); //Result: User8
u8.setName("");
System.out.println(u8.name); //Result: User9
ctx.close();
System.out.println(u8.name); //Result: User10
}
Этот фрагмент кода демонстрирует последовательный вывод «User1», «User2»... до «User10». Вот объяснение:
Приведённый выше пример в основном демонстрирует конфигурацию метода Java jBeanBox. Метод Java можно выполнить динамически или как фиксированную конфигурацию в определённом классе BeanBox. Фиксированная конфигурация может заложить основу конфигурации. Когда необходимо внести изменения, можно использовать тот же метод Java для настройки (поскольку это один и тот же объект BeanBox) или даже временно создать новую конфигурацию, поэтому jBeanBox имеет преимущества фиксированной конфигурации и динамической конфигурации. Кроме того, когда нет исходного кода, например, для настройки экземпляра сторонней библиотеки, все методы аннотаций в настоящее время не используются, и единственный доступный метод конфигурации Java — единственный.
Метод value() в приведённом выше примере — это глобальный метод, статически введённый из класса JBEANBOX. Исходный код этого примера находится в файле HelloWorld.java в каталоге модульного тестирования.
jBeanBox поддерживает не только конфигурацию режима Java, но и конфигурацию режима аннотаций. Поддерживаются следующие аннотации:
@INJECT похож на аннотацию @Inject в JSR, но позволяет добавить целевой класс в качестве параметра
@POSTCONSTRUCT эквивалентен аннотации @PostConstruct в JSR
@PREDESTROY эквивалентен аннотации @PreDestroy в JSR
@VALUE похож на аннотацию @Value в Spring
@PROTOTYPE эквивалентен аннотации @Prototype в Spring
@AOP используется для настройки аннотаций AOP. Подробнее см. в разделе AOP.
@NAMED эквивалентен аннотации @Named в JSR
@QUALIFIER эквивалентен аннотации @Qulifier в JSR
Поскольку все знакомы с конфигурацией метода аннотирования, здесь нет подробного введения. В каталоге jBeanBox\test можно найти файл «AnnotationInjectTest.java», демонстрирующий использование различных режимов аннотирования. Конфигурация.
Чтобы отключить JSR, можно использовать метод Spring annotations ctx.setAllowSpringJsrAnnotation(false). Чтобы отключить все аннотации (это означает, что можно будет использовать только Java configuration), используйте метод ctx.setAllowAnnotation(false).
Ниже приведены примеры конфигурации аннотаций:
// Класс внедрения
@PROTOTYPE
@VALUE("3")
public static class Demo4 { } // ctx.getBean(Demo4.class) вернёт «3»
@INJECT(Demo4.class) @PROTOTYPE
public static class Demo5 { } // прототип
@INJECT(value=Demo4.class )
public static class Demo6 { } // синглтон
@INJECT(value=Demo4.class )
public static interface inf1{}// синглтон
@INJECT(value=Demo4.class, pureValue=true) // возвращает Demo4.class
public static interface inf2{}
// Конструктор внедрения
public static class CA {}
public static class CB {}
public static class C1 { int i = 0; @INJECT public C1() { i = 2; } }
public static class C2 { int i = 0; @INJECT public C2(@VALUE("2") int a) { i = a; } }
public static class C3 { int i = 0; @VALUE("2") public C3(int a) { i = a; } }
public static class C4 { int i = 0; @INJECT public C4(@VALUE("2") Integer a,@VALUE("2") byte b ) { i = b; } }
public static class C5 { Object o ; @INJECT(value=Bar.class, pureValue=true) public C5(Object a) { o = a; } }
public static class C6 { Object o1,o2 ; @INJECT public C6(CA a, CB b) { o1 = a; o2=b; } }
// Внедрение поля
public static class FieldInject2 {
@INJECT(required = false)
public String field0 = "aa";
@INJECT(value = ClassABox.class, pureValue = false, required = true)
private ClassA field1;
@INJECT(value = ClassABox.class)
private ClassA field1;
@INJECT(HelloBox.class)
private String field3;
@VALUE(value = "true")
private Boolean field4;
@VALUE("5")
private long field5;
@VALUE("6")
private Long field6;
@Autowired(required = false)
public String field7 = "7";
@Inject
public CA ca;
@Autowired
public CB cb;
}
// Метод внедрения
public static class MethodInject1 {
public String s1;
public String s2;
public long l3;
public Boolean bl4;
public String s5;
public byte bt5;
public CA a;
@INJECT(HelloBox.class)
private void method1(String a) {
s1 = a;
}
@INJECT
private void method2(@INJECT(value = HelloBox.class) String a) {
s2 = a;
}
@INJECT
private void method3(@VALUE("3") long a) {
l3 = a;
}
@VALUE("true")
private void method4(boolean a) {
bl4 = a;
}
@INJECT
private void method5(@INJECT(HelloBox.class) String a, @VALUE("5") Byte b) {
s5 = a;
bt5 = b;
}
@INJECT
private void method6(CA a) {
this.a = a;
}
}
Приведённый пример — это общая демонстрация конфигурации Java-режима jBeanBox. Давайте подробнее рассмотрим все методы конфигурации Java:
setAsValue(Object) настраивает текущий BeanBox как константное значение, эквивалентное setTarget(Obj)+setPureVale(true);
setPrototype(boolean) Если аргумент равен true, это означает, что это не синглтон, в отличие от метода setSingleton.
injectConstruct(Class<?>, Object...) Устанавливает внедрение конструктора. Параметрами являются класс, тип параметра конструктора и параметры.
injectMethod(String, Object...) Устанавливает внедрение метода. Параметрами являются имя метода, тип параметра и параметры.
addAopToMethod(Object, Method) Добавляет AOP к методу, параметрами являются класс или экземпляр AOP, метод.
addMethodAop(Object, String, Class<?>...) Добавляет AOP к методу, параметры — класс или экземпляр AOP, имя метода, тип параметра.
addBeanAop(Object, String) Добавляет AOP ко всему компоненту. Параметры — класс или экземпляр AOP, правила метода (например, «setUser*»).
setPostConstruct(String) устанавливает имя метода PostConstruct с тем же эффектом, что и аннотация @PostConstruct.
setPreDestroy(String) устанавливает имя метода PreDestroy с тем же эффектом, что и аннотация @PreDestroy.
injectField(String, BeanBox) Внедряет поле, параметр — имя поля. BeanBox и его эквивалентная аннотация @INJECT
setProperty(String, Object) эквивалентен методу injectValue.
injectValue(String, Object). Метод injectValue внедряет поле, параметр — это имя поля, экземпляр объекта, и аннотация, с которой его можно сравнить, — @VALUE.
setTarget(Object) предназначен для цели текущего bean. Кроме того, когда bind("7", User.class), setTarget("7") эквивалентно setTarget(User.class).
setPureValue(boolean) указывает, что цель больше не является целью, а возвращается как чистое значение. «7» на восходящем потоке вернёт строку «7».
setBeanClass(Class<?>) устанавливает конечный целевой класс текущего BeanBox. Все конфигурации основаны на этом классе.
setSingleton(Boolean) — противоположность setPrototype.
setConstructor(Constructor<?>) задаёт конструктор.
setConstructorParams(BeanBox[]) задаёт параметры конструктора, который используется вместе с восходящим потоком.
setPostConstruct(Method) задаёт метод PostConstruct с тем же эффектом, что и аннотация @PostConstruct.
setPreDestroy(Method) задаёт имя метода PreDestroy с тем же эффектом, что и аннотация @PreDestroy.
В Java-конфигурации в классе BeanBox есть два специальных метода: create и config. См. ниже:
public static class DemoBox extends BeanBox {
public Object create(Caller caller) {
A a = new A();
a.field1 = caller.getBean(B.class);
return a;
}
public void config(Object o, Caller caller) {
((A) o).field2 = caller.getBean(C.class);
}
}
Приведённый выше пример показывает, что бин, созданный в DemoBox, генерируется методом create и модифицируется методом config. Параметр Caller в методах create и config можно опустить, если вам не нужно использовать этот параметр Caller для загрузки других бинов.
AOP для jBeanBox (для фасетного программирования)
Большинство функций jBeanBox можно реализовать либо в Java-конфигурации, либо в конфигурации аннотаций. Аналогично существует два способа поддержки AOP:
public static class AopDemo1 {
String name;
String address;
String email;
//getter & setters...
}
public static class MethodAOP implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
invocation.getArguments()[0] = "1";
return invocation.proceed();
}
}
public static class BeanAOP implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
invocation.getArguments()[0] = "2";
return invocation.proceed();
}
}
public static class GlobalAOP implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
invocation.getArguments()[0] = "3";
return invocation.proceed();
}
}
public static class AopDemo1Box extends BeanBox {
{
this.injectConstruct(AopDemo1.class, String.class, value("0"));
this.addMethodAop(MethodAOP.class, "setName", String.class);
this.addBeanAop(BeanAOP.class, "setAddr*");
}
}
@Test
public void aopTest1() {
``` JBEANBOX.ctx().bind("3", GlobalAOP.class);
JBEANBOX.ctx().addGlobalAop("3", AopDemo1.class, "setEm*");
AopDemo1 demo = JBEANBOX.getBean(AopDemo1Box.class);
demo.setName("--");
Assert.assertEquals("1", demo.name);
demo.setAddress("--");
Assert.assertEquals("2", demo.address);
demo.setEmail("--");
Assert.assertEquals("3", demo.email);
}
#### Annotation mode AOP configuration
Режим аннотации AOP имеет только два типа: для метода и для класса.
Метод аннотирования требует специальной аннотации @AOP, которая используется для настройки аннотаций AOP. Примеры использования следующие:
public static class Interceptor1 implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { invocation.getArguments()[0] = "1"; return invocation.proceed(); } }
public static class Interceptor2 implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { invocation.getArguments()[0] = "2"; return invocation.proceed(); } }
@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE }) @AOP public static @interface MyAop1 { public Class<?> value() default Interceptor1.class;
public String method() default "setNa*";
}
@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD }) @AOP public static @interface MyAop2 { public Class<?> value() default Interceptor2.class; }
@MyAop1 public static class AopDemo1 { String name; String address;
public void setName(String name) {
this.name = name;
}
@MyAop2
public void setAddress(String address) {
this.address = address;
}
}
@Test public void aopTest1() { AopDemo1 demo = JBEANBOX.getBean(AopDemo1.class); demo.setName("--"); Assert.assertEquals("1", demo.name); demo.setAddress("--"); Assert.assertEquals("2", demo.address); }
AOP, упомянутый в этой статье, относится к интерфейсу стандарта федерации AOP альянса. Он был включён в jBeanBox и не нуждается в отдельном представлении (конечно, нет проблем с повторным представлением). Стандарт федерации AOP альянса является полезным интерфейсом для достижения взаимозаменяемости между различными реализациями AOP. На его основе jBeanBox может заменить ядро Spring и использовать его декларативную транзакцию. Эта взаимозаменяемость может быть достигнута. Предпосылка заключается в том, что реализация декларативной транзакции Spring (например, TransactionInterceptor) также реализует интерфейс стандарта федерации AOP альянса MethodInterceptor.
Начиная с версии 2.4.8, функция ABean была отключена, а неиспользуемые функции предварительного, последующего и аномального аспектов были удалены. Были сохранены только функции интерфейса стандарта федерации AOP альянса MethodInterceptor (обратите внимание, что в CGLIB также есть интерфейс с таким же именем, не путайте). Класс, который реализует интерфейс MethodInterceptor, обычно называется Interceptor, но сохраняется в jBeanBox, также называется AOP, в конце концов, писать addBeanAop проще, чем писать addBeanInterceptor.
### О циклических зависимостях
jBeanBox поддерживает обнаружение циклических зависимостей. Если будет обнаружена циклическая зависимость инъекции (например, инъекция B в конструкторе A и инъекция A в конструкторе B), будет выброшено исключение времени выполнения BeanBoxException.
Однако в jBeanBox разрешены циклические зависимости инъекций, которые происходят в таких полях или методах:
public static class A { @Inject public B b; }
public static class B { @Inject public A a; }
A a = JBEANBOX.getBean(A.class); Assert.assertTrue(a == a.b.a);//true
### jBeanBox поддерживает несколько контекстов и жизненный цикл Bean Функция, построить дерево экземпляров из 6 объектов), можно увидеть, что jBeanBox создаёт не-синглтон-бин в два раза быстрее Guice и в 45 раз быстрее Spring. Тестовый проект находится по адресу: [di-benchmark] (https://github.com/drinkjava2/di-benchmark).
Бенчмарк времени выполнения, получение нового бина 500 000 раз:
---------------------------------------------------------
Vanilla| 31мс
Guice| 1154мс
Feather| 624мс
Dagger| 312мс
Genie| 609мс
Pico| 4555мс
jBeanBoxNormal| 2075мс
jBeanBoxTypeSafe| 2371мс
jBeanBoxAnnotation| 2059мс
SpringJavaConfiguration| 92149мс
SpringAnnotationScanned| 95504мс
Разделение запуска контейнеров DI и создания графа зависимостей 4999 раз:
-------------------------------------------------------------------------------
Vanilla| запуск: 0мс получение: 0мс
Guice| запуск: 1046мс получение: 1560мс
Feather| запуск: 0мс получение: 109мс
Dagger| запуск: 46мс получение: 173мс
Pico| запуск: 376мс получение: 217мс
Genie| запуск: 766мс получение: 247мс
jBeanBoxNormal| запуск: 79мс получение: 982мс
jBeanBoxTypeSafe| запуск: 0мс получение: 998мс
jBeanBoxAnnotation| запуск: 0мс получение: 468мс
SpringJavaConfiguration| запуск: 51831мс получение: 1834мс
SpringAnnotationScanned| запуск: 70712мс получение: 4155мс
Бенчмарк времени выполнения, получение синглтона 5 000 000 раз:
---------------------------------------------------------
Vanilla| 47мс
Guice| 1950мс
Feather| 624мс
Dagger| 2746мс
Genie| 327мс
Pico| 3385мс
jBeanBoxNormal| 188мс
jBeanBoxTypeSafe| 187мс
jBeanBoxAnnotation| 171мс
SpringJavaConfiguration| 1061мс
SpringAnnotationScanned| 1045мс
Хотя большинство инструментов IOC используются в случаях с синглтонами, производительность почти такая же (потому что она берётся из кэша), но если вы сталкиваетесь с ситуацией, когда необходимо создать не-одиночный экземпляр, такой как генерация нового экземпляра страницы каждый раз, Spring недостаточно быстр. А для начальной скорости он довольно медленный.
Выше представлено введение в jBeanBox, других документов нет, потому что, в конце концов, основной исходный код jBeanBox составляет всего около 1500 строк (сторонние инструменты, такие как CGLIB, интерфейс JSR и т. д., не учитываются). Если у вас есть какие-либо вопросы о jBeanBox, проверить его исходный код — это простое решение.
Дополнительные демонстрации jBeanBox также можно увидеть в проекте jSqlBox (конфигурация источника данных, примеры декларативных транзакций и т.д.).
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )