As you might have read from my previous posting I created an example that demonstrates the usage of
Equinox Aspects as the load-time weaving engine for
Spring Dynamic Modules. Now its time to describe this in more detail. :-)
My first idea behind this combination was to use the
@Configurable annotation to use Spring's dependency injection mechanism for arbitrary objects which you typically don't create via the application context of spring. The default examples for this are plain domain objects, extensions are another example (they are typically created by the extension registry of Eclipse). Spring realizes the dependency injection for those objects by weaving an aspect into their classes. This aspect takes care of injecting the dependencies after each object creation. And this is the point where Equinox Aspects comes into play.
Fortunately Spring ships as a set of OSGi bundles. This is also true for "spring-aspects.jar", the JAR archive that contains the aspect that is responsible for making the @Configurable annotation work. And you can use Equinox Aspects to weave this aspect into your bundles wherever you would like to use the @Configurable extension. Sounds good, eh?
Ok, what do you need to do? Let’s go through the example step by step. First you need a target platform that contains the following:
Now you have a class that would like to use @Configurable. In my example it is a view for an RCP application that looks somewhat like this:
@Configurable
public class View extends ViewPart {
private Service service;
public void setService(Service service) {
this.service = service;
}
public void createPartControl(Composite parent) {
...
Then you define in the spring context of the same bundle the view as a spring bean, including the "service" property (the dependency that should be injected):
<bean class="org.eclipse.example.springdm.rcpview.View" scope="prototype">
<property name="service" ref="myservice"/>
</bean>
<bean id="myservice" class="org.eclipse.example.springdm.rcpview.Service"/>
Take care to define the bean for the view as of scope "prototype". This is necessary to tell spring that this bean definition should be used as prototype for various instances.
Now we need to tell your bundle to be woven with the spring aspect. Therefore you just define the aspect bundle as required bundle:
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.springframework.bundle.spring.aspects
Now Equinox Aspects (if started correctly) weaves the aspect into your bundle wherever the @Configurable annotation is used. The next step is to tell the spring context that it should use load-time weaving and annotation configuration (plain old spring configuration for load-time weaving, nothing special here):
<context:spring-configured>
<context:annotation-config>
<context:load-time-weaver class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver">
This also requires some more import package statements within your manifest:
Import-Package: org.aspectj.lang,
org.aspectj.runtime.reflect,
org.springframework.instrument.classloading,
org.springframework.beans.factory.annotation
The first two import statements are necessary because they are needed if an aspect gets woven into one of your classes. A more elegant solution for this would be to reexport those packages from the spring-aspects bundle, but they didn’t define the reexport in their manifest. Therefore you need to import them manually.
The last step is to take care of the startup sequence of your bundle. If the extension is created, your bundle should be activated to get the spring context created. This creation of the spring context should happen synchronously to ensure that the context is created when your extension object is created – otherwise the dependency injection would not work. Therefore I declare in the manifest:
Eclipse-LazyStart: true
Spring-Context: *;create-asynchronously:=false
If you would like to take a look at the complete example that I used, you can download it here:
Feedback and questions are always welcome!
As you might have read from my previous posting I created an example that demonstrates the usage of
Equinox Aspects as the load-time weaving engine for
Spring Dynamic Modules. Now its time to describe this in more detail. :-)
My first idea behind this combination was to use the
@Configurable annotation to use Spring's dependency injection mechanism for arbitrary objects which you typically don't create via the application context of spring. The default examples for this are plain domain objects, extensions are another example (they are typically created by the extension registry of Eclipse). Spring realizes the dependency injection for those objects by weaving an aspect into their classes. This aspect takes care of injecting the dependencies after each object creation. And this is the point where Equinox Aspects comes into play.
Fortunately Spring ships as a set of OSGi bundles. This is also true for "spring-aspects.jar", the JAR archive that contains the aspect that is responsible for making the @Configurable annotation work. And you can use Equinox Aspects to weave this aspect into your bundles wherever you would like to use the @Configurable extension. Sounds good, eh?
Ok, what do you need to do? Let’s go through the example step by step. First you need a target platform that contains the following:
Now you have a class that would like to use @Configurable. In my example it is a view for an RCP application that looks somewhat like this:
@Configurable
public class View extends ViewPart {
private Service service;
public void setService(Service service) {
this.service = service;
}
public void createPartControl(Composite parent) {
...
Then you define in the spring context of the same bundle the view as a spring bean, including the "service" property (the dependency that should be injected):
<bean class="org.eclipse.example.springdm.rcpview.View" scope="prototype">
<property name="service" ref="myservice"/>
</bean>
<bean id="myservice" class="org.eclipse.example.springdm.rcpview.Service"/>
Take care to define the bean for the view as of scope "prototype". This is necessary to tell spring that this bean definition should be used as prototype for various instances.
Now we need to tell your bundle to be woven with the spring aspect. Therefore you just define the aspect bundle as required bundle:
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.springframework.bundle.spring.aspects
Now Equinox Aspects (if started correctly) weaves the aspect into your bundle wherever the @Configurable annotation is used. The next step is to tell the spring context that it should use load-time weaving and annotation configuration (plain old spring configuration for load-time weaving, nothing special here):
<context:spring-configured>
<context:annotation-config>
<context:load-time-weaver class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver">
This also requires some more import package statements within your manifest:
Import-Package: org.aspectj.lang,
org.aspectj.runtime.reflect,
org.springframework.instrument.classloading,
org.springframework.beans.factory.annotation
The first two import statements are necessary because they are needed if an aspect gets woven into one of your classes. A more elegant solution for this would be to reexport those packages from the spring-aspects bundle, but they didn’t define the reexport in their manifest. Therefore you need to import them manually.
The last step is to take care of the startup sequence of your bundle. If the extension is created, your bundle should be activated to get the spring context created. This creation of the spring context should happen synchronously to ensure that the context is created when your extension object is created – otherwise the dependency injection would not work. Therefore I declare in the manifest:
Eclipse-LazyStart: true
Spring-Context: *;create-asynchronously:=false
If you would like to take a look at the complete example that I used, you can download it here:
Feedback and questions are always welcome!
Dependency Injection for Extensions, Third Edition