当前页面: 开发资料首页 → Java 专题 → 在Eclipse RCP中实现控制反转(IoC)
摘要: 在Eclipse RCP中实现控制反转(IoC)
@Injected public void aServicingMethod(
Service s1,
AnotherService s2) {
// save s1 and s2 into class variables
// to use them when needed
}
/**
* Injects the requested dependencies into the
* parameter object. It scans the serviceable
* object looking for methods tagged with the
* {@link Injected} annotation.Parameter types are
* extracted from the matching method. An instance
* of each type is created from the registered
* factories (see {@link IServiceFactory}). When
* instances for all the parameter types have been
* created the method is invoked and the next one
* is examined.
*
* @param serviceable the object to be serviced
* @throws ServiceException
*/
public static void service(Object serviceable)
throws ServiceException {
ServiceLocator sl = getInstance();
if (sl.isAlreadyServiced(serviceable)) {
// prevent multiple initializations due to
// constructor hierarchies
System.out.println(
"Object " +
serviceable +
" has already been configured ");
return;
}
System.out.println("Configuring " +
serviceable);
// Parse the class for the requested services
for (Method m :
serviceable.getClass().getMethods()) {
boolean skip=false;
Injected ann=m.getAnnotation(Injected.class);
if (ann != null) {
Object[] services =
new Object[m.getParameterTypes().length];
int i = 0;
for(Class<?> klass :m.getParameterTypes()){
IServiceFactory factory =
sl.getFactory(klass,ann.optional());
if (factory == null) {
skip = true;
break;
}
Object service =
factory.getServiceInstance();
// sanity check: verify that the returned
// service's class is the expected one
// from the method
assert(service.getClass().equals(klass) ||
klass.isAssignableFrom(service.getClass()));
services[i++] = service ;
}
try {
if (!skip)
m.invoke(serviceable, services);
}
catch(IllegalAccessException iae) {
if (!ann.optional())
throw new ServiceException(
"Unable to initialize services on " +
serviceable +
": " + iae.getMessage(),iae);
}
catch(InvocationTargetException ite) {
if (!ann.optional())
throw new ServiceException(
"Unable to initialize services on " +
serviceable +
": " + ite.getMessage(),ite);
}
}
}
sl.setAsServiced(serviceable);
}
@Serviceable
public class ServiceableObject {
public ServiceableObject() {
System.out.println("Initializing...");
}
@Injected public void aServicingMethod(
Service s1,
AnotherService s2) {
// ... omissis ...
}
}
@Serviceable
public class ServiceableObject {
public ServiceableObject() {
ServiceLocator.service(this);
System.out.println("Initializing...");
}
@Injected public void aServicingMethod(
Service s1,
AnotherService s2) {
// ... omissis ...
}
}
public class IOCTransformer
implements ClassFileTransformer {
public byte[] transform(
ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer)
throws IllegalClassFormatException {
System.out.println("Loading " + className);
ClassReader creader =
new ClassReader(classfileBuffer);
// Parse the class file
ConstructorVisitor cv =
new ConstructorVisitor();
ClassAnnotationVisitor cav =
new ClassAnnotationVisitor(cv);
creader.accept(cav, true);
if (cv.getConstructors().size() > 0) {
System.out.println("Enhancing "+className);
// Generate the enhanced-constructor class
ClassWriter cw = new ClassWriter(false);
ClassConstructorWriter writer =
new ClassConstructorWriter(
cv.getConstructors(),
cw);
creader.accept(writer, false);
return cw.toByteArray();
}
else
return null;
}
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new IOCTransformer());
}
}
public class ClassAnnotationVisitor
extends ClassAdapter {
private boolean matches = false;
public ClassAnnotationVisitor(ClassVisitor cv) {
super(cv);
}
@Override
public AnnotationVisitor visitAnnotation(
String desc,
boolean visible) {
if (visible &&
desc.equals("Lcom/onjava/servicelocator/annot/Serviceable;")) {
matches = true;
}
return super.visitAnnotation(desc, visible);
}
@Override
public MethodVisitor visitMethod(
int access,
String name,
String desc,
String signature,
String[] exceptions) {
if (matches)
return super.visitMethod(
access,name,desc,signature,exceptions);
else {
return null;
}
}
}
public class ConstructorVisitor
extends EmptyVisitor {
private Setconstructors;
public ConstructorVisitor() {
constructors = new HashSet();
}
public SetgetConstructors() {
return constructors;
}
@Override
public MethodVisitor visitMethod(
int access,
String name,
String desc,
String signature,
String[] exceptions) {
Type t = Type.getReturnType(desc);
if (name.indexOf("") != -1 &&
t.equals(Type.VOID_TYPE)) {
constructors.add(new Method(name,desc));
}
return super.visitMethod(
access,name,desc,signature,exceptions);
}
}
com.onjava.servicelocator.ServiceLocator.service(this);
// mv is an ASM method visitor,
// a class which allows method manipulation
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(
INVOKESTATIC,
"com/onjava/servicelocator/ServiceLocator",
"service",
"(Ljava/lang/Object;)V");
public interface IFortuneCookie {
public String getMessage();
}
public class FortuneServiceFactory
implements IServiceFactory {
public Object getServiceInstance()
throws ServiceException {
return new FortuneCookieImpl();
}
// ... omissis ...
}
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>point="com.onjava.servicelocator.servicefactory">
class="com.onjava.fortuneservice.FortuneServiceFactory"
id="com.onjava.fortuneservice.FortuneServiceFactory"
name="Fortune Service Factory"
resourceClass="com.onjava.fortuneservice.IFortuneCookie"/>
@Serviceable
public class View
extends ViewPart {
public static final String ID =
"FortuneClient.view";
private IFortuneCookie cookie;
@Injected(optional=false)
public void setDate(IFortuneCookie cookie) {
this.cookie = cookie;
}
public void createPartControl(Composite parent){
Label l = new Label(parent,SWT.WRAP);
l.setText("Your fortune cookie is:\n"
+ cookie.getMessage());
}
public void setFocus() {}
}