Projects tigase _server server-core Issues #714
Issue with removal of bean in TKF (#714)
Andrzej Wójcik (Tigase) opened 8 years ago
Due Date
2016-09-26

During work on #4525, I found weird behaviour of beans when some of them are delegated or exported. I created tests to show this weird behaviour and I think this tests should pass without any issues when we fix this weird behaviour.

Andrzej Wójcik (Tigase) commented 8 years ago

I found issue which lead to infinite loop when circular dependency was created by using link in kernel. I fixed it by disabling injection of beans when ln method is executed. Most likely it is not needed as ln will be used in register method of RegistrarBean and dependencies are after this method execution due to delayed dependency injection queue.

%bmalkow Do you agree? or we need to think about other solution?

Bartosz Małkowski commented 8 years ago

What is result of this workaround? Not fully initialized bean?

Maybe we should throw exception in case of cyclic dependency?

Andrzej Wójcik (Tigase) commented 8 years ago

Let me give you an example.

We have beans A, B and C.

@Bean(name = "a")
class A implements RegistrarBean {
    @Inject
    B b;
}

@Bean(name = "b")
class B implements RegistrarBean {
    @Inject
    A a;

    @Inject
    C c;
 
    public void register(Kernel kernel) {
        kernel.getParent().ln("a", kernel, "a");
    }
}

@Bean(name = "c", parent = B.class)
class C {
    @Inject
    A a;
}

Now if I write following code to initialize kernels:

Kernel kernel = new Kernel();
// this will register all beans using annotations
kernel.registerBean(A.class).exec();
kernel.getInstance(A.class);

If we would forbid circular dependency then this would fail but it is often needed to work and if I would remove ln from register() method of bean B then bean C will not get dependency A.

I know this could be fixed by exporting bean A using exportable but I do not want to do this as bean A is in root kernel and would be received by all other components and beans - this is not what I want (and for me it is not acceptable).

In theory I could also use

kernel.registerBean("a").asInstance(kernel.getParent().getInstance(A.class)).exec();

but this will fail as not all dependecies of bean A are registered at this point (ie. bean C which is dependency of bean B on which depends bean A is not initialized yet) - this would fail due to circular dependency.

However my current "workaround" works as it exports bean using link but instance is not injected yet. I think this is ok, as most likely it would be using in register method of RegistrarBean and nowhere else - at least I do not seen any other point where this could be used. And if this is used at this point then dependencies are injected at later stage of initialization by Kernel in initBean method.

Andrzej Wójcik (Tigase) commented 8 years ago

Without usage of parent bean feature:

@Bean(name = "a")
class A implements RegistrarBean {
    @Inject
    B b;
    
    public void register(Kernel kernel) {
        kernel.registerBean(B.class).exec();
    }
}

@Bean(name = "b")
class B implements RegistrarBean {
    @Inject
    A a;

    @Inject
    C c;

    public void register(Kernel kernel) {
        kernel.registerBean(C.class).exec();
        kernel.getParent().ln("a", kernel, "a");
    }
}

@Bean(name = "c")
class C {
    @Inject
    A a;
}
Artur Hefczyc commented 8 years ago

What is status of the ticket now? Bartek, can you confirm QA?

Bartosz Małkowski commented 8 years ago

It seems everything is OK.

I agree with this solution.

issue 1 of 1
Type
Task
Priority
Normal
Assignee
RedmineID
4554
Version
tigase-server-8.0.0
Spent time
92h 35m
Issue Votes (0)
Watchers (0)
Reference
tigase/_server/server-core#714
Please wait...
Page is in error, reload to recover