Thomas Darimont
Erfahrenes Mitglied
Hallo,
hier mal ein kleines Beispiel wie man mit AspectJ / Annotations und Spring nachträglich in Eclipse Komponenten (View, Editoren, etc...) injezieren kann. Dies kann man auf zwei Arten implementieren. Einmal mit statischem Compile-Time weaving
(dazu machen wir das Plugin Projekt zu einem Aspectj Project) oder per Load-Time-Weaving über einen entsprechenden
Java Agenten der über das Instrumentation API den bytecode der Klassen beim Laden modifiziert.
Hier werde ich zunächst einmal den Statischen Weg zeigen und später dann den dynamischen Weg nachreichen.
Als Beispiel nehmen wir hier einfach die Mail template Anwendung. Dort wollen wir einen BusinessService injezieren.
Wir legen also mit dem Plugin-Wizzard eine Mail Template Anwendung an (New-> Plugin Project-> RCP Application -> Mail Template) Anschließend sagen wir AspectJ Tools -> convert to AspectJ Project.
Unser Business Service Interface
Unsere Implementierung:
So nun statten wir unsere Mail Beispielanwendung erstmal mit den notwendigen Bilbiotheken aus.
Wir brauchen das spring.jar , spring-aspects.jar (findet man im dist Verzeichnis der Springframework Distribution)
und commons-logging.jar (lib/jakrata-commons), cg-lib-nodepend2.1_3.jar (lib/cglib), dom4j-xxx.jar (lib/dom4j).
Das Springframework findet man hier (die -with-dependencies) Variante enthält alle notwendigen Bibliotheken auf einen Schlag.
http://www.springframework.org/download
Diese Bibliotheken legen wir in den Runtime-Classpath unserer Anwendung:
Manfest-Editor -> Runtime -> Classpath (hier die jars hinzufügen)
Nun modifizieren wir die generierte NavigationView Klasse:
Hier annotieren wir die Klasse mit @Configurable
und überschreiben die init(...) Methode von ViewPart diese wird von der Eclipse Platform nach dem erzeugen einer View aufgerufen um ihren Lebenszyklus zu starten. Weiterhin haben wir den Business Service als Attribut aufgehängt und entsprechende getter/setter generiert.
Unsere Spring-Konfiguration schaut nun so aus:
applicationContext.xml:
Unser Activator startet den Springframework-Kontext beim Start unserer Anwendung:
Nun kommen unsere Aspekte:
Unser abstracter Configuration aspect bietet die Möglichkeit Objete nach ihrer Erzeugung mit new durch den
abstracten objectInitialization pointcut nachträglich mit Spring zu konfigurieren:
Das funktioniert fast genau so wie ich's schonmal für googles Guice gezeigt hatte:
http://www.tutorials.de/forum/java/...e-bei-mit-new-erzeugten-beans-mt-aspectj.html
Für die Konfiguration einer View sieht ein konkreter Aspect dazu dann ungefähr so aus:
Damit wären wir auch schon fertig.
Zum Starten klicken wir mit der Maus auf das Projekt mit der rechten Maustaste und wählen im Kontextmenü,
run -> as eclipse application aus. Sollte das nicht klappen muss man die Launch-Configuration anpassen.
Dazu geht man einfach in der Launch-Configuration auf den Reiter Plugins, deselektiert erstmal alles, klickt dann
nur "unser" Plugin-Projekt im Workspace an und sagt -> Add required Plugins. Anschließend klickt man auf apply und schon sollte es gehen.
Ausgabe bei mir :
Das Projekt (ohne Libraries) findet man im Anhang.
Gruß Tom
hier mal ein kleines Beispiel wie man mit AspectJ / Annotations und Spring nachträglich in Eclipse Komponenten (View, Editoren, etc...) injezieren kann. Dies kann man auf zwei Arten implementieren. Einmal mit statischem Compile-Time weaving
(dazu machen wir das Plugin Projekt zu einem Aspectj Project) oder per Load-Time-Weaving über einen entsprechenden
Java Agenten der über das Instrumentation API den bytecode der Klassen beim Laden modifiziert.
Hier werde ich zunächst einmal den Statischen Weg zeigen und später dann den dynamischen Weg nachreichen.
Als Beispiel nehmen wir hier einfach die Mail template Anwendung. Dort wollen wir einen BusinessService injezieren.
Wir legen also mit dem Plugin-Wizzard eine Mail Template Anwendung an (New-> Plugin Project-> RCP Application -> Mail Template) Anschließend sagen wir AspectJ Tools -> convert to AspectJ Project.
Unser Business Service Interface
Java:
/**
*
*/
package de.tutorials.rcp.withspringandaspectj.services;
/**
* @author Thomas.Darimont
*
*/
public interface IBusinessService {
String businessOperation(String argument);
}
Unsere Implementierung:
Java:
/**
*
*/
package de.tutorials.rcp.withspringandaspectj.services.internal;
import de.tutorials.rcp.withspringandaspectj.services.IBusinessService;
/**
* @author Thomas.Darimont
*
*/
public class BusinessService implements IBusinessService {
public String businessOperation(String argument) {
return "Upper: " + argument.toUpperCase();
}
}
So nun statten wir unsere Mail Beispielanwendung erstmal mit den notwendigen Bilbiotheken aus.
Wir brauchen das spring.jar , spring-aspects.jar (findet man im dist Verzeichnis der Springframework Distribution)
und commons-logging.jar (lib/jakrata-commons), cg-lib-nodepend2.1_3.jar (lib/cglib), dom4j-xxx.jar (lib/dom4j).
Das Springframework findet man hier (die -with-dependencies) Variante enthält alle notwendigen Bibliotheken auf einen Schlag.
http://www.springframework.org/download
Diese Bibliotheken legen wir in den Runtime-Classpath unserer Anwendung:
Manfest-Editor -> Runtime -> Classpath (hier die jars hinzufügen)
Nun modifizieren wir die generierte NavigationView Klasse:
Java:
package de.tutorials.rcp.withspringandaspectj;
import java.util.ArrayList;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.springframework.beans.factory.annotation.Configurable;
import de.tutorials.rcp.withspringandaspectj.services.IBusinessService;
@Configurable
public class NavigationView extends ViewPart {
public static final String ID = "de.tutorials.rcp.withSpringAndAspectJ.navigationView";
private TreeViewer viewer;
IBusinessService businessService;
class TreeObject {
private String name;
private TreeParent parent;
public TreeObject(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setParent(TreeParent parent) {
this.parent = parent;
}
public TreeParent getParent() {
return parent;
}
public String toString() {
return getName();
}
}
class TreeParent extends TreeObject {
private ArrayList children;
public TreeParent(String name) {
super(name);
children = new ArrayList();
}
public void addChild(TreeObject child) {
children.add(child);
child.setParent(this);
}
public void removeChild(TreeObject child) {
children.remove(child);
child.setParent(null);
}
public TreeObject[] getChildren() {
return (TreeObject[]) children.toArray(new TreeObject[children.size()]);
}
public boolean hasChildren() {
return children.size()>0;
}
}
class ViewContentProvider implements IStructuredContentProvider,
ITreeContentProvider {
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
}
public void dispose() {
}
public Object[] getElements(Object parent) {
return getChildren(parent);
}
public Object getParent(Object child) {
if (child instanceof TreeObject) {
return ((TreeObject)child).getParent();
}
return null;
}
public Object[] getChildren(Object parent) {
if (parent instanceof TreeParent) {
return ((TreeParent)parent).getChildren();
}
return new Object[0];
}
public boolean hasChildren(Object parent) {
if (parent instanceof TreeParent)
return ((TreeParent)parent).hasChildren();
return false;
}
}
class ViewLabelProvider extends LabelProvider {
public String getText(Object obj) {
return obj.toString();
}
public Image getImage(Object obj) {
String imageKey = ISharedImages.IMG_OBJ_ELEMENT;
if (obj instanceof TreeParent)
imageKey = ISharedImages.IMG_OBJ_FOLDER;
return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey);
}
}
/**
* We will set up a dummy model to initialize tree heararchy. In real
* code, you will connect to a real model and expose its hierarchy.
*/
private TreeObject createDummyModel() {
TreeObject to1 = new TreeObject("Inbox");
TreeObject to2 = new TreeObject("Drafts");
TreeObject to3 = new TreeObject("Sent");
TreeParent p1 = new TreeParent("me@this.com");
p1.addChild(to1);
p1.addChild(to2);
p1.addChild(to3);
TreeObject to4 = new TreeObject("Inbox");
TreeParent p2 = new TreeParent("other@aol.com");
p2.addChild(to4);
TreeParent root = new TreeParent("");
root.addChild(p1);
root.addChild(p2);
return root;
}
/**
* This is a callback that will allow us to create the viewer and initialize
* it.
*/
public void createPartControl(Composite parent) {
viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setInput(createDummyModel());
}
/**
* Passing the focus request to the viewer's control.
*/
public void setFocus() {
viewer.getControl().setFocus();
}
public IBusinessService getBusinessService() {
return businessService;
}
public void setBusinessService(IBusinessService businessService) {
System.out.println("Set businessService: " + businessService);
this.businessService = businessService;
}
@Override
public void init(IViewSite site) throws PartInitException {
System.out.println("init -> viewSite: " + site);
System.out.println("init -> businessService: " + getBusinessService());
super.init(site);
}
}
und überschreiben die init(...) Methode von ViewPart diese wird von der Eclipse Platform nach dem erzeugen einer View aufgerufen um ihren Lebenszyklus zu starten. Weiterhin haben wir den Business Service als Attribut aufgehängt und entsprechende getter/setter generiert.
Unsere Spring-Konfiguration schaut nun so aus:
applicationContext.xml:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean name="NavigationView" class="de.tutorials.rcp.withspringandaspectj.NavigationView" lazy-init="true">
<property name="businessService" ref="businessService"/>
</bean>
<bean name="businessService" class="de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService"/>
</beans>
Unser Activator startet den Springframework-Kontext beim Start unserer Anwendung:
Java:
package de.tutorials.rcp.withspringandaspectj;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* The activator class controls the plug-in life cycle
*/
public class Activator extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "de.tutorials.rcp.withSpringAndAspectJ";
// The shared instance
private static Activator plugin;
private ApplicationContext applicationContext;
/**
* The constructor
*/
public Activator() {
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
this.applicationContext = createApplicationContext();
}
/**
*
*/
private ApplicationContext createApplicationContext() {
Thread.currentThread().setContextClassLoader(
Activator.class.getClassLoader());
try {
return new ClassPathXmlApplicationContext(FileLocator.toFileURL(
getBundle().getResource("config/applicationContext.xml"))
.toString());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static Activator getDefault() {
return plugin;
}
/**
* Returns an image descriptor for the image file at the given plug-in
* relative path
*
* @param path
* the path
* @return the image descriptor
*/
public static ImageDescriptor getImageDescriptor(String path) {
return imageDescriptorFromPlugin(PLUGIN_ID, path);
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
Nun kommen unsere Aspekte:
Unser abstracter Configuration aspect bietet die Möglichkeit Objete nach ihrer Erzeugung mit new durch den
abstracten objectInitialization pointcut nachträglich mit Spring zu konfigurieren:
Java:
/**
*
*/
package de.tutorials.rcp.withspringandaspectj.aspects;
import de.tutorials.rcp.withspringandaspectj.Activator;
import org.springframework.beans.factory.annotation.Configurable;
/**
* @author Thomas.Darimont
*
*/
public abstract aspect Configuration {
public abstract pointcut objectInitialization(Object instance);
public pointcut configurableAnnotationIsPresent():
within(@Configurable *);
before(Object instance) : objectInitialization(instance) && configurableAnnotationIsPresent(){
System.out.println("Configuring " + instance.getClass());
Activator.getDefault().getApplicationContext()
.getAutowireCapableBeanFactory().configureBean(instance,
instance.getClass().getSimpleName());
}
}
http://www.tutorials.de/forum/java/...e-bei-mit-new-erzeugten-beans-mt-aspectj.html
Für die Konfiguration einer View sieht ein konkreter Aspect dazu dann ungefähr so aus:
Java:
/**
*
*/
package de.tutorials.rcp.withspringandaspectj.aspects;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.IViewSite;
/**
* @author Thomas.Darimont
*
*/
public aspect ViewConfiguration extends Configuration{
public pointcut objectInitialization(Object instance):
execution(* ViewPart+.init(IViewSite) ) && this(instance);
}
Damit wären wir auch schon fertig.
Zum Starten klicken wir mit der Maus auf das Projekt mit der rechten Maustaste und wählen im Kontextmenü,
run -> as eclipse application aus. Sollte das nicht klappen muss man die Launch-Configuration anpassen.
Dazu geht man einfach in der Launch-Configuration auf den Reiter Plugins, deselektiert erstmal alles, klickt dann
nur "unser" Plugin-Projekt im Workspace an und sagt -> Add required Plugins. Anschließend klickt man auf apply und schon sollte es gehen.
Ausgabe bei mir :
Code:
24.06.2007 17:25:08 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1b1fbf4: display name [org.springframework.context.support.ClassPathXmlApplicationContext@1b1fbf4]; startup date [Sun Jun 24 17:25:08 CEST 2007]; root of context hierarchy
24.06.2007 17:25:08 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from URL [file:/C:/Dokumente und Einstellungen/Thomas.Darimont/workspace-3.3RC4/de.tutorials.rcp.withSpringAndAspectJ/config/applicationContext.xml]
24.06.2007 17:25:08 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@1b1fbf4]: org.springframework.beans.factory.support.DefaultListableBeanFactory@b3319f
24.06.2007 17:25:08 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@b3319f: defining beans [NavigationView,businessService]; root of factory hierarchy
Configuring class de.tutorials.rcp.withspringandaspectj.NavigationView
Set businessService: de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService@771eb1
init -> viewSite: PartSite(id=de.tutorials.rcp.withSpringAndAspectJ.navigationView,pluginId=de.tutorials.rcp.withSpringAndAspectJ,registeredName=Mailboxes,hashCode=8392793)
init -> businessService: de.tutorials.rcp.withspringandaspectj.services.internal.BusinessService@771eb1
Das Projekt (ohne Libraries) findet man im Anhang.
Gruß Tom
Anhänge
Zuletzt bearbeitet von einem Moderator: