You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2019/05/16 19:13:22 UTC

[isis] branch 2112_SpringBoot updated: ISIS-2112: refactoring IsisConfiguration to be managed by Spring

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch 2112_SpringBoot
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/2112_SpringBoot by this push:
     new a6a1864  ISIS-2112: refactoring IsisConfiguration to be managed by Spring
a6a1864 is described below

commit a6a1864abe53826d82023718357c41173926ab18
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu May 16 20:09:16 2019 +0200

    ISIS-2112: refactoring IsisConfiguration to be managed by Spring
    
    - makes the ServiceRegistryDefault the bootstrapping entry-point of
    Spring into Isis, that is ServiceRegistryDefault is
    ApplicationContextAware
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-2112
---
 .../applib/services/inject/ServiceInjector.java    | 27 ++++++++-
 .../main/java/org/apache/isis/config/Presets.java  | 48 ++++------------
 .../beans}/BeanScanInterceptorForSpring.java       |  2 +-
 .../isis/testdomain/jdo/JdoTestDomainModule.java   | 10 +---
 .../core/metamodel/ServiceInjector_forTesting.java |  8 ++-
 .../metamodel/services/ServiceInjectorDefault.java | 47 ++++++++++------
 .../core/metamodel/services/ServicesInjector.java  | 57 -------------------
 .../services/registry/ServiceRegistryDefault.java  | 56 ++++++++++++++++---
 .../services/ServiceInjectorDefaultTest.java       | 57 +++++++++----------
 .../ServiceInjectorDefaultTest_usingFields.java    | 19 +++----
 ...InjectorDefaultTest_validateServices_happy.java | 12 ++--
 .../persistence/PersistenceSessionFactory5.java    |  7 ---
 .../org/apache/isis/runtime/spring/IsisBoot.java   | 57 ++-----------------
 .../sessmgmt/SessionManagementServiceDefault.java  | 11 +---
 .../manager/AuthenticationManager.java             | 18 +++---
 .../standard/AuthenticationManagerStandard.java    | 22 +++-----
 .../wicket/viewer/IsisWicketApplication.java       | 65 +++++++++-------------
 .../viewer/wicket/viewer/IsisWicketModule.java     | 56 ++++++++++---------
 .../viewer/wicket/model/models/ActionModel.java    |  1 -
 .../isis/viewer/wicket/ui/panels/FormAbstract.java |  2 -
 .../viewer/wicket/ui/panels/PanelAbstract.java     |  2 -
 .../java/domainapp/application/HelloWorldApp.java  |  7 ++-
 .../application/HelloWorldAppManifest.java         | 17 +++---
 23 files changed, 259 insertions(+), 349 deletions(-)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/inject/ServiceInjector.java b/core/applib/src/main/java/org/apache/isis/applib/services/inject/ServiceInjector.java
index 31cb535..a56cb61 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/inject/ServiceInjector.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/inject/ServiceInjector.java
@@ -16,6 +16,15 @@
  */
 package org.apache.isis.applib.services.inject;
 
+import java.util.NoSuchElementException;
+import java.util.function.Consumer;
+
+import org.springframework.beans.factory.InjectionPoint;
+
+import org.apache.isis.commons.internal.context._Context;
+
+import lombok.val;
+
 /**
  * Resolves injection points using the ServiceRegistry.
  * <p>
@@ -26,6 +35,22 @@ package org.apache.isis.applib.services.inject;
  */
 public interface ServiceInjector {
 
-    <T> T injectServicesInto(final T domainObject);
+    <T> T injectServicesInto(final T domainObject, Consumer<InjectionPoint> onNotResolvable);
+    
+    default <T> T injectServicesInto(final T domainObject) {
+        return injectServicesInto(domainObject, injectionPoint->{
+            
+            val injectionPointName = injectionPoint.toString();
+            val requiredType = injectionPoint.getDeclaredType();
+            val msg = String
+                    .format("Could not resolve injection point [%s] in target '%s' of required type '%s'",
+                    injectionPointName,        
+                    domainObject.getClass().getName(),
+                    requiredType);
+            throw new NoSuchElementException(msg);
+        });
+            
+    }
+   
     
 }
diff --git a/core/config/src/main/java/org/apache/isis/config/Presets.java b/core/config/src/main/java/org/apache/isis/config/Presets.java
index b356950..bd5344e 100644
--- a/core/config/src/main/java/org/apache/isis/config/Presets.java
+++ b/core/config/src/main/java/org/apache/isis/config/Presets.java
@@ -30,6 +30,7 @@ import org.springframework.core.io.support.PropertySourceFactory;
 
 import org.apache.isis.applib.AppManifest;
 
+import lombok.RequiredArgsConstructor;
 import lombok.val;
 
 /**
@@ -40,50 +41,25 @@ import lombok.val;
  */
 public final class Presets  {
 
-    private static enum Providers implements Consumer<Map<String, String>> {
+    @RequiredArgsConstructor
+    private static enum Providers {
     
-        H2InMemory {
+        H2InMemory(AppManifest.Presets::withH2InMemoryProperties),
+        HsqlDbInMemory(AppManifest.Presets::withHsqlDbInMemoryProperties),
+        DataNucleus(AppManifest.Presets::withDataNucleusProperties),
+        IsisIntegTest(AppManifest.Presets::withIsisIntegTestProperties),
+		NoTranslations(map->map.put("isis.services.translation.po.mode", "disable")),
     
-            @Override
-            public void accept(Map<String, String> map) {
-                AppManifest.Presets.withH2InMemoryProperties(map);
-            }
-            
-        },
-        
-        HsqlDbInMemory {
-    
-            @Override
-            public void accept(Map<String, String> map) {
-                AppManifest.Presets.withHsqlDbInMemoryProperties(map);
-            }
-            
-        },
-        
-        DataNucleus {
-    
-            @Override
-            public void accept(Map<String, String> map) {
-                AppManifest.Presets.withDataNucleusProperties(map);
-            }
-            
-        },
+        ;
         
-        IsisIntegTest {
-    
-            @Override
-            public void accept(Map<String, String> map) {
-                AppManifest.Presets.withIsisIntegTestProperties(map);
-            }
-            
-        },
-    
+        private final Consumer<Map<String, String>> populator;
     }
     
     public static final String H2InMemory = "H2InMemory";
     public static final String HsqlDbInMemory = "HsqlDbInMemory";
     public static final String DataNucleus = "DataNucleus";
     public static final String IsisIntegTest = "IsisIntegTest";
+    public static final String NoTranslations = "NoTranslations";
     
     
     public static class Factory implements PropertySourceFactory {
@@ -94,7 +70,7 @@ public final class Presets  {
                 EncodedResource resource) throws IOException {
             
             val map = new HashMap<String, String>(); 
-            Providers.valueOf(name).accept(map);
+            Providers.valueOf(name).populator.accept(map);
             
             val widenedMap = new HashMap<String, Object>();
             widenedMap.putAll(map);
diff --git a/core/runtime-extensions/src/main/java/org/apache/isis/runtime/spring/BeanScanInterceptorForSpring.java b/core/config/src/main/java/org/apache/isis/config/beans/BeanScanInterceptorForSpring.java
similarity index 98%
rename from core/runtime-extensions/src/main/java/org/apache/isis/runtime/spring/BeanScanInterceptorForSpring.java
rename to core/config/src/main/java/org/apache/isis/config/beans/BeanScanInterceptorForSpring.java
index e3a2361..d284817 100644
--- a/core/runtime-extensions/src/main/java/org/apache/isis/runtime/spring/BeanScanInterceptorForSpring.java
+++ b/core/config/src/main/java/org/apache/isis/config/beans/BeanScanInterceptorForSpring.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.runtime.spring;
+package org.apache.isis.config.beans;
 
 import java.io.IOException;
 
diff --git a/core/detached-tests/src/test/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule.java b/core/detached-tests/src/test/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule.java
index 50aa8bc..f3cf1d3 100644
--- a/core/detached-tests/src/test/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule.java
+++ b/core/detached-tests/src/test/java/org/apache/isis/testdomain/jdo/JdoTestDomainModule.java
@@ -24,9 +24,7 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.PropertySource;
 
 import org.apache.isis.applib.services.fixturespec.FixtureScriptsSpecificationProvider;
-import org.apache.isis.config.IsisConfiguration;
 import org.apache.isis.config.beans.WebAppConfigBean;
-import org.apache.isis.config.internal._Config;
 import org.apache.isis.core.runtime.authorization.standard.AuthorizationManagerStandard;
 import org.apache.isis.core.security.authentication.bypass.AuthenticatorBypass;
 import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
@@ -40,11 +38,6 @@ import org.apache.isis.core.security.authorization.standard.Authorizor;
 @PropertySource("file:src/test/java/org/apache/isis/testdomain/jdo/isis-non-changing.properties")
 public class JdoTestDomainModule {
     
-    @Bean @Produces @Singleton
-    public IsisConfiguration getConfig() {
-        return _Config.getConfiguration();
-    }
-    
     /**
     * The standard authentication manager, configured with the 'bypass' authenticator 
     * (allows all requests through).
@@ -72,8 +65,7 @@ public class JdoTestDomainModule {
    public Authorizor autorizor() {
        return new AuthorizorBypass();
    }
-   
-   
+
    @Bean @Produces @Singleton
    public WebAppConfigBean webAppConfigBean() {
        return WebAppConfigBean.builder()
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/ServiceInjector_forTesting.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/ServiceInjector_forTesting.java
index 72857c0..f14cb62 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/ServiceInjector_forTesting.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/ServiceInjector_forTesting.java
@@ -20,6 +20,10 @@ package org.apache.isis.core.metamodel;
 
 import static java.util.Objects.requireNonNull;
 
+import java.util.function.Consumer;
+
+import org.springframework.beans.factory.InjectionPoint;
+
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.core.metamodel.services.ServiceInjectorDefault;
 import org.apache.isis.core.metamodel.specloader.InjectorMethodEvaluatorDefault;
@@ -31,7 +35,7 @@ class ServiceInjector_forTesting implements ServiceInjector {
     private ServiceInjector delegate;
 
     @Override
-    public <T> T injectServicesInto(T domainObject) {
+    public <T> T injectServicesInto(T domainObject, Consumer<InjectionPoint> onNotResolvable) {
         
         if(delegate==null) {
             
@@ -47,6 +51,8 @@ class ServiceInjector_forTesting implements ServiceInjector {
             val serviceRegistry = requireNonNull(mmcb.getServiceRegistry());
             val injectorMethodEvaluator = new InjectorMethodEvaluatorDefault();
             
+            //Note: when testing we don't report un-resolvable injection points.
+            
             delegate = ServiceInjectorDefault.getInstanceAndInit(
                     configuration, serviceRegistry, injectorMethodEvaluator);
             
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefault.java
index 395b023..11a3e70 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefault.java
@@ -23,12 +23,16 @@ import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Collection;
 import java.util.Map;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
+import org.springframework.beans.factory.InjectionPoint;
+import org.springframework.core.MethodParameter;
+
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.commons.internal.base._NullSafe;
@@ -56,14 +60,14 @@ public class ServiceInjectorDefault implements ServiceInjector {
     private final Map<Class<?>, Field[]> fieldsByClassCache = _Maps.newHashMap();
     
     @Override
-    public <T> T injectServicesInto(T domainObject) {
-        injectServices(domainObject);
+    public <T> T injectServicesInto(T domainObject, Consumer<InjectionPoint> onNotResolvable) {
+        injectServices(domainObject, onNotResolvable);
         return domainObject;
     }
     
     @PostConstruct
     public void init() {
-        autowireSetters = configuration.getBoolean(KEY_SET_PREFIX, true);
+        autowireSetters = configuration.getBoolean(KEY_SET_PREFIX, false);
         autowireInject = configuration.getBoolean(KEY_INJECT_PREFIX, true);
     }
     
@@ -72,34 +76,34 @@ public class ServiceInjectorDefault implements ServiceInjector {
     boolean autowireSetters;
     boolean autowireInject;    
 
-    private void injectServices(final Object targetPojo) {
+    private void injectServices(final Object targetPojo, Consumer<InjectionPoint> onNotResolvable) {
 
         final Class<?> cls = targetPojo.getClass();
 
-        injectToFields(targetPojo, cls);
+        injectToFields(targetPojo, cls, onNotResolvable);
 
         if(autowireSetters) {
-            injectViaPrefixedMethods(targetPojo, cls, "set");
+            injectViaPrefixedMethods(targetPojo, cls, "set", onNotResolvable);
         }
         if(autowireInject) {
-            injectViaPrefixedMethods(targetPojo, cls, "inject");
+            injectViaPrefixedMethods(targetPojo, cls, "inject", onNotResolvable);
         }
     }
 
-    private void injectToFields(final Object targetPojo, final Class<?> cls) {
+    private void injectToFields(final Object targetPojo, final Class<?> cls, Consumer<InjectionPoint> onNotResolvable) {
 
         _NullSafe.stream(fieldsByClassCache.computeIfAbsent(cls, __->cls.getDeclaredFields()))
         .filter(isAnnotatedForInjection())
-        .forEach(field->injectToField(targetPojo, field));
+        .forEach(field->injectToField(targetPojo, field, onNotResolvable));
 
         // recurse up the object's class hierarchy
         final Class<?> superclass = cls.getSuperclass();
         if(superclass != null) {
-            injectToFields(targetPojo, superclass);
+            injectToFields(targetPojo, superclass, onNotResolvable);
         }
     }
 
-    private void injectToField(final Object targetPojo, final Field field) {
+    private void injectToField(final Object targetPojo, final Field field, Consumer<InjectionPoint> onNotResolvable) {
 
         final Class<?> typeToBeInjected = field.getType();
         // don't think that type can ever be null,
@@ -111,7 +115,7 @@ public class ServiceInjectorDefault implements ServiceInjector {
         // inject matching services into a field of type Collection<T> if a generic type T is present
         final Class<?> elementType = _Collections.inferElementTypeIfAny(field);
         if(elementType!=null) {
-            injectToField_nonScalar(targetPojo, field, elementType);
+            injectToField_nonScalar(targetPojo, field, elementType, onNotResolvable);
             return;
         }
         
@@ -119,6 +123,8 @@ public class ServiceInjectorDefault implements ServiceInjector {
         if(beans.isCardinalityOne()) {
             val bean = beans.getSingleton().get();
             invokeInjectorField(field, targetPojo, bean);    
+        } else {
+            onNotResolvable.accept(new InjectionPoint(field));
         }
 
     }
@@ -127,7 +133,8 @@ public class ServiceInjectorDefault implements ServiceInjector {
     private void injectToField_nonScalar(
             final Object targetPojo, 
             final Field field, 
-            final Class<?> elementType) {
+            final Class<?> elementType, 
+            final Consumer<InjectionPoint> onNotResolvable) {
         
         final Class<? extends Collection<Object>> collectionTypeToBeInjected =
                 (Class<? extends Collection<Object>>) field.getType();
@@ -141,6 +148,8 @@ public class ServiceInjectorDefault implements ServiceInjector {
                     .collect(_Collections.<Object>toUnmodifiableOfType(collectionTypeToBeInjected));
 
             invokeInjectorField(field, targetPojo, collectionOfServices);
+        } else {
+            onNotResolvable.accept(new InjectionPoint(field));
         }
         
     }
@@ -148,16 +157,18 @@ public class ServiceInjectorDefault implements ServiceInjector {
     private void injectViaPrefixedMethods(
             final Object targetPojo,
             final Class<?> cls,
-            final String prefix) {
+            final String prefix, 
+            final Consumer<InjectionPoint> onNotResolvable) {
 
         _NullSafe.stream(methodsByClassCache.computeIfAbsent(cls, __->cls.getMethods()))
         .filter(nameStartsWith(prefix))
-        .forEach(prefixedMethod->injectIntoSetter(targetPojo, prefixedMethod));
+        .forEach(prefixedMethod->injectIntoSetter(targetPojo, prefixedMethod, onNotResolvable));
     }
 
     private void injectIntoSetter(
             final Object targetPojo,
-            final Method setter) {
+            final Method setter, 
+            final Consumer<InjectionPoint> onNotResolvable) {
         
         final Class<?> typeToBeInjected = injectorMethodEvaluator.getTypeToBeInjected(setter);
         if(typeToBeInjected == null) {
@@ -168,7 +179,9 @@ public class ServiceInjectorDefault implements ServiceInjector {
         if(instance.isCardinalityOne()) {
             val bean = instance.getSingleton().get();
             invokeInjectorMethod(setter, targetPojo, bean);    
-        } 
+        } else {
+            onNotResolvable.accept(new InjectionPoint(new MethodParameter(setter, 0)));
+        }
         
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java
deleted file mode 100644
index 09c94c8..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-package org.apache.isis.core.metamodel.services;
-
-/**
- * @deprecated JUnit tests need to be migrated. 
- *
- */
-@Deprecated
-public class ServicesInjector /*implements ApplicationScopedComponent*/ {
-    private static final String KEY_SET_PREFIX = "isis.services.injector.setPrefix";
-    private static final String KEY_INJECT_PREFIX = "isis.services.injector.injectPrefix";
-
-
-//    // -- BUILDER
-//    
-//    public static ServicesInjectorBuilder builder() {
-//        final IsisConfiguration config = _Config.getConfiguration();
-//        return new ServicesInjectorBuilder()
-//                .addService(config)
-//                .autowireSetters(config.getBoolean(KEY_SET_PREFIX, true))
-//                .autowireInject(config.getBoolean(KEY_INJECT_PREFIX, true));
-//    }
-//    
-//    public static ServicesInjectorBuilder builderForTesting() {
-//        return builder()
-//                .autowireSetters(true)
-//                .autowireInject(false);
-//    }
-//    
-//    // -- CONSTRUCTOR (NOT EXPOSED)
-//
-//    ServicesInjector(
-//            final List<Object> services,
-//            final InjectorMethodEvaluator injectorMethodEvaluator,
-//            final boolean autowireSetters,
-//            final boolean autowireInject
-//            ) {
-//        
-//    }
-
-    
-}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/registry/ServiceRegistryDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/registry/ServiceRegistryDefault.java
index 04a7971..be042665 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/registry/ServiceRegistryDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/registry/ServiceRegistryDefault.java
@@ -24,23 +24,34 @@ import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import javax.inject.Inject;
 import javax.inject.Singleton;
 
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.env.ConfigurableEnvironment;
+
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.commons.internal.base._NullSafe;
+import org.apache.isis.commons.internal.context._Context;
 import org.apache.isis.commons.internal.spring._Spring;
 import org.apache.isis.commons.ioc.BeanAdapter;
+import org.apache.isis.config.IsisConfiguration;
+import org.apache.isis.config.internal._Config;
+import org.apache.isis.core.runtime.threadpool.ThreadPoolExecutionMode;
+import org.apache.isis.core.runtime.threadpool.ThreadPoolSupport;
+
+import lombok.extern.slf4j.Slf4j;
 
 /**
  * @since 2.0.0
  */
-@Singleton
-public final class ServiceRegistryDefault implements ServiceRegistry {
-
-    private final _Lazy<Set<BeanAdapter>> registeredBeans = _Lazy.threadSafe(this::enumerateBeans);
+@Singleton @Slf4j
+public final class ServiceRegistryDefault implements ServiceRegistry, ApplicationContextAware {
 
     @Override
     public boolean isDomainServiceType(Class<?> cls) {
@@ -54,18 +65,49 @@ public final class ServiceRegistryDefault implements ServiceRegistry {
     public Stream<BeanAdapter> streamRegisteredBeans() {
         return registeredBeans.get().stream();
     }
+    
+    @Override
+    public void setApplicationContext(ApplicationContext springContext) throws BeansException {
+        
+        // disables concurrent Spec-Loading
+        ThreadPoolSupport.HIGHEST_CONCURRENCY_EXECUTION_MODE_ALLOWED = 
+                ThreadPoolExecutionMode.SEQUENTIAL_WITHIN_CALLING_THREAD;
+        
+        _Context.clear(); // ensures a well defined precondition
+
+        _Context.putSingleton(ApplicationContext.class, springContext);
+        _Config.putAll(_Spring.copySpringEnvironmentToMap(configurableEnvironment));
+
+        log.info("Spring's context was passed over to Isis");
+        
+        isisConfiguration = _Config.getConfiguration(); // finalize config
+        
+        // dump config to log
+        if(log.isInfoEnabled() && !isisConfiguration.getEnvironment().isUnitTesting()) {
+            log.info("\n" + _Config.getConfiguration().toStringFormatted());
+        }    
+        
+    }
+    
+    @Bean @Singleton
+    public IsisConfiguration getConfiguration() {
+        return isisConfiguration;
+    }
 
     // -- DEPS
     
-    // ensure we have Spring's context
-    @Inject SpringContextProvider springContextProvider;
+    @Autowired private ConfigurableEnvironment configurableEnvironment;
+    private IsisConfiguration isisConfiguration;
     
     // -- HELPER
     
+    private final _Lazy<Set<BeanAdapter>> registeredBeans = _Lazy.threadSafe(this::enumerateBeans);
+    
     Set<BeanAdapter> enumerateBeans() {
         return _Spring.streamAllBeans(this::isDomainServiceType)
         .filter(_NullSafe::isPresent)
         .collect(Collectors.toCollection(HashSet::new));
     }
 
+
 }
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefaultTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefaultTest.java
index eb13ce3..d5b7a8c 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefaultTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefaultTest.java
@@ -25,42 +25,36 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Profile;
 import org.springframework.test.context.ActiveProfiles;
 
-//import org.jmock.Expectations;
-//import org.jmock.auto.Mock;
-//import org.junit.After;
-//import org.junit.Assert;
-//import org.junit.Before;
-//import org.junit.Rule;
-//import org.junit.Test;
-
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.commons.internal.spring._Spring;
-import org.apache.isis.config.IsisConfiguration;
-import org.apache.isis.config.internal._Config;
 import org.apache.isis.core.metamodel.services.registry.ServiceRegistryDefault;
 import org.apache.isis.core.metamodel.spec.InjectorMethodEvaluator;
 import org.apache.isis.core.metamodel.specloader.InjectorMethodEvaluatorDefault;
 
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.val;
 
 @ActiveProfiles("test")
 @SpringBootTest(classes = {
         ServiceInjectorDefault.class,
         ServiceRegistryDefault.class,
         ServiceInjectorDefaultTest.Producers.class,
-})
+    },
+    properties = {
+            "isis.services.injector.setPrefix=true"
+    })
 class ServiceInjectorDefaultTest {
 
     // -- SPRING SETUP
@@ -70,11 +64,6 @@ class ServiceInjectorDefaultTest {
     static class Producers {
         
         @Bean
-        IsisConfiguration getConfiguration() {
-            return _Config.getConfiguration();
-        }
-        
-        @Bean
         InjectorMethodEvaluator getInjectorMethodEvaluator() {
             return new InjectorMethodEvaluatorDefault();
         }
@@ -120,15 +109,14 @@ class ServiceInjectorDefaultTest {
     public static interface RepositoryServiceExtended extends RepositoryService, MixinService {
     }
 
-    public static interface SomeDomainObject {
-        public void setRepositoryService(RepositoryService container);
-        public void setMixinService(MixinService mixin);
-        public void setService1(Service1 service);
-        public void setService2(Service2 service);
+    @Getter @Setter
+    public static class SomeDomainObject {
+        private RepositoryService a;
+        private MixinService b;
+        private Service1 c;
+        private Service2 d;
     }
     
-    @MockBean SomeDomainObject mockDomainObject;
-    
     // -- TESTS
     
     @Inject private ServiceInjector injector;
@@ -145,13 +133,18 @@ class ServiceInjectorDefaultTest {
     @Test
     void shouldInject_RepositoryService() {
 
-        injector.injectServicesInto(mockDomainObject);
+        val mockDomainObject = new SomeDomainObject();
+        
+        injector.injectServicesInto(mockDomainObject, onNotResolvable->{
+            // ignore, checked below
+        });
+
         
-        verify(mockDomainObject, times(1)).setRepositoryService(any(RepositoryService.class));
+        assertNotNull(mockDomainObject.getA());
         //FIXME[2112] does not get injected ... 
-        //verify(mockDomainObject, times(1)).setMixinService(any(MixinService.class));
-        verify(mockDomainObject, times(1)).setService1(any(Service1.class));
-        verify(mockDomainObject, times(1)).setService2(any(Service2.class));
+        //assertNotNull(mockDomainObject.getB());
+        assertNotNull(mockDomainObject.getC());
+        assertNotNull(mockDomainObject.getD());
         
     }
     
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefaultTest_usingFields.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefaultTest_usingFields.java
index f8a7f82..b566da8 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefaultTest_usingFields.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefaultTest_usingFields.java
@@ -19,9 +19,6 @@
 
 package org.apache.isis.core.metamodel.services;
 
-import static org.hamcrest.Matchers.any;
-import static org.junit.Assert.assertThat;
-
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
@@ -29,17 +26,17 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.test.context.ActiveProfiles;
 
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.applib.services.repository.RepositoryService;
-import org.apache.isis.commons.internal.context._Context;
-import org.apache.isis.commons.internal.spring._Spring;
 import org.apache.isis.core.metamodel.services.registry.ServiceRegistryDefault;
 
+import static org.hamcrest.Matchers.any;
+import static org.junit.Assert.assertThat;
+
 import lombok.Getter;
 
 @ActiveProfiles("test")
@@ -48,7 +45,11 @@ import lombok.Getter;
         ServiceRegistryDefault.class,
         ServiceInjectorDefaultTest.Producers.class,
         ServiceInjectorDefaultTest_usingFields.Producers.class,
-})
+    },
+    properties = {
+            "isis.services.injector.setPrefix=true"
+    }
+)
 class ServiceInjectorDefaultTest_usingFields {
     
     @Configuration
@@ -108,12 +109,10 @@ class ServiceInjectorDefaultTest_usingFields {
     // -- TESTS
     
     @Inject private ServiceInjector injector;
-    @Inject private ApplicationContext applicationContext;
     
     @BeforeEach
     void setup() {
-        _Context.clear();
-        _Spring.init(applicationContext);    
+    
     }
     
     @Inject private A serviceA;
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefaultTest_validateServices_happy.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefaultTest_validateServices_happy.java
index eaaae39..3a5cd0c 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefaultTest_validateServices_happy.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/services/ServiceInjectorDefaultTest_validateServices_happy.java
@@ -24,15 +24,12 @@ import javax.inject.Inject;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Profile;
 import org.springframework.stereotype.Component;
 import org.springframework.test.context.ActiveProfiles;
 
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
-import org.apache.isis.commons.internal.context._Context;
-import org.apache.isis.commons.internal.spring._Spring;
 import org.apache.isis.core.metamodel.services.registry.ServiceRegistryDefault;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -44,7 +41,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
         ServiceInjectorDefaultTest.Producers.class,
         ServiceInjectorDefaultTest_validateServices_happy.DomainServiceWithSomeId.class,
         ServiceInjectorDefaultTest_validateServices_happy.DomainServiceWithDifferentId.class
-})
+        },
+    properties = {
+            "isis.services.injector.setPrefix=true"
+    }
+)
 class ServiceInjectorDefaultTest_validateServices_happy {
     
     // -- SCENARIO
@@ -62,12 +63,9 @@ class ServiceInjectorDefaultTest_validateServices_happy {
     // -- TESTS
     
     @Inject private ServiceRegistry serviceRegistry;
-    @Inject private ApplicationContext applicationContext;
     
     @BeforeEach
     void setup() {
-        _Context.clear();
-        _Spring.init(applicationContext);    
     }
 
     @Test
diff --git a/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionFactory5.java b/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionFactory5.java
index 31da952..5cf58c5 100644
--- a/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionFactory5.java
+++ b/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionFactory5.java
@@ -21,19 +21,16 @@ package org.apache.isis.core.runtime.system.persistence;
 
 import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
 
 import javax.jdo.PersistenceManagerFactory;
 
 import org.datanucleus.PropertyNames;
 import org.datanucleus.api.jdo.JDOPersistenceManagerFactory;
 
-import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.config.IsisConfiguration;
 import org.apache.isis.config.internal._Config;
 import org.apache.isis.core.commons.components.ApplicationScopedComponent;
-import org.apache.isis.core.metamodel.services.ServicesInjector;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.runtime.persistence.FixturesInstalledState;
 import org.apache.isis.core.runtime.persistence.FixturesInstalledStateHolder;
@@ -50,10 +47,6 @@ import lombok.extern.slf4j.Slf4j;
  *
  * Factory for {@link PersistenceSession}.
  *
- * <p>
- * Implementing class is added to {@link ServicesInjector} as an (internal) domain service; all public methods
- * must be annotated using {@link Programmatic}.
- * </p>
  */
 @Slf4j
 public class PersistenceSessionFactory5
diff --git a/core/runtime-extensions/src/main/java/org/apache/isis/runtime/spring/IsisBoot.java b/core/runtime-extensions/src/main/java/org/apache/isis/runtime/spring/IsisBoot.java
index d530449..165fac8 100644
--- a/core/runtime-extensions/src/main/java/org/apache/isis/runtime/spring/IsisBoot.java
+++ b/core/runtime-extensions/src/main/java/org/apache/isis/runtime/spring/IsisBoot.java
@@ -18,35 +18,21 @@
  */
 package org.apache.isis.runtime.spring;
 
-import javax.inject.Singleton;
-
 import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
-import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.ComponentScan.Filter;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.FilterType;
-import org.springframework.core.env.ConfigurableEnvironment;
 
 import org.apache.isis.applib.IsisApplibModule;
-import org.apache.isis.commons.internal.context._Context;
-import org.apache.isis.commons.internal.spring._Spring;
-import org.apache.isis.config.internal._Config;
+import org.apache.isis.config.beans.BeanScanInterceptorForSpring;
 import org.apache.isis.core.metamodel.IsisMetamodelModule;
-import org.apache.isis.core.metamodel.services.registry.ServiceRegistryDefault;
-import org.apache.isis.core.metamodel.services.registry.SpringContextProvider;
 import org.apache.isis.core.runtime.IsisRuntimeModule;
 import org.apache.isis.core.runtime.services.IsisRuntimeServicesModule;
-import org.apache.isis.core.runtime.threadpool.ThreadPoolExecutionMode;
-import org.apache.isis.core.runtime.threadpool.ThreadPoolSupport;
 import org.apache.isis.core.wrapper.IsisWrapperModule;
 
-import lombok.val;
-import lombok.extern.slf4j.Slf4j;
-
 @Configuration 
 @ComponentScan(
 		basePackageClasses= {
@@ -58,44 +44,13 @@ import lombok.extern.slf4j.Slf4j;
 		includeFilters= {
 				@Filter(type = FilterType.CUSTOM, classes= {BeanScanInterceptorForSpring.class})
 		})
-@Slf4j
 public class IsisBoot implements ApplicationContextAware {
-	
-    @Autowired
-    private ConfigurableEnvironment configurableEnvironment;
-    
-	@Override
-	public void setApplicationContext(ApplicationContext springContext) throws BeansException {
-	    
-        // disables concurrent Spec-Loading
-        ThreadPoolSupport.HIGHEST_CONCURRENCY_EXECUTION_MODE_ALLOWED = 
-                ThreadPoolExecutionMode.SEQUENTIAL_WITHIN_CALLING_THREAD;
-        
-        _Context.clear(); // ensures a well defined precondition
 
-	    _Context.putSingleton(ApplicationContext.class, springContext);
-	    _Config.putAll(_Spring.copySpringEnvironmentToMap(configurableEnvironment));
-
-	    log.info("Spring's context was passed over to Isis");
-	    
-	    val config = _Config.getConfiguration();
-	    
-	    // dump config to log
-	    if(log.isInfoEnabled() && !config.getEnvironment().isUnitTesting()) {
-	        log.info("\n" + _Config.getConfiguration().toStringFormatted());
-	    }    
-	    
-	}
-	
-	/**
-	 * With this producer we create a dependency from {@link ServiceRegistryDefault} to here.
-	 * Lets {@link ServiceRegistryDefault} wait on Spring's context to become available.
-	 * @return just a dummy
-	 */
-	@Bean @Singleton 
-	public SpringContextProvider springContextProvider() {
-	    return new SpringContextProvider() {};
-	}
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        // just make sure we wait for the context
+        // (its passed over to ServiceRegistryDefault)
+    }
 
 	
 }
diff --git a/core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/sessmgmt/SessionManagementServiceDefault.java b/core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/sessmgmt/SessionManagementServiceDefault.java
index 50d0fa2..2692db8 100644
--- a/core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/sessmgmt/SessionManagementServiceDefault.java
+++ b/core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/sessmgmt/SessionManagementServiceDefault.java
@@ -19,21 +19,16 @@
 
 package org.apache.isis.core.runtime.services.sessmgmt;
 
-import org.apache.isis.applib.annotation.DomainService;
-import org.apache.isis.applib.annotation.NatureOfService;
-import org.apache.isis.applib.annotation.Programmatic;
+import javax.inject.Singleton;
+
 import org.apache.isis.applib.services.sessmgmt.SessionManagementService;
 import org.apache.isis.core.metamodel.services.persistsession.PersistenceSessionServiceInternal;
 import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
 import org.apache.isis.core.security.authentication.AuthenticationSession;
 
-@DomainService(
-        nature = NatureOfService.DOMAIN,
-        menuOrder = "" + Integer.MAX_VALUE
-        )
+@Singleton
 public class SessionManagementServiceDefault implements SessionManagementService {
 
-    @Programmatic
     @Override
     public void nextSession() {
 
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/AuthenticationManager.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/AuthenticationManager.java
index 116d262..681192a 100644
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/AuthenticationManager.java
+++ b/core/security/src/main/java/org/apache/isis/core/security/authentication/manager/AuthenticationManager.java
@@ -30,10 +30,9 @@ import org.apache.isis.core.security.authentication.AuthenticationSession;
  */
 public interface AuthenticationManager extends ApplicationScopedComponent {
 
-    @Programmatic
+    
     void init();
-
-    @Programmatic
+    
     void shutdown();
 
     /**
@@ -41,22 +40,19 @@ public interface AuthenticationManager extends ApplicationScopedComponent {
      * {@link AuthenticationRequest request} is valid; otherwise returns
      * <tt>null</tt>.
      */
-    @Programmatic
+    
     AuthenticationSession authenticate(AuthenticationRequest request);
-
-    @Programmatic
+    
     boolean supportsRegistration(Class<? extends RegistrationDetails> registrationDetailsClass);
-
-    @Programmatic
+    
     boolean register(RegistrationDetails registrationDetails);
 
     /**
      * Whether the provided {@link AuthenticationSession} is still valid.
      */
-    @Programmatic
+    
     boolean isSessionValid(AuthenticationSession authenticationSession);
-
-    @Programmatic
+    
     void closeSession(AuthenticationSession authenticationSession);
 
 }
diff --git a/core/security/src/main/java/org/apache/isis/core/security/authentication/standard/AuthenticationManagerStandard.java b/core/security/src/main/java/org/apache/isis/core/security/authentication/standard/AuthenticationManagerStandard.java
index 356509f..58bc41d 100644
--- a/core/security/src/main/java/org/apache/isis/core/security/authentication/standard/AuthenticationManagerStandard.java
+++ b/core/security/src/main/java/org/apache/isis/core/security/authentication/standard/AuthenticationManagerStandard.java
@@ -25,7 +25,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
-import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.util.ToString;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.collections._Maps;
@@ -59,7 +58,6 @@ public class AuthenticationManagerStandard implements AuthenticationManager {
      * @param deploymentCategory
      */
     @Override
-    @Programmatic
     public final void init() {
         defaultRandomCodeGeneratorIfNecessary();
         addDefaultAuthenticators();
@@ -84,7 +82,6 @@ public class AuthenticationManagerStandard implements AuthenticationManager {
     }
 
     @Override
-    @Programmatic
     public void shutdown() {
         for (final Authenticator authenticator : authenticators) {
             authenticator.shutdown();
@@ -95,7 +92,7 @@ public class AuthenticationManagerStandard implements AuthenticationManager {
     // Session Management (including authenticate)
     // //////////////////////////////////////////////////////////
 
-    @Programmatic
+    
     @Override
     public synchronized final AuthenticationSession authenticate(final AuthenticationRequest request) {
         if (request == null) {
@@ -126,14 +123,14 @@ public class AuthenticationManagerStandard implements AuthenticationManager {
         return code;
     }
 
-    @Programmatic
+    
     @Override
     public final boolean isSessionValid(final AuthenticationSession session) {
         final String userName = userByValidationCode.get(session.getValidationCode());
         return session.hasUserNameOf(userName);
     }
 
-    @Programmatic
+    
     @Override
     public void closeSession(final AuthenticationSession session) {
         List<Authenticator> authenticators = getAuthenticators();
@@ -147,23 +144,23 @@ public class AuthenticationManagerStandard implements AuthenticationManager {
     // Authenticators
     // //////////////////////////////////////////////////////////
 
-    @Programmatic
+    
     public final void addAuthenticator(final Authenticator authenticator) {
         authenticators.add(authenticator);
     }
 
-    @Programmatic
+    
     public void addAuthenticatorToStart(final Authenticator authenticator) {
         authenticators.add(0, authenticator);
     }
 
-    @Programmatic
+    
     public List<Authenticator> getAuthenticators() {
         return Collections.unmodifiableList(authenticators);
     }
 
 
-    @Programmatic
+    
     @Override
     public boolean register(final RegistrationDetails registrationDetails) {
         for (final Registrar registrar : getRegistrars()) {
@@ -174,7 +171,7 @@ public class AuthenticationManagerStandard implements AuthenticationManager {
         return false;
     }
 
-    @Programmatic
+    
     @Override
     public boolean supportsRegistration(final Class<? extends RegistrationDetails> registrationDetailsClass) {
         for (final Registrar registrar : getRegistrars()) {
@@ -185,7 +182,7 @@ public class AuthenticationManagerStandard implements AuthenticationManager {
         return false;
     }
 
-    @Programmatic
+    
     public List<Registrar> getRegistrars() {
         return asAuthenticators(getAuthenticators());
     }
@@ -206,7 +203,6 @@ public class AuthenticationManagerStandard implements AuthenticationManager {
      * For injection; will {@link #defaultRandomCodeGeneratorIfNecessary()
      * default} otherwise.
      */
-    @Programmatic
     public void setRandomCodeGenerator(final RandomCodeGenerator randomCodeGenerator) {
         assert randomCodeGenerator != null;
         this.randomCodeGenerator = randomCodeGenerator;
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
index 36a9c18..115fec0 100644
--- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
@@ -63,8 +63,6 @@ import org.apache.wicket.settings.DebugSettings;
 import org.apache.wicket.settings.RequestCycleSettings;
 import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
 import org.apache.wicket.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.wicketstuff.select2.ApplicationSettings;
 
 import org.apache.isis.commons.internal.context._Context;
@@ -108,6 +106,8 @@ import de.agilecoders.wicket.core.settings.IBootstrapSettings;
 import de.agilecoders.wicket.webjars.WicketWebjars;
 import de.agilecoders.wicket.webjars.settings.IWebjarsSettings;
 import de.agilecoders.wicket.webjars.settings.WebjarsSettings;
+import lombok.val;
+import lombok.extern.slf4j.Slf4j;
 import net.ftlines.wicketsource.WicketSource;
 
 /**
@@ -133,14 +133,13 @@ import net.ftlines.wicketsource.WicketSource;
  * Alternatively, {@link ComponentFactory}s can be specified by overriding {@link #newIsisWicketModule()}.
  * This mechanism allows a number of other aspects to be customized.
  */
+@Slf4j
 public class IsisWicketApplication
 extends AuthenticatedWebApplication
 implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, WicketViewerSettingsAccessor {
 
     private static final long serialVersionUID = 1L;
 
-    private static final Logger LOG = LoggerFactory.getLogger(IsisWicketApplication.class);
-
     private static final String STRIP_WICKET_TAGS_KEY = "isis.viewer.wicket.stripWicketTags";
     private static final boolean STRIP_WICKET_TAGS_DEFAULT = true;
     private static final String AJAX_DEBUG_MODE_KEY = "isis.viewer.wicket.ajaxDebugMode";
@@ -170,11 +169,12 @@ implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, WicketVi
     }
 
     @Inject private ComponentFactoryRegistry componentFactoryRegistry;
-//    @Inject private ImageResourceCache imageCache;
-//    @Inject private WicketViewerSettings wicketViewerSettings;
     @Inject private PageClassRegistry pageClassRegistry;
-//    @Inject private IsisSessionFactory isisSessionFactory;
     @Inject private WicketViewerSettings settings;
+    
+//    @Inject private ImageResourceCache imageCache;
+//    @Inject private WicketViewerSettings wicketViewerSettings;
+//  @Inject private IsisSessionFactory isisSessionFactory;
 
     private final IsisWicketApplication_Experimental experimental;
 
@@ -227,7 +227,8 @@ implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, WicketVi
     @Override
     protected void init() {
         
-        final IsisConfiguration configuration = IsisContext.getConfiguration();
+        val configuration = IsisContext.getConfiguration();
+        val serviceInjector = IsisContext.getServiceInjector();
         
         List<Future<Object>> futures = null;
         try {
@@ -245,21 +246,9 @@ implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, WicketVi
 
             
             // Initialize Spring Dependency Injection
-            getComponentInstantiationListeners().add(
-                    new SpringComponentInjector(this));
+            getComponentInstantiationListeners().add(new SpringComponentInjector(this));
             
-
-//            // FIXME [2033] remove comments ...
-//            // create IsisSessionFactory
-//            //
-//            final Injector injector = Guice.createInjector(
-//                    newIsisModule(), 
-//                    newIsisWicketModule());
-            //
-//            initWicketComponentInjection(injector);
-            //
-//            injector.injectMembers(this); // populates this.isisSessionFactory
-//            Ensure.ensure("IsisSessionFactory should have been injected.", this.isisSessionFactory != null);
+            serviceInjector.injectServicesInto(this);
             
             if (requestCycleListenerForIsis instanceof WebRequestCycleForIsis) {
                 WebRequestCycleForIsis webRequestCycleForIsis = (WebRequestCycleForIsis) requestCycleListenerForIsis;
@@ -296,8 +285,8 @@ implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, WicketVi
 
             if(_Context.isPrototyping()) {
                 DebugDiskDataStore.register(this);
-                LOG.debug("DebugDiskDataStore registered; access via ~/wicket/internal/debug/diskDataStore");
-                LOG.debug("DebugDiskDataStore: eg, http://localhost:8080/wicket/wicket/internal/debug/diskDataStore");
+                log.debug("DebugDiskDataStore registered; access via ~/wicket/internal/debug/diskDataStore");
+                log.debug("DebugDiskDataStore: eg, http://localhost:8080/wicket/wicket/internal/debug/diskDataStore");
 
                 if(!getDebugSettings().isDevelopmentUtilitiesEnabled()) {
                     boolean enableDevUtils = configuration
@@ -318,14 +307,14 @@ implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, WicketVi
                 }
             }
 
-            LOG.debug("storeSettings.inmemoryCacheSize        : {}", getStoreSettings().getInmemoryCacheSize());
-            LOG.debug("storeSettings.asynchronousQueueCapacity: {}", getStoreSettings().getAsynchronousQueueCapacity());
-            LOG.debug("storeSettings.maxSizePerSession        : {}", getStoreSettings().getMaxSizePerSession());
-            LOG.debug("storeSettings.fileStoreFolder          : {}", getStoreSettings().getFileStoreFolder());
+            log.debug("storeSettings.inmemoryCacheSize        : {}", getStoreSettings().getInmemoryCacheSize());
+            log.debug("storeSettings.asynchronousQueueCapacity: {}", getStoreSettings().getAsynchronousQueueCapacity());
+            log.debug("storeSettings.maxSizePerSession        : {}", getStoreSettings().getMaxSizePerSession());
+            log.debug("storeSettings.fileStoreFolder          : {}", getStoreSettings().getFileStoreFolder());
 
         } catch(RuntimeException ex) {
             // because Wicket's handling in its WicketFilter (that calls this method) does not log the exception.
-            LOG.error("Failed to initialize", ex);
+            log.error("Failed to initialize", ex);
             throw ex;
         } finally {
             ThreadPoolSupport.getInstance().join(futures);
@@ -468,13 +457,13 @@ implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, WicketVi
     }
 
     // //////////////////////////////////////
-
-    /**
-     * Override if required
-     */
-    protected IsisWicketModule newIsisWicketModule() {
-        return new IsisWicketModule(getServletContext());
-    }
+//TODO[2112] cleanup
+//    /**
+//     * Override if required
+//     */
+//    protected IsisWicketModule newIsisWicketModule() {
+//        return new IsisWicketModule(getServletContext());
+//    }
 
     // //////////////////////////////////////
 
@@ -581,7 +570,7 @@ implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, WicketVi
 
     private static void log(String msg) {
         System.err.println(msg);
-        LOG.error(msg);
+        log.error(msg);
     }
 
     // //////////////////////////////////////
@@ -634,7 +623,7 @@ implements ComponentFactoryRegistryAccessor, PageClassRegistryAccessor, WicketVi
             IsisContext.clear();
         } catch(final RuntimeException ex) {
             // symmetry with #init()
-            LOG.error("Failed to destroy", ex);
+            log.error("Failed to destroy", ex);
             throw ex;
         }
     }
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketModule.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketModule.java
index 8c4a55a..f05e11e 100644
--- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketModule.java
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketModule.java
@@ -19,36 +19,40 @@
 
 package org.apache.isis.viewer.wicket.viewer;
 
-import javax.servlet.ServletContext;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.FilterType;
+
+import org.apache.isis.config.beans.BeanScanInterceptorForSpring;
 
 /**
- * To override
- *
- * <pre>
- * final Module isisDefaults = new IsisWicketModule();
- *
- * final Module myAppOverrides = new AbstractModule() {
- *     @Override
- *     protected void configure() {
- *         bind(ComponentFactoryRegistrar.class).to(ComponentFactoryRegistrarForMyApp.class);
- *         bind(PageClassList.class).to(PageClassListForMyApp.class);
- *         ...
- *      }
- *  };
- * final Module overridden = Modules.override(isisDefaults).with(myAppOverrides);
- * </pre>
+ * 
+ * @since 2.0.0
  */
+@Configuration
+@ComponentScan(
+        basePackageClasses= {
+                IsisWicketModule.class,
+           },
+        includeFilters= {
+                @Filter(type = FilterType.CUSTOM, classes= {BeanScanInterceptorForSpring.class})
+        })
 public class IsisWicketModule {
 
-    private ServletContext servletContext;
-
-    public IsisWicketModule(
-            final ServletContext servletContext) {
-        this.servletContext = servletContext;
-    }
-
-    protected void configure() {
-        //bind(ComponentFactoryRegistry.class).to(ComponentFactoryRegistryDefault.class);
+   
+    
+    
+//TODO[2112] clean up
+//    
+//    private ServletContext servletContext;
+//    public IsisWicketModule(
+//            final ServletContext servletContext) {
+//        this.servletContext = servletContext;
+//    }
+//
+//    protected void configure() {
+//        //bind(ComponentFactoryRegistry.class).to(ComponentFactoryRegistryDefault.class);
 //        bind(PageClassRegistry.class).to(PageClassRegistryDefault.class);
 //        bind(EmailVerificationUrlService.class).to(EmailVerificationUrlServiceDefault.class);
 //        bind(PageNavigationService.class).to(PageNavigationServiceDefault.class);
@@ -107,7 +111,7 @@ public class IsisWicketModule {
 //                    }
 //                    return fallback;
 //                });
-    }
+//    }
     
     // -- HELPER
     
diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
index d494293..40c1195 100644
--- a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
+++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
@@ -62,7 +62,6 @@ import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolicyFacet;
 import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
 import org.apache.isis.core.metamodel.facets.object.promptStyle.PromptStyleFacet;
-import org.apache.isis.core.metamodel.services.ServicesInjector;
 import org.apache.isis.core.metamodel.spec.ActionType;
 import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormAbstract.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormAbstract.java
index 5518bb1..a080e4f 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormAbstract.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormAbstract.java
@@ -25,11 +25,9 @@ import org.apache.wicket.model.IModel;
 
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.core.metamodel.adapter.concurrency.ConcurrencyChecking;
-import org.apache.isis.core.metamodel.services.ServicesInjector;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
-import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
 import org.apache.isis.core.security.authentication.AuthenticationSession;
 import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistry;
 import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistryAccessor;
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/PanelAbstract.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/PanelAbstract.java
index ba0508f..2476932 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/PanelAbstract.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/PanelAbstract.java
@@ -31,10 +31,8 @@ import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.config.IsisConfiguration;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-import org.apache.isis.core.metamodel.services.ServicesInjector;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.runtime.system.context.IsisContext;
-import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
 import org.apache.isis.core.security.authentication.AuthenticationSession;
 import org.apache.isis.viewer.wicket.model.hints.UiHintContainer;
diff --git a/example/application/helloworld/src/main/java/domainapp/application/HelloWorldApp.java b/example/application/helloworld/src/main/java/domainapp/application/HelloWorldApp.java
index e99b77c..959d41d 100644
--- a/example/application/helloworld/src/main/java/domainapp/application/HelloWorldApp.java
+++ b/example/application/helloworld/src/main/java/domainapp/application/HelloWorldApp.java
@@ -23,15 +23,16 @@ import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
 import org.springframework.context.annotation.Import;
 
 import org.apache.isis.applib.services.fixturespec.FixtureScriptsDefault;
-import org.apache.isis.core.runtime.system.persistence.PersistenceSession5;
 import org.apache.isis.runtime.spring.IsisBoot;
 
+/**
+ * Bootstrap the application.
+ */
 @SpringBootApplication
 @Import({
-    PersistenceSession5.class,            
     IsisBoot.class,
     FixtureScriptsDefault.class,
-    HelloWorldAppManifest.class
+    HelloWorldAppManifest.class,
 })
 public class HelloWorldApp extends SpringBootServletInitializer {
 
diff --git a/example/application/helloworld/src/main/java/domainapp/application/HelloWorldAppManifest.java b/example/application/helloworld/src/main/java/domainapp/application/HelloWorldAppManifest.java
index 3ff69b2..5f8efed 100644
--- a/example/application/helloworld/src/main/java/domainapp/application/HelloWorldAppManifest.java
+++ b/example/application/helloworld/src/main/java/domainapp/application/HelloWorldAppManifest.java
@@ -22,14 +22,13 @@ import javax.inject.Singleton;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
 import org.springframework.context.annotation.PropertySource;
 import org.springframework.context.annotation.PropertySources;
 import org.springframework.core.io.ClassPathResource;
 
-import org.apache.isis.config.IsisConfiguration;
 import org.apache.isis.config.Presets;
 import org.apache.isis.config.beans.WebAppConfigBean;
-import org.apache.isis.config.internal._Config;
 import org.apache.isis.core.runtime.authorization.standard.AuthorizationManagerStandard;
 import org.apache.isis.core.security.authentication.bypass.AuthenticatorBypass;
 import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
@@ -37,22 +36,22 @@ import org.apache.isis.core.security.authentication.standard.AuthenticationManag
 import org.apache.isis.core.security.authorization.bypass.AuthorizorBypass;
 import org.apache.isis.core.security.authorization.manager.AuthorizationManager;
 import org.apache.isis.core.security.authorization.standard.Authorizor;
+import org.apache.isis.viewer.wicket.viewer.IsisWicketModule;
 
 /**
- * Bootstrap the application.
+ * Makes the integral parts of the 'hello world' web application.
  */
 @Configuration
 @PropertySources({
     @PropertySource("classpath:/domainapp/application/isis-non-changing.properties"),
-    @PropertySource(name=Presets.H2InMemory, factory = Presets.Factory.class, value = { "" })
+    @PropertySource(name=Presets.H2InMemory, factory = Presets.Factory.class, value = { "" }),
+    @PropertySource(name=Presets.NoTranslations, factory = Presets.Factory.class, value = { "" }),
+})
+@Import({
+    IsisWicketModule.class
 })
 public class HelloWorldAppManifest {
     
-    @Bean @Singleton
-    public IsisConfiguration getConfig() {
-        return _Config.getConfiguration();
-    }
-    
     /**
     * The standard authentication manager, configured with the 'bypass' authenticator 
     * (allows all requests through).